New Upstream Release - coinor-cbc

Ready changes

Summary

Merged new upstream version: 2.10.10+ds1 (was: 2.10.8+ds1).

Diff

diff --git a/.coin-or/generate_readme b/.coin-or/generate_readme
index 6e403c3..02e195e 100644
--- a/.coin-or/generate_readme
+++ b/.coin-or/generate_readme
@@ -190,6 +190,13 @@ echo "## CHANGELOG
           - \`oddwext\`: strategy used to search for wheel centers for the cuts found by CglOddWheel - 0=off, 1=one variable, 2=clique - default=2.
       - CglClique was replaced by CglBKClique as the default clique separator in CbcSolver.cpp.
 
+ * Release 2.10.10
+   * Fix for accidental introduction of private symbol into public header.
+
+ * Release 2.10.9
+   * Improvements to symmetry handling.
+   * Maintenance release to push out accumulates patches.
+
  * Release 2.10.8
    * Re-generate binaries due to mistake in Github Actions configuration and 
      incorporate new release of Cgl. 
diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml
index e6a92d0..ea5935c 100644
--- a/.github/workflows/linux-ci.yml
+++ b/.github/workflows/linux-ci.yml
@@ -18,31 +18,31 @@ jobs:
     runs-on: ${{ matrix.os }}
     strategy:
       matrix:
-        os: [ubuntu-18.04, ubuntu-20.04]
+        os: [ubuntu-20.04, ubuntu-22.04]
         build_static: [true, false]
         download_requirements: [sudo apt install -y -qq gfortran liblapack-dev libmetis-dev libnauty2-dev]
         include:
-          - os: macos-10.15
+          - os: macos-12
             build_static: false
-            flags: CC=clang OSX=10.15
+            flags: CC=clang OSX=12
             download_requirements: brew install metis bash
-          - os: macos-10.15
+          - os: macos-12
             build_static: false
-            flags: CC=gcc-9 CXX=g++-9 OSX=10.15
+            flags: CC=gcc-11 CXX=g++-11 OSX=12
             download_requirements: brew install metis bash
-          - os: macos-10.15
+          - os: macos-12
             build_static: false
-            flags: CC=gcc-10 CXX=g++-10 OSX=10.15
+            flags: CC=gcc-12 CXX=g++-12 OSX=12
             download_requirements: brew install metis bash
     steps:
       - name: Checkout source
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
         with:
           path: ${{ github.event.repository.name }}
       - name: Install required packages from package manager
         run: ${{ matrix.download_requirements }}
       - name: Checkout coinbrew
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
         with:
           repository: coin-or/coinbrew
           path: coinbrew
@@ -54,6 +54,7 @@ jobs:
           ADD_BUILD_ARGS=()
           ADD_BUILD_ARGS+=( --tests main --enable-relocatable )
           ADD_BUILD_ARGS+=( --verbosity 2 )
+          [[ ${{ matrix.os }} == ubuntu* ]] && ADD_ARGS+=( --with-nauty-incdir=/usr/include/x86_64-linux-gnu/nauty --with-nauty-lib="-L/usr/lib/ -lnauty" )
           [[ ${{ matrix.build_static }} == "true" ]] && \
           ADD_BUILD_ARGS+=( --static --with-lapack='-llapack -lblas -lgfortran -lquadmath -lm' )
           bash coinbrew/coinbrew fetch ${{ github.event.repository.name }} --skip-update \
@@ -69,7 +70,7 @@ jobs:
           cp ${{ github.event.repository.name }}/LICENSE dist/
           tar -czvf release.tar.gz -C dist .
       - name: Checkout package name generation script
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
         with:
           repository: coin-or-tools/platform-analysis-tools
           path: tools
@@ -84,7 +85,7 @@ jobs:
           echo "platform_string=${platform_str}" >> $GITHUB_ENV
       - name: Upload Artifact
         if: ${{ github.event_name == 'pull_request'}}
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         with:
           name: ${{ github.event.repository.name }}-${{ github.head_ref }}-${{ env.platform_string }}.tar.gz
           path: release.tar.gz
diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml
index a39842d..67e5704 100644
--- a/.github/workflows/windows-ci.yml
+++ b/.github/workflows/windows-ci.yml
@@ -29,17 +29,17 @@ jobs:
         ]
     steps:
       - name: Checkout source
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
         with:
           path: ${{ github.event.repository.name }}
       - name: Checkout coinbrew
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
         with:
           repository: coin-or/coinbrew
           path: coinbrew
       - name: Set up msvc
-        uses: ilammy/msvc-dev-cmd@v1
         if: ${{ matrix.arch == 'msvc' }}
+        uses: ilammy/msvc-dev-cmd@v1
       - name: Set correct host flag and install requirements
         run: |
           echo "host_flag=--host=${{ matrix.arch }}-w64-mingw32" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
@@ -71,7 +71,7 @@ jobs:
           cp ${{ github.event.repository.name }}/LICENSE dist/
         shell: msys2 {0}
       - name: Upload failed build directory
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         if: failure()
         with:
           name: ${{ matrix.os}}-{{ matrix.arch }}-debug=${{ matrix.debug }}-failedbuild
@@ -89,7 +89,7 @@ jobs:
         if: ${{ matrix.arch != 'msvc' }}
       - name: Upload artifact
         if: ${{ github.event_name == 'pull_request'}}
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         with:
           name: ${{ github.event.repository.name }}-${{ github.head_ref }}-${{ env.package_suffix }}
           path: dist
diff --git a/Cbc/configure b/Cbc/configure
index 3529023..ee2d62b 100755
--- a/Cbc/configure
+++ b/Cbc/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for Cbc 2.10.8.
+# Generated by GNU Autoconf 2.59 for Cbc 2.10.10.
 #
 # Report bugs to <cbc@lists.coin-or.org>.
 #
@@ -429,8 +429,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='Cbc'
 PACKAGE_TARNAME='cbc'
-PACKAGE_VERSION='2.10.8'
-PACKAGE_STRING='Cbc 2.10.8'
+PACKAGE_VERSION='2.10.10'
+PACKAGE_STRING='Cbc 2.10.10'
 PACKAGE_BUGREPORT='cbc@lists.coin-or.org'
 
 ac_unique_file="src/CbcTree.hpp"
@@ -1009,7 +1009,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures Cbc 2.10.8 to adapt to many kinds of systems.
+\`configure' configures Cbc 2.10.10 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1075,7 +1075,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Cbc 2.10.8:";;
+     short | recursive ) echo "Configuration of Cbc 2.10.10:";;
    esac
   cat <<\_ACEOF
 
@@ -1324,7 +1324,7 @@ fi
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-Cbc configure 2.10.8
+Cbc configure 2.10.10
 generated by GNU Autoconf 2.59
 
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1344,7 +1344,7 @@ cat >&5 <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by Cbc $as_me 2.10.8, which was
+It was created by Cbc $as_me 2.10.10, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   $ $0 $@
@@ -1870,7 +1870,7 @@ _ACEOF
 
 
 # Capture libtool library version, if given.
- coin_libversion=13:8:10
+ coin_libversion=13:10:10
 
 
 
@@ -4577,7 +4577,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='cbc'
- VERSION='2.10.8'
+ VERSION='2.10.10'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -32542,7 +32542,7 @@ _ASBOX
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by Cbc $as_me 2.10.8, which was
+This file was extended by Cbc $as_me 2.10.10, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -32605,7 +32605,7 @@ _ACEOF
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-Cbc config.status 2.10.8
+Cbc config.status 2.10.10
 configured by $0, generated by GNU Autoconf 2.59,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 
diff --git a/Cbc/configure.ac b/Cbc/configure.ac
index e416799..3dd0445 100644
--- a/Cbc/configure.ac
+++ b/Cbc/configure.ac
@@ -12,7 +12,7 @@
 
 AC_PREREQ(2.59)
 
-AC_INIT([Cbc],[2.10.8],[cbc@lists.coin-or.org])
+AC_INIT([Cbc],[2.10.10],[cbc@lists.coin-or.org])
 
 AC_COPYRIGHT([
 Copyright 2006 International Business Machines and others.
@@ -41,7 +41,7 @@ AC_CANONICAL_BUILD
 # the source root directory contains definition of where to find those
 # externals.  The following macro ensures that those externals are
 # retrieved by svn if they are not there yet.
-AC_COIN_PROJECTDIR_INIT(Cbc,13:8:10)
+AC_COIN_PROJECTDIR_INIT(Cbc,13:10:10)
 
 # Check if user wants to produce debugging code
 AC_COIN_DEBUG_COMPILE(Cbc)
diff --git a/Cbc/examples/userParallelHeuristic.cpp b/Cbc/examples/userParallelHeuristic.cpp
new file mode 100644
index 0000000..5642eec
--- /dev/null
+++ b/Cbc/examples/userParallelHeuristic.cpp
@@ -0,0 +1,401 @@
+// 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 <iomanip>
+
+#include "CoinPragma.hpp"
+#include "CbcModel.hpp"
+#include "OsiClpSolverInterface.hpp"
+#include "CbcSolver.hpp"
+#include "CbcHeuristic.hpp"
+#include "CbcHeuristicFPump.hpp"
+#include "CbcHeuristicRENS.hpp"
+#include "CbcHeuristicVND.hpp"
+
+#include "CoinTime.hpp"
+#define CBC_THREAD
+// Standard build does not copy CbcThread.hpp to correct place
+// use below if fixed
+//#include "CbcThread.hpp"
+// otherwise tweak this
+#include "../../../../Cbc/Cbc/src/CbcThread.hpp" // see comments here
+//#############################################################################
+
+/************************************************************************
+
+This main program shows how to take advantage of the standalone cbc in your program,
+while trapping events
+First it reads in an integer model from an mps file
+Then it initializes the integer model with cbc defaults
+Then it calls CbcMain1 passing all parameters apart from first but with callBack to modify stuff
+Finally it could print solution
+
+************************************************************************/
+class CbcHeuristicUser : public CbcHeuristic {
+public:
+  // Default Constructor
+  CbcHeuristicUser();
+
+  /* Constructor with model - assumed before cuts
+    */
+  CbcHeuristicUser(CbcModel &model);
+
+  // Copy constructor
+  CbcHeuristicUser(const CbcHeuristicUser &);
+
+  // Destructor
+  ~CbcHeuristicUser();
+
+  /// Clone
+  virtual CbcHeuristic *clone() const;
+
+  /// Assignment operator
+  CbcHeuristicUser &operator=(const CbcHeuristicUser &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)
+  */
+  virtual int solution(double &objectiveValue,
+		       double *newSolution);
+
+  virtual bool shouldHeurRun(int whereFrom);
+protected:
+  // Data
+  // Number of solutions found by model
+  int numberSolutions_;
+  // -1 - off, 0 - startup, 1 - do heuristic
+  int actions_;
+  // Add any stuff needed by heuristic
+  int k_;
+  int nodePick_;
+};
+// Default Constructor
+CbcHeuristicUser::CbcHeuristicUser()
+  : CbcHeuristic()
+{
+  numberSolutions_ = 0;
+  actions_= -1;
+  k_ = 0;
+  nodePick_ = 3;
+}
+// Constructor with model - assumed before cuts
+
+CbcHeuristicUser::CbcHeuristicUser(CbcModel &model)
+  : CbcHeuristic(model)
+{
+  numberSolutions_ = 0;
+  actions_ = 0;
+  k_ = 5;
+  nodePick_ = 3;
+}
+
+// Destructor
+CbcHeuristicUser::~CbcHeuristicUser()
+{
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicUser::clone() const
+{
+  return new CbcHeuristicUser(*this);
+}
+
+// Assignment operator
+CbcHeuristicUser &
+CbcHeuristicUser::operator=(const CbcHeuristicUser &rhs)
+{
+  if (this != &rhs) {
+    CbcHeuristic::operator=(rhs);
+    numberSolutions_ = rhs.numberSolutions_;
+    actions_ = rhs.actions_;
+    k_ = rhs.k_;
+    nodePick_ = rhs.nodePick_;
+  }
+  return *this;
+}
+
+// Copy constructor
+CbcHeuristicUser::CbcHeuristicUser(const CbcHeuristicUser &rhs)
+  : CbcHeuristic(rhs)
+{
+  numberSolutions_ = rhs.numberSolutions_;
+  actions_ = rhs.actions_;
+  k_ = rhs.k_;
+  nodePick_ = rhs.nodePick_;
+}
+// Resets stuff if model changes
+void CbcHeuristicUser::resetModel(CbcModel *)
+{
+}
+int CbcHeuristicUser::solution(double &solutionValue,
+  double *betterSolution)
+{
+  if (actions_ <0 ) {
+    return 0;
+  } else if (actions_ == 0) {
+    // see if wanted
+    int numberThreads = model_->getNumberThreads();
+    if (!numberThreads) {
+      actions_ = 1;
+    } else {
+      // choose a thread in middle?? (don't want first)
+      int wantedThread = numberThreads/2;
+      /* This is really clumsy - may be better to modify Cbc a tiny bit
+	 so that it is easy to pick up thread number */
+      CbcThread * masterThread = model_->masterThread();
+      if (!masterThread) 
+	return 0;  // not going yet
+      CbcModel * baseModel = masterThread->baseModel();
+      CbcBaseModel * master = baseModel->master();
+      CbcModel * wanted = master->model(wantedThread);
+      if (model_ == wanted) {
+	actions_ = 1;
+      } else {
+	actions_ = -1;
+	return 0;
+      }
+    }
+  }
+  if (numberSolutions_== model_->getSolutionCount())
+    return 0;
+  // but don't until in tree ?
+  if (model_->getNodeCount()<3)
+    return 0;
+  numberSolutions_ = model_->getSolutionCount();
+  OsiSolverInterface * solver = model_->continuousSolver()->clone();
+  // Add local branching cut.
+  int ones_sum = 0;
+  CoinPackedVector local_branching_cut;
+  const double * best_solution = model_->bestSolution();
+  int numberIntegers = model_->numberIntegers();
+  const int * integer_indices = model_->integerVariable();
+  
+  for(int i=0;i<numberIntegers;i++) {
+    int int_idx = integer_indices[i];
+    double int_val = best_solution[int_idx];
+    
+    if(fabs(int_val - 1.0) <= model_->getIntegerTolerance())
+      {
+	++ones_sum;
+	local_branching_cut.insert(int_idx, -1.0);
+      }
+    else if(fabs(int_val) <= model_->getIntegerTolerance())
+      {
+	local_branching_cut.insert(int_idx, 1.0);
+      }
+  }
+  
+  // k_ - neighbourhood size.
+  solver->addRow(local_branching_cut, -COIN_DBL_MAX, k_ - ones_sum, "LocalBranchingCut"); 
+  CbcModel model(*solver);
+  // Changing settings and adding heuristics.
+  model.setCutoffAsConstraint(true);
+  model.setCutoff(model_->getCutoff());
+  model.setPreferredWay(1);
+  model.setMaximumNodes(150);
+  model.setLogLevel(0); // or 1 when starting off
+  CbcHeuristicVND vnd(model);
+  vnd.setHeuristicName("VND");
+  vnd.setFractionSmall(0.4);
+  vnd.setFeasibilityPumpOptions(1008003);
+  int nodes[] = { -2, 50, 50, 50, 200, 1000, 10000 };
+  vnd.setNumberNodes(nodes[nodePick_]);
+  model.addHeuristic(&vnd);
+  CbcHeuristicRENS rens(model);
+  rens.setHeuristicName("RENSdj");
+  rens.setFractionSmall(0.6 /*3.4*/);
+  rens.setFeasibilityPumpOptions(3);
+  rens.setNumberNodes(10);
+  rens.setWhereFrom(4 * 256 + 4 * 1);
+  rens.setWhen(2);
+  rens.setRensType(1 + 16);
+  model.addHeuristic(&rens);
+  CbcHeuristicFPump fpump(model);
+  fpump.setFractionSmall(0.5);
+  fpump.setMaximumPasses(5);
+  fpump.setFeasibilityPumpOptions(30);
+  fpump.setWhen(13);
+  fpump.setHeuristicName("feasibility pump");
+  model.addHeuristic(&fpump);
+  CbcRounding rounding(model);
+  rounding.setHeuristicName("rounding");
+  model.addHeuristic(&rounding);
+  model.branchAndBound();
+  if (model.bestSolution()) {
+    solutionValue = model.getMinimizationObjValue();
+    // solution may be worse than one found now but ...
+    printf("user_heuristic found solution of %g\n",solutionValue); // debug
+    int numberColumns = solver->getNumCols();
+    memcpy(betterSolution, model.bestSolution(),
+	   numberColumns*sizeof(double));
+    delete solver;
+    return 1;
+  } else {
+    printf("user_failed\n"); // debug
+    delete solver;
+    return 0;
+  }
+}
+// update model
+void CbcHeuristicUser::setModel(CbcModel *model)
+{
+  model_ = model;
+}
+bool CbcHeuristicUser::shouldHeurRun(int whereFrom)
+{
+  switch (actions_) {
+  case 0:
+    return (model_->specialOptions()&2048)==0; //not in submodel
+  case 1:
+    return model_->getSolutionCount()!=numberSolutions_;
+  default:
+    return false;
+  }
+}
+
+/* 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
+*/
+/* Meaning of model status is as normal
+   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) 
+
+      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
+
+   but initially check if status is 0 and secondary status is 1 -> infeasible
+   or you can check solver status.
+*/
+/* Return non-zero to return quickly */
+static int callBack(CbcModel *model, int whereFrom)
+{
+  int returnCode = 0;
+  switch (whereFrom) {
+  case 1:
+  case 2:
+    if (!model->status() && model->secondaryStatus())
+      returnCode = 1;
+    break;
+  case 3: {
+    // Add in dummy heuristic
+    CbcHeuristicUser heuristicUser(*model);
+    heuristicUser.setHeuristicName("UserHeuristic");
+    model->addHeuristic(&heuristicUser);
+  }
+    break;
+  case 4:
+    // If not good enough could skip postprocessing
+    break; 
+  case 5:
+    break;
+  default:
+    abort();
+  }
+  return returnCode;
+}
+//#include "CbcEventHandler.hpp"
+// May want to put back event handler - epecially if a few more events added ???
+
+int main(int argc, const char *argv[])
+{
+
+  OsiClpSolverInterface solver1;
+#define USE_OSI_NAMES
+#ifdef USE_OSI_NAMES
+  // Say we are keeping names (a bit slower this way)
+  solver1.setIntParam(OsiNameDiscipline, 1);
+#endif
+  // Read in model using argv[1]
+  // and assert that it is a clean model
+  std::string mpsFileName;
+  if (argc < 2) {
+    fprintf(stderr, "Do not know where to find MPS file.\n");
+    exit(1);
+  } else {
+    printf("Running"); 
+    for (int i=1;i<argc;i++)
+      printf("%s ",argv[i]);
+    printf("\n");
+    mpsFileName = argv[1];
+  }
+  int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(), "");
+  if (numMpsReadErrors != 0) {
+    printf("%d errors reading MPS file\n", numMpsReadErrors);
+    return numMpsReadErrors;
+  }
+  // Tell solver to return fast if presolve or initial solve infeasible
+  solver1.getModelPtr()->setMoreSpecialOptions(3);
+
+  // Pass to Cbc initialize defaults
+  CbcModel modelA(solver1);
+  CbcSolverUsefulData parameterData;
+  CbcMain0(modelA,parameterData);
+  // Event handler
+  //MyEventHandler3 eventHandler;
+  //modelA.passInEventHandler(&eventHandler);
+  /* Now go into code for standalone solver
+     Could copy arguments and add -quit at end to be safe
+     but this will do
+  */
+  if (argc > 2) {
+    CbcMain1(argc - 1, argv + 1, modelA,callBack,parameterData);
+  } else {
+    const char *argv2[] = { "user", "-solve", "-quit" };
+    CbcMain1(3, argv2, modelA,callBack,parameterData);
+  }
+#ifdef PRINT_SOLUTION
+  // Print solution if finished
+  if (modelA.bestSolution()) {
+    const double *solution = modelA.bestSolution();
+    int numberColumns = modelA.getNumCols();
+    std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14);
+
+    std::cout << "--------------------------------------" << std::endl;
+    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+      double value = solution[iColumn];
+      if (fabs(value) > 1.0e-7 && solver->isInteger(iColumn))
+        std::cout << std::setw(6) << iColumn << " " << std::setw(8) << setiosflags(std::ios::left) << solver->getColName(iColumn)
+                  << resetiosflags(std::ios::adjustfield) << std::setw(14) << " " << value << std::endl;
+    }
+    std::cout << "--------------------------------------" << std::endl;
+
+    std::cout << std::resetiosflags(std::ios::fixed | std::ios::showpoint | std::ios::scientific);
+  } else {
+    std::cout << " No solution!" << std::endl;
+  }
+#else
+  if (modelA.bestSolution()) {
+    printf("Optimal solution of %g\n",modelA.getMinimizationObjValue());
+  } else {
+    printf(" No solution!\n");
+  }
+#endif
+  return 0;
+}
diff --git a/Cbc/examples/userParallelHeuristic2.cpp b/Cbc/examples/userParallelHeuristic2.cpp
new file mode 100644
index 0000000..adcc1f6
--- /dev/null
+++ b/Cbc/examples/userParallelHeuristic2.cpp
@@ -0,0 +1,491 @@
+// 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 <iomanip>
+
+#include "CoinPragma.hpp"
+#include "CbcModel.hpp"
+#include "OsiClpSolverInterface.hpp"
+#include "CbcSolver.hpp"
+#include "CbcHeuristic.hpp"
+#include "CbcHeuristicFPump.hpp"
+#include "CbcHeuristicRENS.hpp"
+#include "CbcHeuristicVND.hpp"
+
+#include "CoinTime.hpp"
+#define CBC_THREAD
+// Standard build does not copy CbcThread.hpp to correct place
+// use below if fixed
+//#include "CbcThread.hpp"
+// otherwise tweak this
+#include "../../../../Cbc/Cbc/src/CbcThread.hpp" // see comments here
+//#############################################################################
+
+/************************************************************************
+
+This main program shows how to take advantage of the standalone cbc in your program,
+while trapping events
+First it reads in an integer model from an mps file
+Then it initializes the integer model with cbc defaults
+Then it calls CbcMain1 passing all parameters apart from first but with callBack to modify stuff
+Finally it could print solution
+
+************************************************************************/
+// Save useful CbcModel
+static CbcModel * userModel = NULL;
+// Restarts cause chaos - can use this instead of model_
+static CbcModel * realModel =NULL;
+class CbcHeuristicUser : public CbcHeuristic {
+public:
+  // Default Constructor
+  CbcHeuristicUser();
+
+  /* Constructor with model - assumed before cuts
+    */
+  CbcHeuristicUser(CbcModel &model);
+
+  // Copy constructor
+  CbcHeuristicUser(const CbcHeuristicUser &);
+
+  // Destructor
+  ~CbcHeuristicUser();
+
+  /// Clone
+  virtual CbcHeuristic *clone() const;
+
+  /// Assignment operator
+  CbcHeuristicUser &operator=(const CbcHeuristicUser &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)
+  */
+  virtual int solution(double &objectiveValue,
+		       double *newSolution);
+
+  virtual bool shouldHeurRun(int whereFrom);
+protected:
+  // Data
+  // Number of solutions found by model
+  int numberSolutions_;
+  // -1 - off, 0 - startup, 1 - do heuristic
+  int actions_;
+  // Add any stuff needed by heuristic
+  int k_;
+  int nodePick_;
+};
+// Default Constructor
+CbcHeuristicUser::CbcHeuristicUser()
+  : CbcHeuristic()
+{
+  numberSolutions_ = 0;
+  actions_= -1;
+  k_ = 0;
+  nodePick_ = 3;
+}
+// Constructor with model - assumed before cuts
+
+CbcHeuristicUser::CbcHeuristicUser(CbcModel &model)
+  : CbcHeuristic(model)
+{
+  numberSolutions_ = 0;
+  actions_ = 0;
+  k_ = 5;
+  nodePick_ = 3;
+}
+
+// Destructor
+CbcHeuristicUser::~CbcHeuristicUser()
+{
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicUser::clone() const
+{
+  return new CbcHeuristicUser(*this);
+}
+
+// Assignment operator
+CbcHeuristicUser &
+CbcHeuristicUser::operator=(const CbcHeuristicUser &rhs)
+{
+  if (this != &rhs) {
+    CbcHeuristic::operator=(rhs);
+    numberSolutions_ = rhs.numberSolutions_;
+    actions_ = rhs.actions_;
+    k_ = rhs.k_;
+    nodePick_ = rhs.nodePick_;
+  }
+  return *this;
+}
+
+// Copy constructor
+CbcHeuristicUser::CbcHeuristicUser(const CbcHeuristicUser &rhs)
+  : CbcHeuristic(rhs)
+{
+  numberSolutions_ = rhs.numberSolutions_;
+  actions_ = rhs.actions_;
+  k_ = rhs.k_;
+  nodePick_ = rhs.nodePick_;
+}
+// Resets stuff if model changes
+void CbcHeuristicUser::resetModel(CbcModel *)
+{
+}
+int CbcHeuristicUser::solution(double &solutionValue,
+  double *betterSolution)
+{
+  if (actions_ <0 ) {
+    return 0;
+  } else if (actions_ == 0) {
+    // see if wanted
+    int numberThreads = model_->getNumberThreads();
+    if (!numberThreads) {
+      actions_ = 1;
+    } else {
+      // choose a thread in middle?? (don't want first)
+      int wantedThread = numberThreads/2;
+      /* This is really clumsy - may be better to modify Cbc a tiny bit
+	 so that it is easy to pick up thread number */
+      CbcThread * masterThread = model_->masterThread();
+      if (!masterThread) 
+	return 0;  // not going yet
+      CbcModel * baseModel = masterThread->baseModel();
+      CbcBaseModel * master = baseModel->master();
+      CbcModel * wanted = master->model(wantedThread);
+      if (model_ == wanted) {
+	actions_ = 1;
+      } else {
+	actions_ = -1;
+	return 0;
+      }
+    }
+  }
+  // if model restarts, some heuristics may not work
+  if (model_->numberIntegers()!=realModel->numberIntegers()) {
+    //printf("restartx? %d columns, %d rows, %d,%d ints\n",model_->getNumCols(),model_->getNumRows(),
+    //	   model_->numberIntegers(),realModel->numberIntegers() );
+    static int xxxxxx=0;
+    if (!xxxxxx)
+      printf("restart models not yet reset\n");
+    xxxxxx++;
+    return 0;
+  }
+  if (numberSolutions_== realModel->getSolutionCount())
+    return 0;
+  // but don't until in tree ?
+  if (realModel->getNodeCount()<3)
+    return 0;
+  numberSolutions_ = realModel->getSolutionCount();
+  if (!userModel) {
+    // must have restarted model!
+    return 0;
+  }
+  // Can either use LP solver or with root cuts
+  // if LP solver then can use model_->
+  OsiSolverInterface * solver = userModel->continuousSolver()->clone();
+  //OsiSolverInterface * solver = userModel->solver()->clone();
+  // Add local branching cut.
+  int ones_sum = 0;
+  CoinPackedVector local_branching_cut;
+  const double * best_solution = realModel->bestSolution();
+  int numberIntegers = realModel->numberIntegers();
+  const int * integer_indices = realModel->integerVariable();
+  
+  for(int i=0;i<numberIntegers;i++) {
+    int int_idx = integer_indices[i];
+    double int_val = best_solution[int_idx];
+    
+    if(fabs(int_val - 1.0) <= realModel->getIntegerTolerance())
+      {
+	++ones_sum;
+	local_branching_cut.insert(int_idx, -1.0);
+      }
+    else if(fabs(int_val) <= realModel->getIntegerTolerance())
+      {
+	local_branching_cut.insert(int_idx, 1.0);
+      }
+  }
+  
+  // k_ - neighbourhood size.
+  solver->addRow(local_branching_cut, -COIN_DBL_MAX, k_ - ones_sum, "LocalBranchingCut"); 
+  CbcModel model(*solver);
+  // Changing settings and adding heuristics.
+  model.setCutoffAsConstraint(true);
+  model.setCutoff(realModel->getCutoff());
+  model.setPreferredWay(1);
+  model.setMaximumNodes(150);
+  model.setLogLevel(0); // or 1 when starting off
+  CbcHeuristicVND vnd(model);
+  vnd.setHeuristicName("VND");
+  vnd.setFractionSmall(0.4);
+  vnd.setFeasibilityPumpOptions(1008003);
+  int nodes[] = { -2, 50, 50, 50, 200, 1000, 10000 };
+  vnd.setNumberNodes(nodes[nodePick_]);
+  model.addHeuristic(&vnd);
+  CbcHeuristicRENS rens(model);
+  rens.setHeuristicName("RENSdj");
+  rens.setFractionSmall(0.6 /*3.4*/);
+  rens.setFeasibilityPumpOptions(3);
+  rens.setNumberNodes(10);
+  rens.setWhereFrom(4 * 256 + 4 * 1);
+  rens.setWhen(2);
+  rens.setRensType(1 + 16);
+  model.addHeuristic(&rens);
+  CbcHeuristicFPump fpump(model);
+  fpump.setFractionSmall(0.5);
+  fpump.setMaximumPasses(5);
+  fpump.setFeasibilityPumpOptions(30);
+  fpump.setWhen(13);
+  fpump.setHeuristicName("feasibility pump");
+  model.addHeuristic(&fpump);
+  CbcRounding rounding(model);
+  rounding.setHeuristicName("rounding");
+  model.addHeuristic(&rounding);
+  printf("starting user with cutoff of %g\n",realModel->getCutoff());
+  model.branchAndBound();
+  if (model.bestSolution()) {
+    solutionValue = model.getMinimizationObjValue();
+    // solution may be worse than one found now but ...
+    printf("user_heuristic found solution of %g\n",solutionValue); // debug
+    int numberColumns = solver->getNumCols();
+    memcpy(betterSolution, model.bestSolution(),
+	   numberColumns*sizeof(double));
+    delete solver;
+    return 1;
+  } else {
+    printf("user_failed\n"); // debug
+    delete solver;
+    return 0;
+  }
+}
+// update model
+void CbcHeuristicUser::setModel(CbcModel *model)
+{
+  model_ = model;
+}
+bool CbcHeuristicUser::shouldHeurRun(int whereFrom)
+{
+  switch (actions_) {
+  case 0:
+    return (model_->specialOptions()&2048)==0; //not in submodel
+  case 1:
+    return realModel->getSolutionCount()!=numberSolutions_;
+  default:
+    return false;
+  }
+}
+#include "CbcEventHandler.hpp"
+/** This is so user can trap events and do useful stuff.  
+
+    CbcModel model_ is available as well as anything else you care 
+    to pass in 
+*/
+
+class MyEventHandler3 : public CbcEventHandler {
+
+public:
+  /**@name Overrides */
+  //@{
+  virtual CbcAction event(CbcEvent whichEvent);
+  //@}
+
+  /**@name Constructors, destructor etc*/
+  //@{
+  /** Default constructor. */
+  MyEventHandler3();
+  /// Constructor with pointer to model (redundant as setEventHandler does)
+  MyEventHandler3(CbcModel *model);
+  /** Destructor */
+  virtual ~MyEventHandler3();
+  /** The copy constructor. */
+  MyEventHandler3(const MyEventHandler3 &rhs);
+  /// Assignment
+  MyEventHandler3 &operator=(const MyEventHandler3 &rhs);
+  /// Clone
+  virtual CbcEventHandler *clone() const;
+  /*! \brief Set model. */
+  //@}
+
+protected:
+  // data goes here
+};
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+MyEventHandler3::MyEventHandler3()
+  : CbcEventHandler()
+{
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+MyEventHandler3::MyEventHandler3(const MyEventHandler3 &rhs)
+  : CbcEventHandler(rhs)
+{
+}
+
+// Constructor with pointer to model
+MyEventHandler3::MyEventHandler3(CbcModel *model)
+  : CbcEventHandler(model)
+{
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+MyEventHandler3::~MyEventHandler3()
+{
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+MyEventHandler3 &
+MyEventHandler3::operator=(const MyEventHandler3 &rhs)
+{
+  if (this != &rhs) {
+    CbcEventHandler::operator=(rhs);
+  }
+  return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CbcEventHandler *MyEventHandler3::clone() const
+{
+  return new MyEventHandler3(*this);
+}
+
+CbcEventHandler::CbcAction
+MyEventHandler3::event(CbcEvent whichEvent)
+{
+  // If in sub tree carry on (need to miss out when in heuristics)
+  if ((model_->specialOptions()&2048)!=0) {
+    return noAction; // carry on as in subproblem
+  } else if (whichEvent == startUp) {
+    // check heuristic not there (restart)
+    int numberHeuristics = model_->numberHeuristics();
+    int found;
+    for (found=0;found<numberHeuristics;found++) {
+      if (dynamic_cast<CbcHeuristicUser *>(model_->heuristic(found))) {
+	// already there
+	break;
+      }
+    }
+    if (found==numberHeuristics) {
+      // Add in dummy heuristic
+      CbcHeuristicUser heuristicUser(*model_);
+      heuristicUser.setHeuristicName("UserHeuristic");
+      model_->addHeuristic(&heuristicUser);
+    } else {
+      model_->heuristic(found)->setModel(model_);
+      delete userModel; 
+      userModel = NULL;
+    }
+    realModel = model_;
+    //printf("startup %p\n",model_);
+  } else if (whichEvent == afterRootCuts) {
+    // save model
+    delete userModel; // in case restart
+    userModel = new CbcModel(*model_);
+    //printf("afterRootCuts %p\n",model_);
+  } else if (whichEvent == endSearch) {
+    //printf("endSearch %p\n",model_);
+    // free model
+    delete userModel;
+    userModel = NULL;
+  }
+  return noAction; // carry on
+}
+
+static int dummyCallBack(CbcModel * /*model*/, int /*whereFrom*/)
+{
+  return 0;
+}
+int main(int argc, const char *argv[])
+{
+
+  OsiClpSolverInterface solver1;
+#define USE_OSI_NAMES
+#ifdef USE_OSI_NAMES
+  // Say we are keeping names (a bit slower this way)
+  solver1.setIntParam(OsiNameDiscipline, 1);
+#endif
+  // Read in model using argv[1]
+  // and assert that it is a clean model
+  std::string mpsFileName;
+  if (argc < 2) {
+    fprintf(stderr, "Do not know where to find MPS file.\n");
+    exit(1);
+  } else {
+    printf("Running"); 
+    for (int i=1;i<argc;i++)
+      printf("%s ",argv[i]);
+    printf("\n");
+    mpsFileName = argv[1];
+  }
+  int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(), "");
+  if (numMpsReadErrors != 0) {
+    printf("%d errors reading MPS file\n", numMpsReadErrors);
+    return numMpsReadErrors;
+  }
+  // Tell solver to return fast if presolve or initial solve infeasible
+  solver1.getModelPtr()->setMoreSpecialOptions(3);
+
+  // Pass to Cbc initialize defaults
+  CbcModel modelA(solver1);
+  CbcSolverUsefulData parameterData;
+  CbcMain0(modelA,parameterData);
+  // Event handler
+  MyEventHandler3 eventHandler;
+  modelA.passInEventHandler(&eventHandler);
+  /* Now go into code for standalone solver
+     Could copy arguments and add -quit at end to be safe
+     but this will do
+  */
+  if (argc > 2) {
+    CbcMain1(argc - 1, argv + 1, modelA,dummyCallBack,parameterData);
+  } else {
+    const char *argv2[] = { "user", "-solve", "-quit" };
+    CbcMain1(3, argv2, modelA,dummyCallBack,parameterData);
+  }
+#ifdef PRINT_SOLUTION
+  // Print solution if finished
+  if (modelA.bestSolution()) {
+    const double *solution = modelA.bestSolution();
+    int numberColumns = modelA.getNumCols();
+    std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14);
+
+    std::cout << "--------------------------------------" << std::endl;
+    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+      double value = solution[iColumn];
+      if (fabs(value) > 1.0e-7 && solver->isInteger(iColumn))
+        std::cout << std::setw(6) << iColumn << " " << std::setw(8) << setiosflags(std::ios::left) << solver->getColName(iColumn)
+                  << resetiosflags(std::ios::adjustfield) << std::setw(14) << " " << value << std::endl;
+    }
+    std::cout << "--------------------------------------" << std::endl;
+
+    std::cout << std::resetiosflags(std::ios::fixed | std::ios::showpoint | std::ios::scientific);
+  } else {
+    std::cout << " No solution!" << std::endl;
+  }
+#else
+  if (modelA.bestSolution()) {
+    printf("Optimal solution of %g\n",modelA.getMinimizationObjValue());
+  } else {
+    printf(" No solution!\n");
+  }
+#endif
+  return 0;
+}
diff --git a/Cbc/src/CbcBranchDynamic.cpp b/Cbc/src/CbcBranchDynamic.cpp
index 1b2bd94..a02b533 100644
--- a/Cbc/src/CbcBranchDynamic.cpp
+++ b/Cbc/src/CbcBranchDynamic.cpp
@@ -512,19 +512,14 @@ int CbcBranchDynamicDecision::betterBranch(CbcBranchingObject *thisOne,
 #if TRY_STUFF > 1
     // Get current number of infeasibilities, cutoff and current objective
     CbcNode *node = model->currentNode();
-    int numberUnsatisfied = node->numberUnsatisfied();
+    int numberUnsatisfied = node ? node->numberUnsatisfied() : 1;
     double cutoff = model->getCutoff();
-    double objectiveValue = node->objectiveValue();
+    double objectiveValue = node ? node->objectiveValue() : 0.0;
 #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
@@ -535,16 +530,18 @@ int CbcBranchDynamicDecision::betterBranch(CbcBranchingObject *thisOne,
     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;
+    if (node) {
+      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
diff --git a/Cbc/src/CbcBranchLotsize.hpp b/Cbc/src/CbcBranchLotsize.hpp
index 9ab88ce..8b106a9 100644
--- a/Cbc/src/CbcBranchLotsize.hpp
+++ b/Cbc/src/CbcBranchLotsize.hpp
@@ -142,7 +142,7 @@ private:
   /// Just for debug (CBC_PRINT defined in CbcBranchLotsize.cpp)
   void printLotsize(double value, bool condition, int type) const;
 
-private:
+protected:
   /// data
 
   /// Column number in model
diff --git a/Cbc/src/CbcEventHandler.hpp b/Cbc/src/CbcEventHandler.hpp
index f74cadd..0871ab0 100644
--- a/Cbc/src/CbcEventHandler.hpp
+++ b/Cbc/src/CbcEventHandler.hpp
@@ -107,7 +107,9 @@ public:
     /*! Having generated cuts, allows user to think. */
     generatedCuts,
     /*! End of search. */
-    endSearch
+    endSearch,
+    /*! Just before starting branching i.e. after root cuts. */
+    afterRootCuts
   };
 
   /*! \brief Action codes returned by the event handler.
diff --git a/Cbc/src/CbcGeneralDepth.cpp b/Cbc/src/CbcGeneralDepth.cpp
index 482d1e4..90a4594 100644
--- a/Cbc/src/CbcGeneralDepth.cpp
+++ b/Cbc/src/CbcGeneralDepth.cpp
@@ -320,9 +320,12 @@ CbcBranchingObject *
 CbcGeneralDepth::createCbcBranch(OsiSolverInterface *solver, const OsiBranchingInformation *info, int /*way*/)
 {
   int numberDo = numberNodes_;
-  if (whichSolution_ >= 0 && (model_->moreSpecialOptions() & 33554432) == 0)
+  if (whichSolution_ >= 0 && (model_->moreSpecialOptions() & 33554432) == 0) {
     numberDo--;
-  assert(numberDo > 0);
+    if (numberDo <= 0)
+      return NULL; // solution but complete search
+  }
+ assert(numberDo > 0);
   // create object
   CbcGeneralBranchingObject *branch = new CbcGeneralBranchingObject(model_);
   // skip solution
diff --git a/Cbc/src/CbcHeuristic.cpp b/Cbc/src/CbcHeuristic.cpp
index 0f2fdcd..6876267 100644
--- a/Cbc/src/CbcHeuristic.cpp
+++ b/Cbc/src/CbcHeuristic.cpp
@@ -196,6 +196,7 @@ CbcHeuristic::operator=(const CbcHeuristic &rhs)
   return *this;
 }
 
+static
 void CbcHeurDebugNodes(CbcModel *model_)
 {
   CbcNode *node = model_->currentNode();
@@ -1398,7 +1399,7 @@ int CbcHeuristic::smallBranchAndBound(OsiSolverInterface *solver, int numberNode
             value *= solver3->getObjSense();
             model.setCutoff(value);
             sprintf(generalPrint, "Unable to insert previous solution - using cutoff of %g",
-              value);
+		    trueObjValue(value));
             model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
               << generalPrint
               << CoinMessageEol;
diff --git a/Cbc/src/CbcHeuristic.hpp b/Cbc/src/CbcHeuristic.hpp
index 3476a57..d55fa80 100644
--- a/Cbc/src/CbcHeuristic.hpp
+++ b/Cbc/src/CbcHeuristic.hpp
@@ -12,6 +12,7 @@
 #include "OsiCuts.hpp"
 #include "CoinHelperFunctions.hpp"
 #include "OsiBranchingObject.hpp"
+#include "CbcModel.hpp"
 
 class OsiSolverInterface;
 
@@ -334,6 +335,11 @@ public:
   {
     return numCouldRun_;
   }
+  /// Return objective function value with sign corrected
+  inline double trueObjValue(double value) const
+  {
+    return (model_->moreSpecialOptions2()&67108864)==0 ? value : -value;
+  }
   /// Is it integer for heuristics?
 #ifdef COIN_HAS_CLP
   inline bool isHeuristicInteger(const OsiSolverInterface *solver, int iColumn) const
diff --git a/Cbc/src/CbcHeuristicDW.cpp b/Cbc/src/CbcHeuristicDW.cpp
index cb83394..82d1bfc 100644
--- a/Cbc/src/CbcHeuristicDW.cpp
+++ b/Cbc/src/CbcHeuristicDW.cpp
@@ -1097,16 +1097,16 @@ int CbcHeuristicDW::solution(double &solutionValue,
       //model.solver()->setHintParam(OsiDoPresolveInResolve, false, OsiHintDo, 0) ;
       model.initialSolve();
       if (bestObjective_ > model.solver()->getObjValue() + 1.0e-1) {
-        const double *dj = model.solver()->getReducedCost();
         int nFix = 0;
+#ifdef HOT_START
+        // Set up hot start
+        const double *dj = model.solver()->getReducedCost();
         const double *lower = model.solver()->getColLower();
         const double *upper = model.solver()->getColUpper();
         const double *solution = model.solver()->getColSolution();
         double gap = CoinMax(bestObjective_ - model.solver()->getObjValue(),
           1.0e-3);
         int numberColumns2 = model.solver()->getNumCols();
-#ifdef HOT_START
-        // Set up hot start
         const int *originalColumns = pinfo.originalColumns();
         double *hot = new double[2 * numberColumns2];
         int *hotPriorities = new int[numberColumns2 * 2];
@@ -1800,12 +1800,12 @@ void CbcHeuristicDW::findStructure()
       int nTotalZero = 0;
       int base = 0;
       for (int iBlock = 0; iBlock < numberBlocks_; iBlock++) {
-        int aff = 0;
+        //int aff = 0;
         int nZero = 0;
         for (int jBlock = 0; jBlock < numberBlocks_; jBlock++) {
           if (iBlock != jBlock) {
             if (affinity_[base + jBlock])
-              aff += affinity_[base + jBlock];
+              ;//aff += affinity_[base + jBlock];
             else
               nZero++;
           }
diff --git a/Cbc/src/CbcHeuristicDive.cpp b/Cbc/src/CbcHeuristicDive.cpp
index 2c0bc2a..9eac8e9 100644
--- a/Cbc/src/CbcHeuristicDive.cpp
+++ b/Cbc/src/CbcHeuristicDive.cpp
@@ -286,11 +286,11 @@ int CbcHeuristicDive::solution(double &solutionValue, int &numberNodes,
   // but can't be exactly coin_int_max
   maxSimplexIterations = CoinMin(maxSimplexIterations, COIN_INT_MAX >> 3);
   bool fixGeneralIntegers = false;
-  int maxIterations = maxIterations_;
+  //int maxIterations = maxIterations_;
   int saveSwitches = switches_;
   if ((maxIterations_ % 10) != 0) {
     int digit = maxIterations_ % 10;
-    maxIterations -= digit;
+    //maxIterations -= digit;
     switches_ |= 65536;
     if ((digit & 3) != 0)
       fixGeneralIntegers = true;
@@ -402,7 +402,9 @@ int CbcHeuristicDive::solution(double &solutionValue, int &numberNodes,
   int iteration = 0;
   int numberAtBoundFixed = 0;
   int numberGeneralFixed = 0; // fixed as satisfied but not at bound
+#if DIVE_PRINT > 1
   int numberReducedCostFixed = 0;
+#endif
   while (numberFractionalVariables) {
     iteration++;
 
@@ -1453,7 +1455,7 @@ int CbcHeuristicDive::reducedCostFix(OsiSolverInterface *solver)
               djValue, gap, lower[iColumn], upper[iColumn]);
 #endif
           } else {
-            assert(clpSimplex->getColumnStatus(iColumn) == ClpSimplex::atLowerBound || clpSimplex->getColumnStatus(iColumn) == ClpSimplex::isFixed);
+            //assert(clpSimplex->getColumnStatus(iColumn) == ClpSimplex::atLowerBound || clpSimplex->getColumnStatus(iColumn) == ClpSimplex::isFixed);
           }
         }
 #endif
@@ -1470,7 +1472,7 @@ int CbcHeuristicDive::reducedCostFix(OsiSolverInterface *solver)
               djValue, gap, lower[iColumn], upper[iColumn]);
 #endif
           } else {
-            assert(clpSimplex->getColumnStatus(iColumn) == ClpSimplex::atUpperBound || clpSimplex->getColumnStatus(iColumn) == ClpSimplex::isFixed);
+            //assert(clpSimplex->getColumnStatus(iColumn) == ClpSimplex::atUpperBound || clpSimplex->getColumnStatus(iColumn) == ClpSimplex::isFixed);
           }
         }
 #endif
diff --git a/Cbc/src/CbcHeuristicFPump.cpp b/Cbc/src/CbcHeuristicFPump.cpp
index ffc775c..85bd8ad 100644
--- a/Cbc/src/CbcHeuristicFPump.cpp
+++ b/Cbc/src/CbcHeuristicFPump.cpp
@@ -878,7 +878,7 @@ int CbcHeuristicFPump::solutionInternal(double &solutionValue,
         for (i = 0; i < numberColumns; i++)
           newSolutionValue += saveObjective[i] * newSolution[i];
         newSolutionValue *= direction;
-        sprintf(pumpPrint, "Solution found of %g", newSolutionValue);
+        sprintf(pumpPrint, "Solution found of %g", trueObjValue(newSolutionValue));
         model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
           << pumpPrint
           << CoinMessageEol;
@@ -940,7 +940,7 @@ int CbcHeuristicFPump::solutionInternal(double &solutionValue,
                   newSolutionValue += saveObjective[i] * newSolution[i];
                 }
                 newSolutionValue *= direction;
-                sprintf(pumpPrint, "Relaxing continuous gives %g", newSolutionValue);
+                sprintf(pumpPrint, "Relaxing continuous gives %g", trueObjValue(newSolutionValue));
                 //#define DEBUG_BEST
 #ifdef DEBUG_BEST
                 {
@@ -1060,7 +1060,7 @@ int CbcHeuristicFPump::solutionInternal(double &solutionValue,
             if (numberSolutions >= maxSolutions)
               exitAll = true;
             if (general && saveValue != newSolutionValue) {
-              sprintf(pumpPrint, "Cleaned solution of %g", solutionValue);
+              sprintf(pumpPrint, "Cleaned solution of %g", trueObjValue(solutionValue));
               model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
                 << pumpPrint
                 << CoinMessageEol;
@@ -1074,7 +1074,7 @@ int CbcHeuristicFPump::solutionInternal(double &solutionValue,
               << CoinMessageEol;
           }
         } else {
-          sprintf(pumpPrint, "After further testing solution no better than previous of %g", solutionValue);
+          sprintf(pumpPrint, "After further testing solution no better than previous of %g", trueObjValue(solutionValue));
           model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
             << pumpPrint
             << CoinMessageEol;
@@ -1297,7 +1297,7 @@ int CbcHeuristicFPump::solutionInternal(double &solutionValue,
             for (i = 0; i < numberColumns; i++)
               newSolutionValue += saveObjective[i] * newSolution[i];
             newSolutionValue *= direction;
-            sprintf(pumpPrint, "Intermediate solution found of %g", newSolutionValue);
+            sprintf(pumpPrint, "Intermediate solution found of %g", trueObjValue(newSolutionValue));
             model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
               << pumpPrint
               << CoinMessageEol;
@@ -1750,11 +1750,11 @@ int CbcHeuristicFPump::solutionInternal(double &solutionValue,
           sprintf(pumpPrint, "Pass %3d: suminf. %10.5f (%d) obj. %g iterations %d",
             numberPasses + totalNumberPasses,
             newSumInfeas, newNumberInfeas,
-            newTrueSolutionValue, numberIterations);
+		  trueObjValue(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);
+		  trueObjValue(newTrueSolutionValue), numberIterations);
         model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
           << pumpPrint
           << CoinMessageEol;
@@ -1906,7 +1906,7 @@ int CbcHeuristicFPump::solutionInternal(double &solutionValue,
     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);
+		trueObjValue(roundingObjective), trueObjValue(solutionValue));
         model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
           << pumpPrint
           << CoinMessageEol;
@@ -2100,14 +2100,14 @@ int CbcHeuristicFPump::solutionInternal(double &solutionValue,
           delete newSolver;
           newSolver = cloneBut(3); // was model_->continuousSolver()->clone();
           newSolutionValue = -saveOffset;
-          double newSumInfeas = 0.0;
+          //double newSumInfeas = 0.0;
           const double *obj = newSolver->getObjCoefficients();
           for (int i = 0; i < numberColumns; i++) {
-            if (isHeuristicInteger(newSolver, i)) {
-              double value = newSolution[i];
-              double nearest = floor(value + 0.5);
-              newSumInfeas += fabs(value - nearest);
-            }
+            //if (isHeuristicInteger(newSolver, i)) {
+            //  double value = newSolution[i];
+            //  double nearest = floor(value + 0.5);
+            //  newSumInfeas += fabs(value - nearest);
+            //}
             newSolutionValue += obj[i] * newSolution[i];
           }
           newSolutionValue *= direction;
@@ -2115,7 +2115,8 @@ int CbcHeuristicFPump::solutionInternal(double &solutionValue,
         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());
+		  trueObjValue(saveValue), trueObjValue(newSolutionValue)
+		  , model_->getCurrentSeconds());
           model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
             << pumpPrint
             << CoinMessageEol;
@@ -2224,7 +2225,7 @@ int CbcHeuristicFPump::solutionInternal(double &solutionValue,
                     newSumInfeas);
                 }
 #endif
-                sprintf(pumpPrint, "Freeing continuous variables gives a solution of %g", value);
+                sprintf(pumpPrint, "Freeing continuous variables gives a solution of %g", trueObjValue(value));
                 model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
                   << pumpPrint
                   << CoinMessageEol;
@@ -2265,7 +2266,7 @@ int CbcHeuristicFPump::solutionInternal(double &solutionValue,
             if (newSolver->isProvenOptimal()) {
               double value = newSolver->getObjValue() * newSolver->getObjSense();
               if (value < saveValue) {
-                sprintf(pumpPrint, "Freeing continuous variables gives a solution of %g", value);
+                sprintf(pumpPrint, "Freeing continuous variables gives a solution of %g", trueObjValue(value));
                 model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
                   << pumpPrint
                   << CoinMessageEol;
@@ -2332,7 +2333,7 @@ int CbcHeuristicFPump::solutionInternal(double &solutionValue,
         cutoff = exactMultiple * floor(cutoff / exactMultiple);
       if (cutoff < continuousObjectiveValue)
         break;
-      sprintf(pumpPrint, "Round again with cutoff of %g", cutoff);
+      sprintf(pumpPrint, "Round again with cutoff of %g", trueObjValue(cutoff));
       secondMajorPass = true;
       model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
         << pumpPrint
@@ -2414,10 +2415,10 @@ int CbcHeuristicFPump::solutionInternal(double &solutionValue,
       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);
+	    model_->getCurrentSeconds(), trueObjValue(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,
+	    model_->getCurrentSeconds(), trueObjValue(solutionValue),
       numberSolutions, CoinCpuTime() - time1);
   model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
     << pumpPrint
@@ -2758,14 +2759,14 @@ int CbcHeuristicFPump::rounds(OsiSolverInterface *solver, double *solution,
   const double *columnLower = solver->getColLower();
   const double *columnUpper = solver->getColUpper();
   // Check if valid with current solution (allow for 0.99999999s)
-  double newSumInfeas = 0.0;
+  //double newSumInfeas = 0.0;
   int newNumberInfeas = 0;
   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) {
-      newSumInfeas += fabs(value - round);
+      //newSumInfeas += fabs(value - round);
       newNumberInfeas++;
     }
   }
@@ -2875,7 +2876,9 @@ int CbcHeuristicFPump::rounds(OsiSolverInterface *solver, double *solution,
   memset(rowActivity, 0, numberRows * sizeof(double));
   solver->getMatrixByCol()->times(solution, rowActivity);
   double largestInfeasibility = primalTolerance;
+#ifdef JJF_ZERO
   double sumInfeasibility = 0.0;
+#endif
   int numberBadRows = 0;
   for (i = 0; i < numberRows; i++) {
     double value;
@@ -2883,13 +2886,17 @@ int CbcHeuristicFPump::rounds(OsiSolverInterface *solver, double *solution,
     if (value > primalTolerance) {
       numberBadRows++;
       largestInfeasibility = CoinMax(largestInfeasibility, value);
+#ifdef JJF_ZERO
       sumInfeasibility += value;
+#endif
     }
     value = rowActivity[i] - rowUpper[i];
     if (value > primalTolerance) {
       numberBadRows++;
       largestInfeasibility = CoinMax(largestInfeasibility, value);
+#ifdef JJF_ZERO
       sumInfeasibility += value;
+#endif
     }
   }
 #ifdef JJF_ZERO
diff --git a/Cbc/src/CbcHeuristicGreedy.cpp b/Cbc/src/CbcHeuristicGreedy.cpp
index 6b71ce0..6c6cc97 100644
--- a/Cbc/src/CbcHeuristicGreedy.cpp
+++ b/Cbc/src/CbcHeuristicGreedy.cpp
@@ -1350,7 +1350,7 @@ int CbcHeuristicGreedySOS::solution(double &solutionValue,
     }
 #endif
     double gap = 0.0;
-    double over = 0.0;
+    //double over = 0.0;
     int nL = 0;
     int nG = 0;
     int nUnder = 0;
@@ -1366,7 +1366,7 @@ int CbcHeuristicGreedySOS::solution(double &solutionValue,
       } else if (rowActivity[iRow] > rowUpper[iRow] + 10.0 * primalTolerance) {
         gap += rowActivity[iRow] - rowUpper[iRow];
       } else {
-        over += rowActivity[iRow] - rowLower[iRow];
+        //over += rowActivity[iRow] - rowLower[iRow];
         //rowWeight[iRow] *= 0.9;
       }
     }
diff --git a/Cbc/src/CbcHeuristicLocal.cpp b/Cbc/src/CbcHeuristicLocal.cpp
index 3eb03ad..26947c4 100644
--- a/Cbc/src/CbcHeuristicLocal.cpp
+++ b/Cbc/src/CbcHeuristicLocal.cpp
@@ -878,15 +878,21 @@ int CbcHeuristicLocal::solution(double &solutionValue,
         }
       }
       int numberBad = 0;
+#ifdef COIN_DETAIL
       double sumBad = 0.0;
+#endif
       // check was approximately feasible
       for (i = 0; i < numberRows; i++) {
         if (rowActivity[i] < rowLower[i]) {
+#ifdef COIN_DETAIL
           sumBad += rowLower[i] - rowActivity[i];
+#endif
           if (rowActivity[i] < rowLower[i] - 10.0 * primalTolerance)
             numberBad++;
         } else if (rowActivity[i] > rowUpper[i]) {
+#ifdef COIN_DETAIL
           sumBad += rowUpper[i] - rowActivity[i];
+#endif
           if (rowActivity[i] > rowUpper[i] + 10.0 * primalTolerance)
             numberBad++;
         }
diff --git a/Cbc/src/CbcLinked.cpp b/Cbc/src/CbcLinked.cpp
index 7fba55e..6e7a7aa 100644
--- a/Cbc/src/CbcLinked.cpp
+++ b/Cbc/src/CbcLinked.cpp
@@ -140,7 +140,7 @@ void OsiSolverLink::initialSolve()
     for (int i = 0; i < numberVariables_; i++) {
       info_[i].updateBounds(modelPtr_);
     }
-    int updated = updateCoefficients(modelPtr_, temp);
+    /* int updated =*/ updateCoefficients(modelPtr_, temp);
     //if (updated || 1) {
       temp->removeGaps(1.0e-14);
       ClpMatrixBase *save = modelPtr_->clpMatrix();
@@ -245,14 +245,14 @@ void OsiSolverLink::initialSolve()
               memcpy(gradient, qpTemp.objectiveAsObject()->gradient(&qpTemp, bestSolution_, offset, true, 2),
                 numberColumns * sizeof(double));
               // assume convex
-              double rhs = 0.0;
+              //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];
+                  //rhs += value * solution[i];
                   column[n++] = i;
                 }
               }
@@ -504,14 +504,14 @@ void OsiSolverLink::resolve()
                   }
                 }
                 // assume convex
-                double rhs = 0.0;
+                //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];
+                    //rhs += value * solution[i];
                     column[n++] = i;
                   }
                 }
@@ -2627,14 +2627,14 @@ OsiSolverLink::linearizedBAB(CglStored *cut)
       double *gradient = new double[numberColumns + 1];
       memcpy(gradient, qp->objectiveAsObject()->gradient(qp, solution, offset, true, 2),
         numberColumns * sizeof(double));
-      double rhs = 0.0;
+      //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];
+          //rhs += value * solution[i];
           column[n++] = i;
         }
       }
@@ -3415,13 +3415,13 @@ int OsiSolverLink::fathom(bool allFixed)
     const double *objective = modelPtr_->objective();
     int numberColumns = newSolver.getNumCols();
     bool zeroObjective = true;
-    double sum = 0.0;
+    //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];
+        //sum += lower[i] * objective[i];
       }
     }
     int fake[] = { 5, 4, 3, 2, 0, 0, 0 };
@@ -4071,8 +4071,10 @@ OsiOldLink::infeasibility(const OsiBranchingInformation *info, int &whichWay) co
   //const double * lower = info->lower_;
   const double *upper = info->upper_;
   double integerTolerance = info->integerTolerance_;
+#ifdef DISTANCE
   double weight = 0.0;
   double sum = 0.0;
+#endif
 
   // check bounds etc
   double lastWeight = -1.0e100;
@@ -4084,7 +4086,9 @@ OsiOldLink::infeasibility(const OsiBranchingInformation *info, int &whichWay) co
         throw CoinError("Weights too close together in OsiLink", "infeasibility", "OsiLink");
       lastWeight = weights_[j];
       double value = CoinMax(0.0, solution[iColumn]);
+#ifdef DISTANCE
       sum += value;
+#endif
       if (value > integerTolerance && upper[iColumn]) {
         // Possibly due to scaling a fixed variable might slip through
         if (value > upper[iColumn] + 1.0e-8) {
@@ -4094,7 +4098,9 @@ OsiOldLink::infeasibility(const OsiBranchingInformation *info, int &whichWay) co
 #endif
         }
         value = CoinMin(value, upper[iColumn]);
+#ifdef DISTANCE
         weight += weights_[j] * value;
+#endif
         if (firstNonZero < 0)
           firstNonZero = j;
         lastNonZero = j;
@@ -4107,8 +4113,10 @@ OsiOldLink::infeasibility(const OsiBranchingInformation *info, int &whichWay) co
   whichWay_ = 1;
   if (lastNonZero - firstNonZero >= sosType_) {
     // find where to branch
+#ifdef DISTANCE
     assert(sum > 0.0);
     weight /= sum;
+#endif
     valueInfeasibility = lastNonZero - firstNonZero + 1;
     valueInfeasibility *= 0.5 / static_cast< double >(numberMembers_);
     //#define DISTANCE
@@ -4229,17 +4237,21 @@ OsiOldLink::feasibleRegion(OsiSolverInterface *solver, const OsiBranchingInforma
   const double *solution = info->solution_;
   const double *upper = info->upper_;
   double integerTolerance = info->integerTolerance_;
+#ifdef DISTANCE
   double weight = 0.0;
-  double sum = 0.0;
+#endif
+  // 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;
+      //sum += value;
       if (value > integerTolerance && upper[iColumn]) {
+#ifdef DISTANCE
         weight += weights_[j] * value;
+#endif
         if (firstNonZero < 0)
           firstNonZero = j;
         lastNonZero = j;
@@ -6377,7 +6389,9 @@ OsiBiLinear::computeLambdas(const double xB[3], const double yB[3], const double
   }
   lambda[3] = 1.0 - (lambda[0] + lambda[1] + lambda[2]);
   double infeasibility = 0.0;
+#ifndef NDEBUG
   double xy = 0.0;
+#endif
   for (int j = 0; j < 4; j++) {
     double value = lambda[j];
     if (value > 1.0) {
@@ -6389,7 +6403,9 @@ OsiBiLinear::computeLambdas(const double xB[3], const double yB[3], const double
       value = 0.0;
     }
     lambda[j] = value;
+#ifndef NDEBUG
     xy += xybar[j] * value;
+#endif
   }
   assert(fabs(xy - x * y) < 1.0e-4);
   return infeasibility;
@@ -7147,6 +7163,7 @@ CglTemporary::operator=(const CglTemporary &rhs)
   }
   return *this;
 }
+static
 void checkQP(ClpSimplex * /*model*/)
 {
 #ifdef JJF_ZERO
@@ -7495,7 +7512,9 @@ int CoinModel::expandKnapsack(int knapsackRow, int &numberOutput, double *buildO
     buildStart[0] = 0;
   while (iStack >= 0) {
     if (sum >= minSize && sum <= maxSize) {
+#ifndef NDEBUG
       double checkSize = 0.0;
+#endif
       bool good = true;
       int nRow = 0;
       double obj = objectiveOffset;
@@ -7584,10 +7603,12 @@ int CoinModel::expandKnapsack(int knapsackRow, int &numberOutput, double *buildO
           }
           break;
         }
+#ifndef NDEBUG
         for (int j = 0; j < numJ; j++) {
           checkSize += stack[j] * size[j];
         }
         assert(fabs(sum - checkSize) < 1.0e-3);
+#endif
       }
       for (jRow = 0; jRow < nRow; jRow++) {
         int kRow = build[jRow];
diff --git a/Cbc/src/CbcMipStartIO.cpp b/Cbc/src/CbcMipStartIO.cpp
index e1847b8..95dc4f4 100644
--- a/Cbc/src/CbcMipStartIO.cpp
+++ b/Cbc/src/CbcMipStartIO.cpp
@@ -18,6 +18,7 @@
 
 using namespace std;
 
+static
 bool isNumericStr(const char *str)
 {
   const size_t l = strlen(str);
@@ -70,7 +71,7 @@ int readMIPStart(CbcModel *model, const char *fileName,
   if (colValues.size()) {
     sprintf(printLine, "MIPStart values read for %d variables.", static_cast< int >(colValues.size()));
     model->messageHandler()->message(CBC_GENERAL, model->messages()) << printLine << CoinMessageEol;
-    if (colValues.size() < model->getNumCols()) {
+    if ((int)colValues.size() < model->getNumCols()) {
       int numberColumns = model->getNumCols();
       OsiSolverInterface *solver = model->solver();
       vector< pair< string, double > > fullValues;
@@ -119,7 +120,7 @@ int computeCompleteSolution(CbcModel *model,
   for (int i = 0; (i < static_cast< int >(colNames.size())); ++i)
     colIdx[colNames[i]] = i;
 
-  char printLine[STR_SIZE];
+  char printLine[STR_SIZE+100];
   int fixed = 0;
   int notFound = 0;
   char colNotFound[256] = "";
diff --git a/Cbc/src/CbcModel.cpp b/Cbc/src/CbcModel.cpp
index d67e0e5..e49c869 100644
--- a/Cbc/src/CbcModel.cpp
+++ b/Cbc/src/CbcModel.cpp
@@ -1064,7 +1064,28 @@ void CbcModel::analyzeObjective()
 
   if (coeffMultiplier)
       delete[] coeffMultiplier;
-
+#ifdef COIN_HAS_NTY
+    if (rootSymmetryInfo_) {
+      CbcSymmetry *info = rootSymmetryInfo_;
+      int numberColumns = solver_->getNumCols();
+      int numberPermutations = info->numberPermutations();
+      int *marked = new int[numberColumns];
+      memset(marked, 0, numberColumns * sizeof(int));
+      for (int iPerm = 0; iPerm < numberPermutations; iPerm++) {
+	const int *orbit = info->permutation(iPerm);
+	for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	  if (orbit[iColumn] >= 0)
+	    marked[iColumn]++;
+	}
+      }
+      // add in summary permutation
+      cbc_permute permutation;
+      permutation.orbits = marked;
+      permutation.numberPerms = 0;
+      permutation.numberInPerm = 1;
+      info->addPermutation(permutation);
+    }
+#endif
   return;
 }
 
@@ -1098,6 +1119,24 @@ void CbcModel::saveModel(OsiSolverInterface *saveSolver, double *checkCutoffForR
       const double *solution = saveSolver->getColSolution();
       const double *reducedCost = saveSolver->getReducedCost();
 
+#ifdef COIN_HAS_NTY
+#define COIN_HAS_NTY2
+#endif
+#ifdef COIN_HAS_NTY2
+      double *saveLower = NULL;
+      double *saveUpper = NULL;
+      if (rootSymmetryInfo_ && (moreSpecialOptions2_ & 131072) != 0) {
+        if (true) { // try both ways
+          saveLower = CoinCopyOfArray(solver_->getColLower(), numberColumns);
+          saveUpper = CoinCopyOfArray(solver_->getColUpper(), numberColumns);
+        } else {
+          saveLower =
+              CoinCopyOfArray(continuousSolver_->getColLower(), numberColumns);
+          saveUpper =
+              CoinCopyOfArray(continuousSolver_->getColUpper(), numberColumns);
+        }
+      }
+#endif
       int numberFixed = 0;
       int numberFixed2 = 0;
       for (int i = 0; i < numberIntegers_; i++) {
@@ -1145,6 +1184,25 @@ void CbcModel::saveModel(OsiSolverInterface *saveSolver, double *checkCutoffForR
       }
       printf("Restart could fix %d integers (%d already fixed)\n",
         numberFixed + numberFixed2, numberFixed2);
+#endif
+#ifdef COIN_HAS_NTY2
+      if (rootSymmetryInfo_ && (moreSpecialOptions2_ & 131072) != 0) {
+        // better to sort changed for least interaction?
+        if (numberFixed + numberFixed2) {
+          int nExtra = 0;
+          for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (!upper[iColumn] && saveUpper[iColumn])
+              nExtra += rootSymmetryInfo_->changeBounds(
+                  iColumn, saveLower, saveUpper, saveSolver, 0);
+          }
+          if (nExtra) {
+            // printf("TIGHTEN2 orbital %d bounds\n",nExtra);
+            rootSymmetryInfo_->fixSuccess(nExtra);
+          }
+        }
+        delete[] saveLower;
+        delete[] saveUpper;
+      }
 #endif
       numberFixed += numberFixed2;
       if (numberFixed * 20 < numberColumns)
@@ -2083,7 +2141,7 @@ void CbcModel::branchAndBound(int doStatistics)
       // best solution found by various heuristics - set solution
       char general[200];
       sprintf(general, "Solution of %g already found by heuristic",
-        bestObjective_);
+        trueBestObjValue());
       messageHandler()->message(CBC_GENERAL,
         messages())
         << general << CoinMessageEol;
@@ -2369,17 +2427,28 @@ void CbcModel::branchAndBound(int doStatistics)
 #endif
 #ifdef COIN_HAS_NTY
   // maybe allow on fix and restart later
-  if ((moreSpecialOptions2_ & (128 | 256)) != 0 && !parentModel_) {
-    symmetryInfo_ = new CbcSymmetry();
-    symmetryInfo_->setupSymmetry(this);
-    int numberGenerators = symmetryInfo_->statsOrbits(this, 0);
-    if (!symmetryInfo_->numberUsefulOrbits() && (moreSpecialOptions2_ & (128 | 256)) != (128 | 256)) {
-      delete symmetryInfo_;
-      symmetryInfo_ = NULL;
-      moreSpecialOptions2_ &= ~(128 | 256);
-    }
-    if ((moreSpecialOptions2_ & (128 | 256)) == (128 | 256)) {
-      //moreSpecialOptions2_ &= ~256;
+  if ((moreSpecialOptions2_ & (128 | 256)) != 0) {
+    if ((specialOptions_ & 2048) == 0) {
+      symmetryInfo_ = new CbcSymmetry();
+      symmetryInfo_->setupSymmetry(this);
+      //int numberGenerators = symmetryInfo_->statsOrbits(this, 0);
+      if (!symmetryInfo_->numberUsefulOrbits() &&
+          (moreSpecialOptions2_ & (128 | 256)) != (128 | 256)) {
+        delete symmetryInfo_;
+        symmetryInfo_ = NULL;
+        moreSpecialOptions2_ &= ~(128 | 256 | 131072);
+      }
+      if ((moreSpecialOptions2_ & (128 | 256)) == (128 | 256)) {
+        if ((moreSpecialOptions2_ & 131072) != 0) {
+          // keep it simple
+          moreSpecialOptions2_ &= ~(128 | 256);
+          rootSymmetryInfo_ = symmetryInfo_;
+          symmetryInfo_ = NULL;
+        }
+      }
+    } else {
+      // small B&B
+      moreSpecialOptions2_ &= ~(128 | 256 | 131072);
     }
   }
 #endif
@@ -2871,6 +2940,182 @@ void CbcModel::branchAndBound(int doStatistics)
       convertToDynamic();
     }
   }
+#ifdef COIN_HAS_NTY
+#define MAX_NAUTY_PASS 2000
+  int testOptions = moreSpecialOptions2_&1073741824;
+  /* nauty switches off 128,256 - so bug - for now just if heavy
+     as we can test for that */
+  if (!parentModel_ && testOptions) {
+    bool changed = true;
+    int numberAdded = 0;
+    int numberPasses = 0;
+    moreSpecialOptions2_ &= ~1073741824;
+    testOptions = moreSpecialOptions2_;
+    int changeType = 0;
+    OsiSolverInterface *solverOriginal = solver_;
+    OsiSolverInterface *continuousSolver = continuousSolver_;
+    continuousSolver_ = NULL;
+    int numberOriginalRows = solverOriginal->getNumRows();
+    OsiSolverInterface *solver = solverOriginal->clone();
+    solver_ = solver;
+    while (changed) {
+      changed = false;
+      moreSpecialOptions2_ = testOptions;
+      CbcSymmetry symmetryInfo;
+      // symmetryInfo.setModel(&model);
+      // for now strong is just on counts - use user option
+      // int maxN=5000000;
+      // OsiSolverInterface * solver = solver();
+      symmetryInfo.setupSymmetry(this);
+      int numberGenerators = symmetryInfo.getNtyInfo()->getNumGenerators();
+      if (numberGenerators) {
+	// symmetryInfo.Print_Orbits();
+	int numberUsefulOrbits = symmetryInfo.numberUsefulOrbits();
+	if (numberUsefulOrbits) {
+	  symmetryInfo.Compute_Symmetry();
+	  symmetryInfo.fillOrbits(/*true*/);
+	  const int *orbits = symmetryInfo.whichOrbit();
+	  int numberUsefulOrbits = symmetryInfo.numberUsefulOrbits();
+	  int *counts = new int[numberUsefulOrbits];
+	  memset(counts, 0, numberUsefulOrbits * sizeof(int));
+	  int numberColumns = solver_->getNumCols();
+	  int numberUseful = 0;
+	  if (changeType == 1) {
+	    // just 0-1
+	    for (int i = 0; i < numberColumns; i++) {
+	      int iOrbit = orbits[i];
+	      if (iOrbit >= 0) {
+		if (solver_->isBinary(i)) {
+		  counts[iOrbit]++;
+		  numberUseful++;
+		}
+	      }
+	    }
+	  } else if (changeType == 2) {
+	    // just integer
+	    for (int i = 0; i < numberColumns; i++) {
+	      int iOrbit = orbits[i];
+	      if (iOrbit >= 0) {
+		if (solver_->isInteger(i)) {
+		  counts[iOrbit]++;
+		  numberUseful++;
+		}
+	      }
+	    }
+	  } else {
+	    // all
+	    for (int i = 0; i < numberColumns; i++) {
+	      int iOrbit = orbits[i];
+	      if (iOrbit >= 0) {
+		counts[iOrbit]++;
+		numberUseful++;
+	      }
+	    }
+	  }
+	  int iOrbit = -1;
+#define LONGEST 0
+#if LONGEST
+	  // choose longest
+	  int maxOrbit = 0;
+	  for (int i = 0; i < numberUsefulOrbits; i++) {
+	    if (counts[i] > maxOrbit) {
+	      maxOrbit = counts[i];
+	      iOrbit = i;
+	    }
+	  }
+#else
+	  // choose closest to 2
+	  int minOrbit = numberColumns + 1;
+	  for (int i = 0; i < numberUsefulOrbits; i++) {
+	    if (counts[i] > 1 && counts[i] < minOrbit) {
+	      minOrbit = counts[i];
+	      iOrbit = i;
+	    }
+	  }
+#endif
+	  delete[] counts;
+	  if (!numberUseful)
+	    break;
+	  // take largest
+	  const double *solution = solver_->getColSolution();
+	  double *size = new double[numberColumns];
+	  int *which = new int[numberColumns];
+	  int nIn = 0;
+	  for (int i = 0; i < numberColumns; i++) {
+	    if (orbits[i] == iOrbit) {
+	      size[nIn] = -solution[i];
+	      which[nIn++] = i;
+	    }
+	  }
+	  if (nIn > 1) {
+	    // printf("Using orbit length %d\n",nIn);
+	    CoinSort_2(size, size + nIn, which);
+	    size[0] = 1.0;
+	    size[1] = -1.0;
+#if LONGEST == 0
+	    solver_->addRow(2, which, size, 0.0, COIN_DBL_MAX);
+	    numberAdded++;
+#elif LONGEST == 1
+	    for (int i = 0; i < nIn - 1; i++) {
+	      solver_->addRow(2, which + i, size, 0.0, COIN_DBL_MAX);
+	      numberAdded++;
+	    }
+#else
+	    for (int i = 0; i < nIn - 1; i++) {
+	      solver_->addRow(2, which, size, 0.0, COIN_DBL_MAX);
+	      which[1] = which[2 + i];
+	      numberAdded++;
+	    }
+#endif
+	    numberPasses++;
+	    if (numberPasses < MAX_NAUTY_PASS)
+	      changed = true;
+	  }
+	  delete[] size;
+	  delete[] which;
+	}
+      }
+    }
+    // switch off
+    moreSpecialOptions2_&=~(131072|262144);
+    solver_ = solverOriginal;
+    if (numberAdded) {
+      char general[100];
+      if (numberPasses < MAX_NAUTY_PASS)
+	sprintf(general, "%d symmetry cuts added in %d passes", numberAdded,
+		numberPasses);
+      else
+	sprintf(
+		general,
+		"%d symmetry cuts added in %d passes (maximum) - must be better way",
+		numberAdded, numberPasses);
+      messageHandler()->message(CBC_GENERAL, messages())
+        << general << CoinMessageEol;
+      // have to switch nauty off totally!
+      moreSpecialOptions2_ &= ~(128 | 256);
+    }
+    continuousSolver_ = continuousSolver;
+    int numberRows = solver->getNumRows();
+    if (numberRows > numberOriginalRows) {
+      const CoinPackedMatrix *rowCopy = solver->getMatrixByRow();
+      const int *column = rowCopy->getIndices();
+      const int *rowLength = rowCopy->getVectorLengths();
+      const CoinBigIndex *rowStart = rowCopy->getVectorStarts();
+      const double *elements = rowCopy->getElements();
+      const double *rowLower = solver->getRowLower();
+      const double *rowUpper = solver->getRowUpper();
+      for (int iRow = numberOriginalRows; 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);
+	globalCuts_.addCutIfNotDuplicate(rc);
+      }
+    }
+    delete solver;
+  }
+#endif
 
   /*
       Do an initial round of cut generation for the root node. Depending on the
@@ -4532,7 +4777,7 @@ void CbcModel::branchAndBound(int doStatistics)
 #endif
         if (tryNewSearch) {
           // back to solver without cuts?
-          OsiSolverInterface *solver2 = saveSolver->clone();
+          OsiSolverInterface *solver2 = continuousSolver_->clone();
           const double *lower = saveSolver->getColLower();
           const double *upper = saveSolver->getColUpper();
           for (int i = 0; i < numberIntegers_; i++) {
@@ -4766,7 +5011,7 @@ void CbcModel::branchAndBound(int doStatistics)
       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());
+            getCutoff(), trueBestObjValue(), getCutoffIncrement());
         assert(getCutoff() < bestObjective_ - getCutoffIncrement() + 1.0e-6 + 1.0e-10 * fabs(bestObjective_));
       }
 #endif
@@ -4777,26 +5022,26 @@ void CbcModel::branchAndBound(int doStatistics)
         else
           lastBestPossibleObjective = bestPossibleObjective_;
         messageHandler()->message(CBC_STATUS, messages())
-          << numberNodes_ << CoinMax(nNodes, 1) << bestObjective_ << bestPossibleObjective_
+          << numberNodes_ << CoinMax(nNodes, 1) << trueBestObjValue() << trueObjValue(bestPossibleObjective_)
           << getCurrentSeconds()
           << CoinMessageEol;
       } else if (intParam_[CbcPrinting] == 1) {
         messageHandler()->message(CBC_STATUS2, messages())
-          << numberNodes_ << nNodes << bestObjective_ << bestPossibleObjective_
+          << numberNodes_ << nNodes << trueBestObjValue() << trueObjValue(bestPossibleObjective_)
           << tree_->lastDepth() << tree_->lastUnsatisfied()
-          << tree_->lastObjective() << numberIterations_
+          << trueObjValue(tree_->lastObjective()) << numberIterations_
           << getCurrentSeconds()
           << CoinMessageEol;
       } else if (!numberExtraIterations_) {
         messageHandler()->message(CBC_STATUS2, messages())
-          << numberNodes_ << nNodes << bestObjective_ << bestPossibleObjective_
+          << numberNodes_ << nNodes << trueBestObjValue() << trueObjValue(bestPossibleObjective_)
           << tree_->lastDepth() << tree_->lastUnsatisfied() << numberIterations_
           << getCurrentSeconds()
           << CoinMessageEol;
       } else {
         messageHandler()->message(CBC_STATUS3, messages())
           << numberNodes_ << numberFathoms_ << numberExtraNodes_ << nNodes
-          << bestObjective_ << bestPossibleObjective_
+          << trueBestObjValue() << trueObjValue(bestPossibleObjective_)
           << tree_->lastDepth() << tree_->lastUnsatisfied() << numberIterations_ << numberExtraIterations_
           << getCurrentSeconds()
           << CoinMessageEol;
@@ -4984,7 +5229,7 @@ void CbcModel::branchAndBound(int doStatistics)
          */
     if (stoppedOnGap_) {
       messageHandler()->message(CBC_GAP, messages())
-        << bestObjective_ - bestPossibleObjective_
+        << trueBestObjValue() - trueObjValue(bestPossibleObjective_)
         << dblParam_[CbcAllowableGap]
         << dblParam_[CbcAllowableFractionGap] * 100.0
         << CoinMessageEol;
@@ -5014,6 +5259,14 @@ void CbcModel::branchAndBound(int doStatistics)
   }
 #ifdef CBC_THREAD
   if (master_) {
+#ifdef COIN_HAS_NTY
+    if (rootSymmetryInfo_) {
+      // adjust statistics
+      for (int iModel=0;iModel<numberThreads_;iModel++) {
+	rootSymmetryInfo_->adjustStats(master_->model(iModel)->rootSymmetryInfo());
+      }
+    }
+#endif
     delete master_;
     master_ = NULL;
     masterThread_ = NULL;
@@ -5036,16 +5289,20 @@ void CbcModel::branchAndBound(int doStatistics)
   if (eventHandler) {
     eventHandler->event(CbcEventHandler::endSearch);
   }
+#ifdef COIN_HAS_NTY
+  if (rootSymmetryInfo_)
+    rootSymmetryInfo_->statsOrbits(this, 2);
+#endif
   if (!status_) {
     // Set best possible unless stopped on gap
     if (secondaryStatus_ != 2)
       bestPossibleObjective_ = bestObjective_;
     handler_->message(CBC_END_GOOD, messages_)
-      << bestObjective_ << numberIterations_ << numberNodes_ << getCurrentSeconds()
+      << trueBestObjValue() << numberIterations_ << numberNodes_ << getCurrentSeconds()
       << CoinMessageEol;
   } else {
     handler_->message(CBC_END, messages_)
-      << bestObjective_ << bestPossibleObjective_
+      << trueBestObjValue() << trueObjValue(bestPossibleObjective_)
       << numberIterations_ << numberNodes_ << getCurrentSeconds()
       << CoinMessageEol;
   }
@@ -5087,6 +5344,8 @@ void CbcModel::branchAndBound(int doStatistics)
 #ifdef COIN_HAS_NTY
   if (symmetryInfo_)
     symmetryInfo_->statsOrbits(this, 1);
+  if (rootSymmetryInfo_)
+    rootSymmetryInfo_->statsOrbits(this, 1);
 #endif
   if (doStatistics == 100) {
     for (int i = 0; i < numberObjects_; i++) {
@@ -5611,9 +5870,8 @@ CbcModel::CbcModel()
   , lastHeuristic_(NULL)
   , fastNodeDepth_(-1)
   , eventHandler_(NULL)
-#ifdef COIN_HAS_NTY
   , symmetryInfo_(NULL)
-#endif
+  , rootSymmetryInfo_(NULL)
   , numberObjects_(0)
   , object_(NULL)
   , ownObjects_(true)
@@ -5783,9 +6041,8 @@ CbcModel::CbcModel(const OsiSolverInterface &rhs)
   , lastHeuristic_(NULL)
   , fastNodeDepth_(-1)
   , eventHandler_(NULL)
-#ifdef COIN_HAS_NTY
   , symmetryInfo_(NULL)
-#endif
+  , rootSymmetryInfo_(NULL)
   , numberObjects_(0)
   , object_(NULL)
   , ownObjects_(true)
@@ -6326,6 +6583,10 @@ CbcModel::CbcModel(const CbcModel &rhs, bool cloneHandler)
     symmetryInfo_ = new CbcSymmetry(*rhs.symmetryInfo_);
   else
     symmetryInfo_ = NULL;
+  if (rhs.rootSymmetryInfo_)
+    rootSymmetryInfo_ = new CbcSymmetry(*rhs.rootSymmetryInfo_);
+  else
+    rootSymmetryInfo_ = NULL;
 #endif
   synchronizeModel();
   if (cloneHandler && !defaultHandler_) {
@@ -6677,6 +6938,10 @@ CbcModel::operator=(const CbcModel &rhs)
       symmetryInfo_ = new CbcSymmetry(*rhs.symmetryInfo_);
     else
       symmetryInfo_ = NULL;
+    if (rhs.rootSymmetryInfo_)
+      rootSymmetryInfo_ = new CbcSymmetry(*rhs.rootSymmetryInfo_);
+    else
+      rootSymmetryInfo_ = NULL;
 #endif
     synchronizeModel();
     cbcColLower_ = NULL;
@@ -6770,6 +7035,8 @@ void CbcModel::gutsOfDestructor2()
 #ifdef COIN_HAS_NTY
   delete symmetryInfo_;
   symmetryInfo_ = NULL;
+  delete rootSymmetryInfo_;
+  rootSymmetryInfo_ = NULL;
 #endif
 }
 // Clears out enough to reset CbcModel
@@ -6997,11 +7264,15 @@ void CbcModel::gutsOfCopy(const CbcModel &rhs, int mode)
     branchingMethod_ = NULL;
   messageHandler()->setLogLevel(rhs.messageHandler()->logLevel());
   whenCuts_ = rhs.whenCuts_;
-#ifdef COIN_HAS_NTY
-  if (rhs.symmetryInfo_)
-    symmetryInfo_ = new CbcSymmetry(*rhs.symmetryInfo_);
-  else
+#ifdef COIN_HAS_NTY // better to do again
+  //if (rhs.symmetryInfo_)
+  //symmetryInfo_ = new CbcSymmetry(*rhs.symmetryInfo_);
+  //else
     symmetryInfo_ = NULL;
+    //if (rhs.rootSymmetryInfo_)
+    //rootSymmetryInfo_ = new CbcSymmetry(*rhs.rootSymmetryInfo_);
+    //else
+    rootSymmetryInfo_ = NULL;
 #endif
   synchronizeModel();
 }
@@ -8131,7 +8402,7 @@ bool CbcModel::solveWithCuts(OsiCuts &cuts, int numberTries, CbcNode *node)
 
 #ifdef CBC_DEBUG
   if (feasible) {
-    printf("Obj value %g (%s) %d rows\n", solver_->getObjValue(),
+    printf("Obj value %g (%s) %d rows\n", trueObjValue(solver_->getObjValue()),
       (solver_->isProvenOptimal()) ? "proven" : "unproven",
       solver_->getNumRows());
   }
@@ -8459,7 +8730,7 @@ bool CbcModel::solveWithCuts(OsiCuts &cuts, int numberTries, CbcNode *node)
         << currentPassNumber_
         << solver_->getNumRows()
         << solver_->getNumRows() - numberRowsAtContinuous_
-        << solver_->getObjValue()
+        << trueObjValue(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)
@@ -8743,7 +9014,7 @@ bool CbcModel::solveWithCuts(OsiCuts &cuts, int numberTries, CbcNode *node)
         break;
       }
 #ifdef CBC_DEBUG
-      printf("Obj value after cuts %g %d rows\n", solver_->getObjValue(),
+      printf("Obj value after cuts %g %d rows\n", trueObjValue(solver_->getObjValue()),
         solver_->getNumRows());
       if (onOptimalPath && !solver_->isDualObjectiveLimitReached())
         assert(feasible);
@@ -8856,7 +9127,7 @@ bool CbcModel::solveWithCuts(OsiCuts &cuts, int numberTries, CbcNode *node)
                 badObj ? "true" : "false",
                 nBadPasses, maximumBadPasses, goodDrop, minimumDrop,
                 thisObj - cut_obj[CUT_HISTORY - 1],
-                solver_->getObjValue());
+                trueObjValue(solver_->getObjValue()));
 #endif
             maximumBadPasses = CoinMax(maximumBadPasses, nBadPasses);
             if (nBadPasses < 2 || goodDrop > 2.0 * minimumDrop) {
@@ -9133,7 +9404,7 @@ bool CbcModel::solveWithCuts(OsiCuts &cuts, int numberTries, CbcNode *node)
   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;
+  std::cout << "Node " << numberNodes_ << ", father " << fatherNum << ", #iterations " << solver_->getIterationCount() << ", sol value : " << trueObjValue(solver_->getObjValue()) << std::endl;
 #endif
   if (fullScan && numberCutGenerators_) {
     /* If cuts just at root node then it will probably be faster to
@@ -9323,7 +9594,7 @@ bool CbcModel::solveWithCuts(OsiCuts &cuts, int numberTries, CbcNode *node)
     if (!numberNodes_) {
       handler_->message(CBC_ROOT, messages_)
         << numberNewCuts_
-        << startObjective << thisObjective
+        << trueObjValue(startObjective) << trueObjValue(thisObjective)
         << currentPassNumber_
         << CoinMessageEol;
       // do heuristics again! if feasibility pump still exists
@@ -9331,6 +9602,8 @@ bool CbcModel::solveWithCuts(OsiCuts &cuts, int numberTries, CbcNode *node)
         specialOptions_ &= ~33554432;
         doHeuristicsAtRoot();
       }
+      if (eventHandler_) 
+        eventHandler_->event(CbcEventHandler::afterRootCuts);
     }
     /*
           Count the number of cuts produced by each cut generator on this call. Not
@@ -10347,8 +10620,68 @@ int CbcModel::resolve(CbcNodeInfo *parent, int whereFrom,
     if ((specialOptions_ & 1) != 0 && onOptimalPath) {
       solver_->writeMpsNative("before-tighten.mps", NULL, NULL, 2);
     }
-    if (clpSolver && (!currentNode_ || (currentNode_->depth() & 2) != 0) && !solverCharacteristics_->solutionAddsCuts() && (moreSpecialOptions_ & 1073741824) == 0)
+    if (clpSolver && (!currentNode_ || (currentNode_->depth() & 2) != 0) &&
+        !solverCharacteristics_->solutionAddsCuts() &&
+        (moreSpecialOptions_ & 1073741824) == 0 &&
+        (moreSpecialOptions2_ & 65536) == 0) {
+#ifdef COIN_HAS_NTY
+      double *saveLower = NULL;
+      double *saveUpper = NULL;
+      if (getMaximumNodes() > 1000000 && (moreSpecialOptions2_ & 131072) != 0) {
+        if (getMaximumNodes() - 1000000 < numberNodes_) {
+          printf("switching off after %d nodes\n", numberNodes_);
+          moreSpecialOptions2_ &= ~131072;
+        }
+      }
+#define ORBIT_OLD_WAY 1
+      if (rootSymmetryInfo_ && (moreSpecialOptions2_ & 131072) != 0) {
+        int numberColumns = solver_->getNumCols();
+        if (numberNodes_ && ORBIT_OLD_WAY) {
+          saveLower = CoinCopyOfArray(solver_->getColLower(), numberColumns);
+          saveUpper = CoinCopyOfArray(solver_->getColUpper(), numberColumns);
+        } else {
+          saveLower =
+              CoinCopyOfArray(continuousSolver_->getColLower(), numberColumns);
+          saveUpper =
+              CoinCopyOfArray(continuousSolver_->getColUpper(), numberColumns);
+        }
+      }
+#endif
       nTightened = clpSolver->tightenBounds();
+#ifdef COIN_HAS_NTY
+      if (rootSymmetryInfo_ && (moreSpecialOptions2_ & 131072) != 0) {
+        // better to sort changed for least interaction?
+        if (nTightened || true) {
+          int numberColumns = solver_->getNumCols();
+          const double *upper = solver_->getColUpper();
+          const double *lower = solver_->getColLower();
+          int nExtra = 0;
+          for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (!upper[iColumn] && saveUpper[iColumn] && !lower[iColumn])
+              nExtra += rootSymmetryInfo_->changeBounds(
+                  iColumn, saveLower, saveUpper, solver_, ORBIT_OLD_WAY - 1);
+          }
+          if (nExtra) {
+            rootSymmetryInfo_->fixSuccess(nExtra);
+            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 orbital tighten\n");
+                // abort();
+                onOptimalPath = false;
+              }
+            }
+          }
+        }
+        delete[] saveLower;
+        delete[] saveUpper;
+      }
+#endif
+    }
     if (nTightened) {
       //printf("%d bounds tightened\n",nTightened);
       if ((specialOptions_ & 1) != 0 && onOptimalPath) {
@@ -10377,7 +10710,7 @@ int CbcModel::resolve(CbcNodeInfo *parent, int whereFrom,
           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(),
+            testValue, trueBestObjValue(), getCutoffIncrement(),
             value, getCutoff());
 #endif
           feasible = false;
@@ -10677,9 +11010,11 @@ CbcModel::findCliques(bool makeEquality,
     lookup[integerVariable_[i]] = i;
 
   // Statistics
+#if COIN_DEVELOP > 1
   int totalP1 = 0, totalM1 = 0;
   int numberBig = 0, totalBig = 0;
   int numberFixed = 0;
+#endif
 
   // Row copy
   const double *elementByRow = matrixByRow.getElements();
@@ -10777,7 +11112,9 @@ CbcModel::findCliques(bool makeEquality,
         break;
       } else if (abs(state) == 2) {
         // we can fix all
+#if COIN_DEVELOP > 1
         numberFixed += numberP1 + numberM1;
+#endif
         if (state > 0) {
           // fix all +1 at 0, -1 at 1
           for (i = 0; i < numberP1; i++)
@@ -10827,8 +11164,10 @@ CbcModel::findCliques(bool makeEquality,
                       upper bound.
                     */
           if (state > 0) {
+#if COIN_DEVELOP > 1
             totalP1 += numberP1;
             totalM1 += numberM1;
+#endif
             for (i = 0; i < numberP1; i++)
               type[i] = 1;
             for (i = 0; i < numberM1; i++) {
@@ -10836,8 +11175,10 @@ CbcModel::findCliques(bool makeEquality,
               type[numberP1++] = 0;
             }
           } else {
+#if COIN_DEVELOP > 1
             totalP1 += numberM1;
             totalM1 += numberP1;
+#endif
             for (i = 0; i < numberP1; i++)
               type[i] = 0;
             for (i = 0; i < numberM1; i++) {
@@ -10863,8 +11204,10 @@ CbcModel::findCliques(bool makeEquality,
           numberCliques++;
         } else if (numberP1 + numberM1 >= lessThanThis) {
           // too big
+#if COIN_DEVELOP > 1
           numberBig++;
           totalBig += numberP1 + numberM1;
+#endif
         }
       }
     }
@@ -13115,7 +13458,7 @@ void CbcModel::setBestSolution(CBC_Message how,
       objectiveValue2 = checkSolution(cutoff, solution2, -1, objectiveValue2);
 #if CBC_FEASIBILITY_INVESTIGATE
       printf("Relaxed second try had objective of %.16g\n",
-        objectiveValue2);
+	     trueObjValue(objectiveValue2));
 #endif
       if (objectiveValue2 + 1.0e-7 < objectiveValue) {
         // Now check tolerances
@@ -13164,14 +13507,14 @@ void CbcModel::setBestSolution(CBC_Message how,
 #endif
         if (largestAway > integerTolerance) {
           handler_->message(CBC_RELAXED1, messages_)
-            << objectiveValue2
+            << trueObjValue(objectiveValue2)
             << iAway
             << largestAway
             << integerTolerance
             << CoinMessageEol;
         } else {
           handler_->message(CBC_RELAXED2, messages_)
-            << objectiveValue2
+            << trueObjValue(objectiveValue2)
             << integerTolerance
             << CoinMessageEol;
           // take
@@ -13202,7 +13545,7 @@ void CbcModel::setBestSolution(CBC_Message how,
         handler_->message(CBC_NOTFEAS1, messages_) << CoinMessageEol;
       else
         handler_->message(CBC_NOTFEAS2, messages_)
-          << objectiveValue << cutoff << CoinMessageEol;
+          << trueObjValue(objectiveValue) << trueObjValue(cutoff) << CoinMessageEol;
     } else if (objectiveValue < bestObjective_) {
       /*
               We have a winner. Install it as the new incumbent.
@@ -13223,7 +13566,7 @@ void CbcModel::setBestSolution(CBC_Message how,
 #if CBC_FEASIBILITY_INVESTIGATE
         if (saveObjectiveValue + 1.0e-7 < bestObjective_)
           printf("First try at solution had objective %.16g, rechecked as %.16g\n",
-            saveObjectiveValue, bestObjective_);
+            saveObjectiveValue, trueBestObjValue());
 #endif
         saveObjectiveValue = CoinMax(saveObjectiveValue, bestObjective_ - 0.0000001 * fabs(bestObjective_));
         cutoff = CoinMin(bestObjective_, saveObjectiveValue) - 1.0e-5;
@@ -13257,7 +13600,7 @@ void CbcModel::setBestSolution(CBC_Message how,
 
       if (how != CBC_ROUNDING) {
         handler_->message(how, messages_)
-          << bestObjective_ << numberIterations_
+          << trueBestObjValue() << numberIterations_
           << numberNodes_ << getCurrentSeconds()
           << CoinMessageEol;
         dealWithEventHandler(CbcEventHandler::solution,
@@ -13269,7 +13612,7 @@ void CbcModel::setBestSolution(CBC_Message how,
         else
           name = "Reduced search";
         handler_->message(CBC_ROUNDING, messages_)
-          << bestObjective_
+          << trueBestObjValue()
           << name
           << numberIterations_
           << numberNodes_ << getCurrentSeconds()
@@ -13398,7 +13741,7 @@ void CbcModel::setBestSolution(CBC_Message how,
             handler_->message(CBC_NOTFEAS1, messages_) << CoinMessageEol;
           else
             handler_->message(CBC_NOTFEAS2, messages_)
-              << objectiveValue << cutoff << CoinMessageEol;
+              << trueObjValue(objectiveValue) << trueObjValue(cutoff) << CoinMessageEol;
         }
       }
     } else {
@@ -13437,14 +13780,14 @@ void CbcModel::setBestSolution(CBC_Message how,
 
         if (how != CBC_ROUNDING) {
           handler_->message(how, messages_)
-            << bestObjective_ << numberIterations_
+            << trueBestObjValue() << numberIterations_
             << numberNodes_ << getCurrentSeconds()
             << CoinMessageEol;
         } else {
           assert(lastHeuristic_);
           const char *name = lastHeuristic_->heuristicName();
           handler_->message(CBC_ROUNDING, messages_)
-            << bestObjective_
+            << trueBestObjValue()
             << name
             << numberIterations_
             << numberNodes_ << getCurrentSeconds()
@@ -15118,6 +15461,19 @@ int CbcModel::chooseBranch(CbcNode *&newNode, int numberPassesLeft,
             }
           }
         }
+      } else if (rootSymmetryInfo_) {
+        int n = rootSymmetryInfo_->orbitalFixing2(solver_);
+        if (n) {
+#if PRINT_MORE == 0
+          if (logLevel() > 1)
+            printf("%d orbital fixes\n", n);
+#endif
+          solver_->resolve();
+          if (!isProvenOptimal()) {
+            if (logLevel() > 1)
+              printf("infeasible after orbital fixing\n");
+          }
+        }
       }
 #endif
       if (numberBeforeTrust_ == 0) {
@@ -15470,7 +15826,7 @@ void CbcModel::setBestSolution(const double *solution, int numberColumns,
       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);
+		trueObjValue(objectiveValue), trueObjValue(objValue));
         messageHandler()->message(CBC_GENERAL, messages())
           << printBuffer << CoinMessageEol;
       }
@@ -15499,7 +15855,7 @@ void CbcModel::setBestSolution(const double *solution, int numberColumns,
     } else {
       // message
       sprintf(printBuffer, "Solution with objective value %g saved",
-        objectiveValue);
+	      trueObjValue(objectiveValue));
       messageHandler()->message(CBC_GENERAL, messages())
         << printBuffer << CoinMessageEol;
     }
@@ -17082,7 +17438,7 @@ int CbcModel::doOneNode(CbcModel *baseModel, CbcNode *&node, CbcNode *&newNode)
         }
         if (newNode->branchingObject()) {
           handler_->message(CBC_BRANCH, messages_)
-            << numberNodes_ << newNode->objectiveValue()
+            << numberNodes_ << trueObjValue(newNode->objectiveValue())
             << newNode->numberUnsatisfied() << newNode->depth()
             << CoinMessageEol;
           // Increment cut counts (taking off current)
@@ -17320,7 +17676,7 @@ int CbcModel::doOneNode(CbcModel *baseModel, CbcNode *&node, CbcNode *&newNode)
       CoinCopyN(bestSolution_, numberColumns, baseModel->bestSolution_);
       baseModel->setCutoff(getCutoff());
       baseModel->handler_->message(CBC_ROUNDING, messages_)
-        << bestObjective_
+        << trueBestObjValue()
         << "heuristic"
         << baseModel->numberIterations_
         << baseModel->numberNodes_ << getCurrentSeconds()
@@ -18315,6 +18671,11 @@ void CbcModel::flipModel()
   flipSolver(referenceSolver_, cutoff);
   flipSolver(continuousSolver_, cutoff);
   flipSolver(solver_, cutoff);
+  // flip interesting bit
+  if ((moreSpecialOptions2_&67108864)==0)
+    moreSpecialOptions2_ |= 67108864;
+  else
+    moreSpecialOptions2_ &= ~67108864;
 }
 #ifdef CBC_KEEP_DEPRECATED
 /* preProcess problem - replacing solver
@@ -18954,6 +19315,12 @@ static void *doRootCbcThread(void *voidInfo)
       model->messages())
       << general << CoinMessageEol;
   }
+#endif
+  // switch off nauty
+#ifdef COIN_HAS_NTY
+  int newOptions = model->moreSpecialOptions2();
+  newOptions &= ~(128 | 256);
+  model->setMoreSpecialOptions2(newOptions);
 #endif
   model->branchAndBound();
   sprintf(general, "Ending multiple root solver");
diff --git a/Cbc/src/CbcModel.hpp b/Cbc/src/CbcModel.hpp
index b1e32b4..96e6ead 100644
--- a/Cbc/src/CbcModel.hpp
+++ b/Cbc/src/CbcModel.hpp
@@ -1413,6 +1413,26 @@ public:
   {
     return solver_->getRowActivity();
   }
+   /// Return true if model flipped to make minimize (for printing)
+  inline bool modelFlipped() const
+  {
+    return (moreSpecialOptions2_&67108864)!=0;
+  }
+  /// Return objective function value with sign corrected
+  inline double trueObjValue(double value) const
+  {
+    return (moreSpecialOptions2_&67108864)==0 ? value : -value;
+  }
+  inline double trueBestObjValue() const
+  {
+    return (moreSpecialOptions2_&67108864)==0 ? bestObjective_ : -bestObjective_;
+  }
+  /// Return cutoff value with sign corrected
+  inline double trueCutoff() const
+  {
+    return (moreSpecialOptions2_&67108864)==0 ?
+      dblParam_[CbcCurrentCutoff] : -dblParam_[CbcCurrentCutoff]; 
+  }
 
   /// Get current objective function value
   inline double getCurrentObjValue() const
@@ -2104,6 +2124,7 @@ public:
 	11/12 bit 2048 - intermittent cuts
 	13/14 bit 8192 - go to bitter end in strong branching (first time)
 	15 bit 32768 - take care of very very small values for Integer/SOS variables
+	24 bit (67108864) - model has been flipped
     */
   inline void setMoreSpecialOptions2(int value)
   {
@@ -2588,15 +2609,24 @@ public:
   {
     maximumNumberIterations_ = value;
   }
-#ifdef COIN_HAS_NTY
+
   /// Symmetry information
   inline CbcSymmetry *symmetryInfo() const
   {
     return symmetryInfo_;
   }
+  /// Set symmetry information
+  inline void setSymmetryInfo(CbcSymmetry * info)
+  {
+    symmetryInfo_ = info;
+  }
   /// get rid of all
   void zapSymmetry();
-#endif
+  /// Root symmetry information
+  inline CbcSymmetry *rootSymmetryInfo() const
+  {
+    return rootSymmetryInfo_;
+  }
   /// Set depth for fast nodes
   inline void setFastNodeDepth(int value)
   {
@@ -3084,6 +3114,8 @@ private:
 #endif
   /// Symmetry information
   CbcSymmetry *symmetryInfo_;
+  /// Root symmetry information
+  CbcSymmetry *rootSymmetryInfo_;
   /// Total number of objects
   int numberObjects_;
 
diff --git a/Cbc/src/CbcNode.cpp b/Cbc/src/CbcNode.cpp
index acbffd8..16db64b 100644
--- a/Cbc/src/CbcNode.cpp
+++ b/Cbc/src/CbcNode.cpp
@@ -1471,19 +1471,19 @@ int CbcNode::chooseBranch(CbcModel *model, CbcNode *lastNode, int numberPassesLe
 
         // 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);
-        }
+        //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;
+        //averageCostPerIteration /= totalNumberIterations;
         // all feasible - choose best bet
 
         // New method does all at once so it can be more sophisticated
@@ -1778,7 +1778,12 @@ int CbcNode::chooseDynamicBranch(CbcModel *model, CbcNode *lastNode,
   int xMark = 0;
   // Get arrays to sort
   double *sort = new double[numberObjects];
+#ifndef COIN_HAS_NTY
   int *whichObject = new int[numberObjects];
+#else
+  int *whichObject = new int[2*numberObjects];
+  int *symmetryType = whichObject+numberObjects;
+#endif
 #ifdef RANGING
   int xPen = 0;
   int *objectMark = new int[2 * numberObjects + 1];
@@ -2021,6 +2026,9 @@ int CbcNode::chooseDynamicBranch(CbcModel *model, CbcNode *lastNode,
     int *which = objectMark + numberObjects + 1;
     int neededPenalties;
     int optionalPenalties;
+#endif
+#ifdef COIN_HAS_NTY
+    int numberOfInterest; 
 #endif
     // We may go round this loop three times (only if we think we have solution)
     for (int iPass = 0; iPass < 3; iPass++) {
@@ -2062,6 +2070,9 @@ int CbcNode::chooseDynamicBranch(CbcModel *model, CbcNode *lastNode,
 
             */
       numberToDo = 0;
+#ifdef COIN_HAS_NTY
+      numberOfInterest = 0; 
+#endif
 #ifdef RANGING
       neededPenalties = 0;
       optionalPenalties = numberObjects;
@@ -2219,6 +2230,9 @@ int CbcNode::chooseDynamicBranch(CbcModel *model, CbcNode *lastNode,
           // Better priority? Flush choices.
           if (priorityLevel < bestPriority) {
             numberToDo = 0;
+#ifdef COIN_HAS_NTY
+	    numberOfInterest = 0;
+#endif
             bestPriority = priorityLevel;
             iBestGot = -1;
             best = 0.0;
@@ -2274,6 +2288,25 @@ int CbcNode::chooseDynamicBranch(CbcModel *model, CbcNode *lastNode,
               i, iColumn, numberThisDown, object->downEstimate(), numberThisUp, object->upEstimate(),
               infeasibility, sort[numberToDo], saveSolution[iColumn]);
           }
+#ifdef COIN_HAS_NTY
+	  symmetryType[numberToDo]=0;
+	  if (infeasibility && model->rootSymmetryInfo() && iColumn<numberColumns) {
+	    int numberCouldFix;
+	    CbcSymmetry * info = model->rootSymmetryInfo();
+	    int nOrbits =
+	      info->worthBranching(saveLower,saveUpper,
+				   iColumn,numberCouldFix);
+	    if (nOrbits && numberCouldFix) {
+#ifdef PRINT_CBCAUTO
+	      printf("Column %d - %d orbits - could fix %d\n",
+		     iColumn,nOrbits,numberCouldFix);
+#endif
+	      // could tune
+	      symmetryType[numberToDo] = (nOrbits<<16) | numberCouldFix;
+	      numberOfInterest++;
+	    }
+	  }
+#endif
           whichObject[numberToDo++] = i;
         } else {
           // for debug
@@ -2443,6 +2476,63 @@ int CbcNode::chooseDynamicBranch(CbcModel *model, CbcNode *lastNode,
     // skip if solution
     if (!numberUnsatisfied_)
       break;
+#ifdef COIN_HAS_NTY
+    // clean
+    if (numberOfInterest) {
+      int n = numberToDo;
+      numberToDo = 0;
+      double best=0.0;
+      // leave as is iBestGot = -1;
+      int loN = 999999;
+      int hiN = 0;
+      for (int i=0;i<n;i++) {
+	int iObject = whichObject[i];
+	if (symmetryType[i]) {
+	  double infeas = sort[i];
+	  int nOrbits = symmetryType[i]>>16;
+	  int nFix = symmetryType[i]|0xffff;
+	  loN = CoinMin(nOrbits,loN); 
+	  hiN = CoinMax(nOrbits,hiN); 
+	  if (nOrbits==1)
+	    infeas *= 100.0;
+	  infeas *= nFix;
+#ifdef PRINT_CBCAUTO
+	  printf("changing infeas for %d from %g to %g\n",
+		 dynamic_cast< const CbcSimpleInteger * >(model->object(whichObject[i]))->columnNumber(),
+		 sort[i],infeas);
+#endif
+	  if (infeas>best) {
+	    best = infeas;
+	    iBestGot = i;
+	  }
+	  sort[numberToDo] = infeas;
+	  symmetryType[numberToDo] = symmetryType[i];
+	  whichObject[numberToDo++] = iObject;
+	}
+      }
+      if (loN!=hiN) {
+	// take out some
+	n = numberToDo;
+	numberToDo = 0;
+	double best=0.0;
+	// leave as is iBestGot = -1;
+	for (int i=0;i<n;i++) {
+	  int iObject = whichObject[i];
+	  int nOrbits = symmetryType[i]>>16;
+	  double infeas = sort[i];
+	  if (nOrbits==loN) {
+	    if (infeas>best) {
+	      best = infeas;
+	      iBestGot = i;
+	    }
+	    sort[numberToDo] = infeas;
+	    symmetryType[numberToDo] = symmetryType[i];
+	    whichObject[numberToDo++] = iObject;
+	  }
+	}
+      }
+    }
+#endif
     int skipAll = (numberNotTrusted == 0 || numberToDo == 1) ? 1 : 0;
     bool doneHotStart = false;
     //DEPRECATED_STRATEGYint searchStrategy = saveSearchStrategy>=0 ? (saveSearchStrategy%10) : -1;
@@ -3997,12 +4087,30 @@ int CbcNode::chooseDynamicBranch(CbcModel *model, CbcNode *lastNode,
         }
       }
     }
+  } else if (model->rootSymmetryInfo() && kColumn >=0) {
+    CbcObject *obj = (dynamic_cast< CbcBranchingObject * >(branch_))->object();
+    int returnCode =
+      model->rootSymmetryInfo()->changeBounds(kColumn,
+					      saveLower,saveUpper,
+					      solver,1);
+    if (returnCode>0) {
+#ifdef PRINT_CBCAUTO
+      printf("Orbital branching on %d - %d fixed depth %d\n",kColumn,returnCode,depth_);
+#endif
+      // saved orbit OK
+      delete branch_;
+      // use saved list
+      branch_ = new CbcOrbitalBranchingObject(model, kColumn, returnCode);
+    } else if (returnCode == -1) {
+      // switch off from here on
+    }
   }
 #endif
   if (model->logLevel() > 1)
     printf("Node %d depth %d unsatisfied %d sum %g obj %g guess %g branching on %d\n",
       model->getNodeCount(), depth_, numberUnsatisfied_,
-      sumInfeasibilities_, objectiveValue_, guessedObjectiveValue_,
+	   sumInfeasibilities_, model->trueObjValue(objectiveValue_),
+	   model->trueObjValue(guessedObjectiveValue_),
       kColumn);
 #ifdef DO_ALL_AT_ROOT
   if (strongType) {
@@ -4111,6 +4219,7 @@ typedef struct {
    2 set if down was infeasible
    4 set if up was infeasible
  */
+static
 int solveAnalyze(void *info)
 {
   StrongBundle *bundle = reinterpret_cast< StrongBundle * >(info);
@@ -4232,7 +4341,7 @@ int solveAnalyze(void *info)
         }
         choice->movement[iWay] = newObjectiveValue;
       } else {
-#ifdef COIN_HAS_CLP
+#if 0 //def COIN_HAS_CLP
         OsiClpSolverInterface *osiclp = dynamic_cast< OsiClpSolverInterface * >(solver);
         ClpSimplex *simplex = osiclp ? osiclp->getModelPtr() : NULL;
 #endif
@@ -4591,7 +4700,6 @@ int CbcNode::analyze(CbcModel *model, double *results)
   double *currentSolution = model->currentSolution();
   double objMin = 1.0e50;
   double objMax = -1.0e50;
-  bool needResolve = false;
   int maxChoices = 1;
   int currentChoice = 0;
   int numberThreads = 0;
@@ -4762,7 +4870,6 @@ int CbcNode::analyze(CbcModel *model, double *results)
     Now calculate the cost forcing the variable up and down.
   */
   int iDo = 0;
-  int iDone = -1;
   int numberDone = 0;
   int iThread = 0;
   int threadStatus = 0;
@@ -4804,9 +4911,7 @@ int CbcNode::analyze(CbcModel *model, double *results)
       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;
         if (nearest < saveUpper[iColumn]) {
           lowerValue = nearest;
         } else {
@@ -4964,7 +5069,6 @@ int CbcNode::analyze(CbcModel *model, double *results)
             << CoinMessageEol;
         } else {
           // up feasible, down infeasible
-          needResolve = true;
           numberToFix++;
           saveLower[iColumn] = choice.upLowerBound;
           solver->setColLower(iColumn, choice.upLowerBound);
@@ -4977,7 +5081,6 @@ int CbcNode::analyze(CbcModel *model, double *results)
       } else {
         if (choice.movement[0] < 1.0e100) {
           // down feasible, up infeasible
-          needResolve = true;
           numberToFix++;
           saveUpper[iColumn] = choice.downUpperBound;
           solver->setColUpper(iColumn, choice.downUpperBound);
@@ -5043,7 +5146,6 @@ int CbcNode::analyze(CbcModel *model, double *results)
       } else {
         if (choice.movement[0] < 1.0e100) {
           // down feasible, up infeasible
-          needResolve = true;
           numberToFix++;
           saveUpper[iColumn] = lowerValue;
           solver->setColUpper(iColumn, lowerValue);
@@ -5245,12 +5347,14 @@ int CbcNode::analyze(CbcModel *model, double *results)
     temp->setDblParam(OsiDualObjectiveLimit, COIN_DBL_MAX);
     temp->resolve();
     {
+#ifndef NDEBUG
       const double *lower = temp->getColLower();
       const double *upper = temp->getColUpper();
       for (int i = 0; i < numberColumns; i++) {
         assert(lower[i] == saveLower[i]);
         assert(upper[i] == saveUpper[i]);
       }
+#endif
     }
     delete ws;
     ws = temp->getWarmStart();
@@ -5274,7 +5378,6 @@ int CbcNode::analyze(CbcModel *model, double *results)
     double primalTolerance;
     solver->getDblParam(OsiPrimalTolerance, primalTolerance);
     iDo = 0;
-    iDone = -1;
     numberDone = 0;
     int iThread = 0;
     threadStatus = 0;
diff --git a/Cbc/src/CbcParam.cpp b/Cbc/src/CbcParam.cpp
index fea4b08..84a7779 100644
--- a/Cbc/src/CbcParam.cpp
+++ b/Cbc/src/CbcParam.cpp
@@ -34,10 +34,10 @@ CbcParam::CbcParam()
   , shortHelp_()
   , longHelp_()
   , action_(CBC_PARAM_NOTUSED_INVALID)
+  , currentKeyWord_(-1)
   , display_(false)
   , intValue_(0)
   , doubleValue_(0)
-  , currentKeyWord_(-1)
   , indexNumber_(0)
 {
 }
@@ -346,6 +346,7 @@ CbcParam::doubleParameter(OsiSolverInterface *model) const
   default:
     abort();
   }
+  (void)getDblParamRetValue;
   return value;
 }
 int CbcParam::setIntParameter(OsiSolverInterface *model, int value) const
diff --git a/Cbc/src/CbcSOS.cpp b/Cbc/src/CbcSOS.cpp
index 4a188df..53adc55 100644
--- a/Cbc/src/CbcSOS.cpp
+++ b/Cbc/src/CbcSOS.cpp
@@ -453,16 +453,16 @@ void CbcSOS::feasibleRegion()
   double integerTolerance2 = model_->getDblParam(CbcModel::CbcIntegerTolerance);
   int firstNonZero2 = -1;
   int lastNonZero2 = -1;
-  double weight = 0.0;
-  double sum = 0.0;
+  //double weight = 0.0;
+  //double sum = 0.0;
 
   for (j = 0; j < numberMembers_; j++) {
     int iColumn = members_[j];
     double value = CoinMax(lower[iColumn], solution[iColumn]);
     value = CoinMin(upper[iColumn], value);
-    sum += value;
+    //sum += value;
     if (fabs(value) > integerTolerance && (upper[iColumn] || oddValues_)) {
-      weight += weights_[j] * value;
+      //weight += weights_[j] * value;
       if (firstNonZero < 0)
         firstNonZero = j;
       lastNonZero = j;
diff --git a/Cbc/src/CbcSolver.cpp b/Cbc/src/CbcSolver.cpp
index 5b26e2d..3464f54 100644
--- a/Cbc/src/CbcSolver.cpp
+++ b/Cbc/src/CbcSolver.cpp
@@ -874,6 +874,7 @@ static void signal_handler_error(int whichSignal)
   a noop when COIN_DEVELOP is not defined. To avoid compiler warnings, the
   formal parameters also need to go away.
 */
+static
 #ifdef COIN_DEVELOP
 void checkSOS(CbcModel *babModel, const OsiSolverInterface *solver)
 #else
@@ -1261,6 +1262,25 @@ CoinReadGetDoubleField(int &whichArgument, int argc, const char *argv[], int *va
 #define CoinReadGetIntField(x, y, z) CoinReadGetIntField(whichArgument, x, y, z)
 #define CoinReadGetDoubleField(x, y, z) CoinReadGetDoubleField(whichArgument, x, y, z)
 #endif
+// For setting maximum time after postprocessing
+static void setMaximumSeconds(OsiSolverInterface * solver,double originalLimit,
+			      double startTime, double startTimeElapsed,
+			      bool useCpuTime)
+{
+  OsiClpSolverInterface *osiclp =
+    dynamic_cast< OsiClpSolverInterface * >(solver);
+  if (osiclp) {
+    ClpSimplex *lpSolver = osiclp->getModelPtr();
+    // How much have we got left
+    if (useCpuTime) {
+      double timeLeft = originalLimit-(CoinCpuTime()-startTime);
+      lpSolver->setMaximumSeconds(CoinMax(timeLeft,0.0));
+    } else {
+      double timeLeft = originalLimit-(CoinGetTimeOfDay()-startTimeElapsed);
+      lpSolver->setMaximumWallSeconds(CoinMax(timeLeft,0.0));
+    }
+  }
+}
 // Default Constructor
 CbcSolverUsefulData::CbcSolverUsefulData()
 {
@@ -1343,7 +1363,9 @@ int CbcMain1(int argc, const char *argv[],
   CbcSolverUsefulData &parameterData)
 {
   std::vector< CbcOrClpParam > parameters_(parameterData.parameters_);
+#ifdef COIN_HAS_ASL
   double totalTime = parameterData.totalTime_;
+#endif
   bool noPrinting = parameterData.noPrinting_;
   bool useSignalHandler = parameterData.useSignalHandler_;
   CbcModel &model_ = model;
@@ -1431,12 +1453,16 @@ int CbcMain1(int argc, const char *argv[],
       break;
     }
   }
+#if CBC_QUIET == 0
   double time0;
   double time0Elapsed = CoinGetTimeOfDay();
+#endif
   {
     double time1 = CoinCpuTime(), time2;
+#if CBC_QUIET == 0
     time0 = time1;
     double time1Elapsed = time0Elapsed;
+#endif
     bool goodModel = (originalSolver->getNumCols()) ? true : false;
 
     // register signal handler
@@ -1940,7 +1966,9 @@ int CbcMain1(int argc, const char *argv[],
       field = CoinReadGetCommand(argc, argv);
       // Reset time
       time1 = CoinCpuTime();
+#if CBC_QUIET == 0
       time1Elapsed = CoinGetTimeOfDay();
+#endif
       // adjust field if has odd trailing characters
       char temp[200];
       strcpy(temp, field.c_str());
@@ -3703,14 +3731,14 @@ int CbcMain1(int argc, const char *argv[],
                         double *gradient = new double[numberColumns + 1];
                         memcpy(gradient, qp->objectiveAsObject()->gradient(qp, solution, offset, true, 2),
                           numberColumns * sizeof(double));
-                        double rhs = 0.0;
+                        //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];
+                            //rhs += value * solution[i];
                             column[n++] = i;
                           }
                         }
@@ -4001,7 +4029,9 @@ int CbcMain1(int argc, const char *argv[],
               babModel_->assignSolver(solver3);
 #endif
               time2 = CoinCpuTime();
+#ifdef COIN_HAS_ASL
               totalTime += time2 - time1;
+#endif
               //time1 = time2;
               double timeLeft = babModel_->getMaximumSeconds();
               int numberOriginalColumns = babModel_->solver()->getNumCols();
@@ -4569,9 +4599,8 @@ int CbcMain1(int argc, const char *argv[],
                       int iColumn = originalColumns[i];
                       back[iColumn] = i;
                     }
-                    int numberSOSOld = osiclp->numberSOS();
                     int numberSOS = osiclp2->numberSOS();
-                    assert(numberSOS == numberSOSOld);
+                    assert(numberSOS == osiclp->numberSOS());
                     CoinSet *setInfo = const_cast< CoinSet * >(osiclp2->setInfo());
                     for (int i = 0; i < numberSOS; i++) {
                       //int type = setInfo[i].setType();
@@ -5884,14 +5913,12 @@ int CbcMain1(int argc, const char *argv[],
                   // 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 (!integersOK) {
                       int type = (pseudoUp) ? 1 : 0;
                       babModel_->findIntegers(true, type);
-                      numberIntegers = babModel_->numberIntegers();
                     }
                     OsiObject **oldObjects = babModel_->objects();
                     // Do sets and priorities
@@ -7275,10 +7302,30 @@ int CbcMain1(int argc, const char *argv[],
                     int k = parameters_[jParam].currentOptionAsInteger();
                     if (k < 4) {
                       babModel_->setMoreSpecialOptions2(babModel_->moreSpecialOptions2() | (k * 128));
-                    } else {
+                    } else if (k==4 ) {
 #define MAX_NAUTY_PASS 2000
                       nautyAdded = nautiedConstraints(*babModel_,
 						      MAX_NAUTY_PASS);
+		    } else {
+		      assert (k>=5 && k <=9);
+                      if (k == 5)
+                        babModel_->setMoreSpecialOptions2(
+                            babModel_->moreSpecialOptions2() | 128 | 256 |
+                            131072);
+                      else if (k == 6)
+                        babModel_->setMoreSpecialOptions2(
+                            babModel_->moreSpecialOptions2() | 128 | 256 |
+                            262144);
+                      else if (k == 7)
+                        babModel_->setMoreSpecialOptions2(
+                            babModel_->moreSpecialOptions2() | 128 | 256 |
+                            131072 | 262144);
+                      else if (k == 8)
+                        babModel_->setMoreSpecialOptions2(
+                            babModel_->moreSpecialOptions2()|131072|1073741824);
+                      else 
+                        babModel_->setMoreSpecialOptions2(
+                            babModel_->moreSpecialOptions2()|262144|1073741824);
                     }
                   }
                 }
@@ -7361,7 +7408,7 @@ int CbcMain1(int argc, const char *argv[],
                   if (numberSolutions > 1) {
                     for (int iSolution = numberSolutions - 1; iSolution >= 0; iSolution--) {
                       model_.setBestSolution(babModel_->savedSolution(iSolution),
-                        model_.solver()->getNumCols(),
+					     CoinMin(model_.solver()->getNumCols(),babModel_->solver()->getNumCols()),
                         babModel_->savedSolutionObjective(iSolution));
                     }
                   }
@@ -7477,12 +7524,6 @@ int CbcMain1(int argc, const char *argv[],
                     }
                   }
                 }
-#ifndef CBC_OTHER_SOLVER
-		{
-		  OsiClpSolverInterface *solver = dynamic_cast< OsiClpSolverInterface * >(model_.solver());
-		  ClpSimplex *simplex = solver->getModelPtr();
-		}
-#endif
                 int returnCode = CbcClpUnitTest(model_, dirMiplib, extra2, stuff,argc,argv,callBack,parameterData);
                 babModel_ = NULL;
                 return returnCode;
@@ -7503,9 +7544,12 @@ int CbcMain1(int argc, const char *argv[],
 #endif
               statistics_cut_time = 0.0;
               if (!noPrinting_) {
+		double direction =
+		  babModel_->solver()->getObjSense();
                 // Print more statistics
                 sprintf(generalPrint, "Cuts at root node changed objective from %g to %g",
-                  babModel_->getContinuousObjective(), babModel_->rootObjectiveAfterCuts());
+                  babModel_->getContinuousObjective()*direction,
+			babModel_->rootObjectiveAfterCuts()*direction);
                 generalMessageHandler->message(CLP_GENERAL, generalMessages)
                   << generalPrint
                   << CoinMessageEol;
@@ -7571,7 +7615,9 @@ int CbcMain1(int argc, const char *argv[],
               }
               // adjust time to allow for children on some systems
               time2 = CoinCpuTime() + CoinCpuTimeJustChildren();
+#ifdef COIN_HAS_ASL
               totalTime += time2 - time1;
+#endif
               // For best solution
               double *bestSolution = NULL;
               // Say in integer
@@ -7721,12 +7767,19 @@ int CbcMain1(int argc, const char *argv[],
                       << generalPrint
                       << CoinMessageEol;
                   }
-                  saveSolver->resolve();
+		  // set time limit for really bad problems
+		  double timeLimit = parameters_[whichParam(CBC_PARAM_DBL_TIMELIMIT_BAB, parameters_)].doubleValue();
+		  bool useCpuTime = !model_.useElapsedTime();
+		  setMaximumSeconds(saveSolver, timeLimit,
+				    time0, time0Elapsed, useCpuTime);
+                  saveSolver->resolve(); 
                   if (!saveSolver->isProvenOptimal()) {
                     // try all slack
                     CoinWarmStartBasis *basis = dynamic_cast< CoinWarmStartBasis * >(babModel_->solver()->getEmptyWarmStart());
                     saveSolver->setWarmStart(basis);
                     delete basis;
+		    setMaximumSeconds(saveSolver, timeLimit,
+				      time0, time0Elapsed, useCpuTime);
                     saveSolver->initialSolve();
 #ifdef COIN_DEVELOP
                     saveSolver->writeMps("inf2");
@@ -7748,12 +7801,16 @@ int CbcMain1(int argc, const char *argv[],
                   CoinWarmStartBasis *basis = dynamic_cast< CoinWarmStartBasis * >(babModel_->solver()->getWarmStart());
                   originalSolver->setBasis(*basis);
                   delete basis;
+		  setMaximumSeconds(originalSolver, timeLimit,
+				    time0, time0Elapsed, useCpuTime);
                   originalSolver->resolve();
                   if (!originalSolver->isProvenOptimal()) {
                     // try all slack
                     CoinWarmStartBasis *basis = dynamic_cast< CoinWarmStartBasis * >(babModel_->solver()->getEmptyWarmStart());
                     originalSolver->setBasis(*basis);
                     delete basis;
+		    setMaximumSeconds(originalSolver, timeLimit,
+				      time0, time0Elapsed, useCpuTime);
                     originalSolver->initialSolve();
                     OsiClpSolverInterface *osiclp = dynamic_cast< OsiClpSolverInterface * >(originalSolver);
                     if (osiclp)
@@ -8318,7 +8375,9 @@ int CbcMain1(int argc, const char *argv[],
                 goodModel = true;
 #endif
                 time2 = CoinCpuTime();
+#ifdef COIN_HAS_ASL
                 totalTime += time2 - time1;
+#endif
                 time1 = time2;
                 // Go to canned file if just input file
                 if (CbcOrClpRead_mode == 2 && argc == 2) {
@@ -8616,7 +8675,9 @@ int CbcMain1(int argc, const char *argv[],
 #endif
                 }
                 time2 = CoinCpuTime();
+#ifdef COIN_HAS_ASL
                 totalTime += time2 - time1;
+#endif
                 time1 = time2;
               }
             } else {
@@ -9218,7 +9279,9 @@ int CbcMain1(int argc, const char *argv[],
                 ClpSimplex *model2 = lpSolver;
                 model2->writeBasis(fileName.c_str(), outputFormat > 1, outputFormat - 2);
                 time2 = CoinCpuTime();
+#ifdef COIN_HAS_ASL
                 totalTime += time2 - time1;
+#endif
                 time1 = time2;
               }
             } else {
@@ -9292,7 +9355,9 @@ int CbcMain1(int argc, const char *argv[],
               if (!status) {
                 goodModel = true;
                 time2 = CoinCpuTime();
+#ifdef COIN_HAS_ASL
                 totalTime += time2 - time1;
+#endif
                 time1 = time2;
               } else {
                 // errors
@@ -9342,7 +9407,9 @@ int CbcMain1(int argc, const char *argv[],
               if (!status) {
                 goodModel = true;
                 time2 = CoinCpuTime();
+#ifdef COIN_HAS_ASL
                 totalTime += time2 - time1;
+#endif
                 time1 = time2;
               } else {
                 // errors
@@ -10510,7 +10577,9 @@ clp watson.mps -\nscaling off\nprimalsimplex");
               }
               static_cast< ClpSimplexOther * >(lpSolver)->parametrics(fileName.c_str());
               time2 = CoinCpuTime();
+#ifdef COIN_HAS_ASL
               totalTime += time2 - time1;
+#endif
               time1 = time2;
             } else {
               sprintf(generalPrint, "** Current model not valid");
@@ -12120,7 +12189,7 @@ static void statistics(ClpSimplex *originalModel, ClpSimplex *model)
                   }
                 } else {
                   int row2 = mapRow[iRow];
-                  assert(iRow = mapRow[row2]);
+                  assert(iRow == mapRow[row2]);
                   if (rowLower[iRow] != rowLower[row2] || rowLower[row2] != rowLower[iRow])
                     good = false;
                   CoinBigIndex offset2 = rowStart[row2] - start;
diff --git a/Cbc/src/CbcSolverAnalyze.cpp b/Cbc/src/CbcSolverAnalyze.cpp
index 394096d..c73d6a3 100644
--- a/Cbc/src/CbcSolverAnalyze.cpp
+++ b/Cbc/src/CbcSolverAnalyze.cpp
@@ -15,10 +15,9 @@
 */
 
 #include "CbcConfig.h"
+#include "CbcSolverAnalyze.hpp"
 #include "CoinPragma.hpp"
 
-#include "OsiClpSolverInterface.hpp"
-
 #include "ClpMessage.hpp"
 
 #include "CbcModel.hpp"
diff --git a/Cbc/src/CbcSolverAnalyze.hpp b/Cbc/src/CbcSolverAnalyze.hpp
index 456288c..0234fc2 100644
--- a/Cbc/src/CbcSolverAnalyze.hpp
+++ b/Cbc/src/CbcSolverAnalyze.hpp
@@ -11,6 +11,8 @@
 #ifndef CbcSolverAnalyze_H
 #define CbcSolverAnalyze_H
 
+#include "OsiClpSolverInterface.hpp"
+
 int *analyze(OsiClpSolverInterface *solverMod, int &numberChanged,
   double &increment, bool changeInt,
   CoinMessageHandler *generalMessageHandler, bool noPrinting);
diff --git a/Cbc/src/CbcSolverExpandKnapsack.cpp b/Cbc/src/CbcSolverExpandKnapsack.cpp
index a6e7c3b..41e943f 100644
--- a/Cbc/src/CbcSolverExpandKnapsack.cpp
+++ b/Cbc/src/CbcSolverExpandKnapsack.cpp
@@ -14,12 +14,9 @@
 */
 
 #include "CbcConfig.h"
+#include "CbcSolverExpandKnapsack.hpp"
 #include "CoinPragma.hpp"
 
-#include "OsiSolverInterface.hpp"
-
-#include "CglStored.hpp"
-
 #ifndef COIN_HAS_LINK
 #define COIN_HAS_LINK
 #endif
diff --git a/Cbc/src/CbcSolverExpandKnapsack.hpp b/Cbc/src/CbcSolverExpandKnapsack.hpp
index aeebcfe..524a9a9 100644
--- a/Cbc/src/CbcSolverExpandKnapsack.hpp
+++ b/Cbc/src/CbcSolverExpandKnapsack.hpp
@@ -11,6 +11,9 @@
 #ifndef CbcSolverExpandKnapsack_H
 #define CbcSolverExpandKnapsack_H
 
+#include "OsiClpSolverInterface.hpp"
+#include "CglStored.hpp"
+
 OsiSolverInterface *
 expandKnapsack(CoinModel &model, int *whichColumn, int *knapsackStart,
   int *knapsackRow, int &numberKnapsack,
diff --git a/Cbc/src/CbcSolverHeuristics.cpp b/Cbc/src/CbcSolverHeuristics.cpp
index c55c32c..913eb3b 100644
--- a/Cbc/src/CbcSolverHeuristics.cpp
+++ b/Cbc/src/CbcSolverHeuristics.cpp
@@ -8,6 +8,7 @@
 */
 
 #include "CbcConfig.h"
+#include "CbcSolverHeuristics.hpp"
 #include "CoinPragma.hpp"
 
 #include "CoinTime.hpp"
@@ -16,10 +17,6 @@
 
 #include "ClpPresolve.hpp"
 
-#include "CbcOrClpParam.hpp"
-
-#include "CbcModel.hpp"
-
 #include "CbcHeuristicLocal.hpp"
 #include "CbcHeuristicPivotAndFix.hpp"
 //#include "CbcHeuristicPivotAndComplement.hpp"
@@ -710,7 +707,9 @@ fixVubs(CbcModel &model, int skipZero2,
         }
         int jLayer = 0;
         int nFixed = -1;
+#ifdef COIN_DETAIL
         int nTotalFixed = 0;
+#endif
         while (nFixed) {
           nFixed = 0;
           for (iColumn = 0; iColumn < numberColumns; iColumn++) {
@@ -734,7 +733,9 @@ fixVubs(CbcModel &model, int skipZero2,
               }
             }
           }
+#ifdef COIN_DETAIL
           nTotalFixed += nFixed;
+#endif
           jLayer += 100;
         }
         COIN_DETAIL_PRINT(printf("This fixes %d variables in lower priorities\n", nTotalFixed));
@@ -794,7 +795,9 @@ fixVubs(CbcModel &model, int skipZero2,
       //skipZero2=0; // leave 0 fixing
       int jLayer = 0;
       int nFixed = -1;
+#ifdef COIN_DETAIL
       int nTotalFixed = 0;
+#endif
       while (nFixed) {
         nFixed = 0;
         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
@@ -818,7 +821,9 @@ fixVubs(CbcModel &model, int skipZero2,
             }
           }
         }
+#ifdef COIN_DETAIL
         nTotalFixed += nFixed;
+#endif
         jLayer += 100;
       }
       COIN_DETAIL_PRINT(printf("This fixes %d variables in lower priorities\n", nTotalFixed));
@@ -903,9 +908,9 @@ fixVubs(CbcModel &model, int skipZero2,
         break;
       iRelax++;
       int n = 0;
-      double sum0 = 0.0;
-      double sum00 = 0.0;
-      double sum1 = 0.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;
@@ -918,7 +923,7 @@ fixVubs(CbcModel &model, int skipZero2,
           assert(fullSolution[iColumn] > 0.1);
           if (djValue > 0.0) {
             //printf("YY dj of %d at %g is %g\n",iColumn,value,djValue);
-            sum1 += djValue;
+            //sum1 += djValue;
             sort[n] = iColumn;
             dsort[n++] = -djValue;
           } else {
@@ -942,8 +947,8 @@ fixVubs(CbcModel &model, int skipZero2,
             //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;
+              //sum0 -= djValue;
+              //sum00 -= otherValue;
               sort[n] = iColumn;
               if (djValue < -1.0e-2)
                 dsort[n++] = djValue + otherValue;
@@ -1002,7 +1007,9 @@ fixVubs(CbcModel &model, int skipZero2,
       COIN_DETAIL_PRINT(printf("%d fixed %d orig 0 %d 1\n", nFixed, nFixed0, nFixed1));
       int jLayer = 0;
       nFixed = -1;
+#ifdef COIN_DETAIL
       int nTotalFixed = 0;
+#endif
       while (nFixed) {
         nFixed = 0;
         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
@@ -1027,7 +1034,9 @@ fixVubs(CbcModel &model, int skipZero2,
             }
           }
         }
+#ifdef COIN_DETAIL
         nTotalFixed += nFixed;
+#endif
         jLayer += 100;
       }
       nFixed = 0;
diff --git a/Cbc/src/CbcSolverHeuristics.hpp b/Cbc/src/CbcSolverHeuristics.hpp
index 7d64f8a..8e719b4 100644
--- a/Cbc/src/CbcSolverHeuristics.hpp
+++ b/Cbc/src/CbcSolverHeuristics.hpp
@@ -10,6 +10,9 @@
 #ifndef CbcSolverHeuristics_H
 #define CbcSolverHeuristics_H
 
+#include "CbcModel.hpp"
+#include "CbcOrClpParam.hpp"
+
 void crunchIt(ClpSimplex *model);
 
 /*
diff --git a/Cbc/src/CbcSubProblem.cpp b/Cbc/src/CbcSubProblem.cpp
index dceaca3..29fa6c0 100644
--- a/Cbc/src/CbcSubProblem.cpp
+++ b/Cbc/src/CbcSubProblem.cpp
@@ -224,10 +224,10 @@ 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_]);
+    //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
@@ -287,7 +287,7 @@ void CbcSubProblem::apply(OsiSolverInterface *solver, int what) const
         numberChangedBounds_, what);
 #endif
 #endif
-    printf("new bounds %g <= %g <= %g\n", solver->getColLower()[branchVariable_], branchValue_, solver->getColUpper()[branchVariable_]);
+    //printf("new bounds %g <= %g <= %g\n", solver->getColLower()[branchVariable_], branchValue_, solver->getColUpper()[branchVariable_]);
   }
 #ifdef JJF_ZERO
   if ((what & 2) != 0) {
diff --git a/Cbc/src/CbcSymmetry.cpp b/Cbc/src/CbcSymmetry.cpp
index a6f2036..2a62123 100644
--- a/Cbc/src/CbcSymmetry.cpp
+++ b/Cbc/src/CbcSymmetry.cpp
@@ -14,14 +14,6 @@
 
 #ifdef COIN_HAS_NTY
 
-extern "C" {
-#include "nauty.h"
-#include "nausparse.h"
-#ifdef NTY_TRACES
-#include "traces.h"
-#endif
-}
-
 #include <stdio.h>
 #include <cassert>
 #include <vector>
@@ -31,25 +23,12 @@ extern "C" {
 
 #include "CbcSymmetry.hpp"
 #include "CbcBranchingObject.hpp"
+#include "CbcSimpleInteger.hpp"
 #include "CoinTime.hpp"
 #define NAUTY_MAX_LEVEL 0
 #if NAUTY_MAX_LEVEL
 extern int nauty_maxalllevel;
 #endif
-/* Deliberately not threadsafe to save effort
-   Just for statistics
-   and not worth gathering across threads
-   can redo later
- */
-static int nautyBranchCalls_ = 0;
-static int lastNautyBranchCalls_ = 0;
-static int nautyBranchSucceeded_ = 0;
-static int nautyFixCalls_ = 0;
-static int lastNautyFixCalls_ = 0;
-static int nautyFixSucceeded_ = 0;
-static double nautyTime_ = 0.0;
-static double nautyFixes_ = 0.0;
-static double nautyOtherBranches_ = 0.0;
 
 void CbcSymmetry::Node::node(int i, double c, double l, double u, int cod, int s)
 {
@@ -76,6 +55,8 @@ inline bool CbcSymmetry::compare(register Node &a, register Node &b) const
 // simple nauty definitely not thread safe
 static int calls = 0;
 static int maxLevel = 0;
+static char message_[200];
+static CbcSymmetry * baseSymmetry=NULL;
 static void
 userlevelproc(int *lab, int *ptn, int level, int *orbits, statsblk *stats,
   int tv, int index, int tcellsize,
@@ -83,8 +64,7 @@ userlevelproc(int *lab, int *ptn, int level, int *orbits, statsblk *stats,
 {
   calls++;
   if (level > maxLevel) {
-    printf("Level %d after %d calls\n", level, calls);
-    fprintf(stderr, "Level %d after %d calls\n", level, calls);
+    sprintf(message_,"Nauty:: level %d after %d calls", level, calls);
     maxLevel = level;
   }
   if (level > 1500) {
@@ -93,10 +73,94 @@ userlevelproc(int *lab, int *ptn, int level, int *orbits, statsblk *stats,
   //}
   return;
 }
+
+static void userautomproc(int numGenerators,
+		   int * perm,
+		   int * orbits, int numorbits,
+		   int stabvertex, int n)
+{
+  //printf("count %d\n",numGenerators);
+  if (numGenerators>64)
+    return;
+  assert (baseSymmetry);
+  int numberColumns = baseSymmetry->numberColumns();
+  int * workperm = new int [n];
+  int * orbitsX = new int [numberColumns];
+  memset(workperm,0,n*sizeof(int));
+  for (int i=0;i<numberColumns;i++)
+    orbitsX[i]=-1;
+  int numberPerms=0;
+  int numberInPerm=-1;
+  int firstL=-1;
+  for (int i = 0; i < n; ++i) {
+    if (workperm[i] == 0 && perm[i] != i) {
+      int nRow=0;
+      int nCol=0;
+      int l = i;
+      if (l<numberColumns) {
+#ifdef PRINT_CBCAUTO
+	printf("%d ",l);
+#endif
+	nCol++;
+	firstL=l;
+	assert (orbitsX[l]<0);
+      } else {
+	nRow++;
+      }
+      int k;
+      do {
+	  k = l;
+	  l = perm[l];
+	  workperm[k] = 1;
+	  if (l != i) {
+	    if (l<numberColumns) {
+#ifdef PRINT_CBCAUTO
+	      printf("%d ",l);
+#endif
+	      nCol++;
+	      assert (orbitsX[l]<0);
+	      orbitsX[k]=l;
+	    } else {
+	      nRow++;
+	    }
+	  }
+      } while (l != i);
+      if (nCol) {
+	orbitsX[k]=firstL;
+#ifdef PRINT_CBCAUTO
+	printf("\n");
+#endif
+      }
+      assert (nCol==0||nRow==0);
+      if (nCol>0) {
+	if (numberInPerm<0) {
+	  numberInPerm=nCol;
+	} else {
+	  assert (numberInPerm==nCol);
+	}
+	numberPerms++;
+      }
+    }
+  }
+#ifdef PRINT_CBCAUTO
+  printf("%d permutations, %d in each\n",numberPerms,numberInPerm);
+#endif
+  delete [] workperm;
+  if (numberPerms) {
+    cbc_permute permute;
+    permute.numberInPerm=numberInPerm;
+    permute.numberPerms=numberPerms;
+    permute.orbits=orbitsX;
+    baseSymmetry->addPermutation(permute);
+  } else {
+    delete [] orbitsX;
+  }
+}
 void CbcSymmetry::Compute_Symmetry() const
 {
 
   nauty_info_->options()->userlevelproc = userlevelproc;
+  message_[0]='\0';
   std::sort(node_info_.begin(), node_info_.end(), node_sort);
 
   for (std::vector< Node >::iterator i = node_info_.begin(); i != node_info_.end(); ++i)
@@ -126,6 +190,39 @@ void CbcSymmetry::Compute_Symmetry() const
 
   //Print_Orbits ();
   nauty_info_->computeAuto();
+#ifdef PRINT_MORE
+  if (permutations_) {
+    int * marked = new int [4*numberColumns_];
+    //int * whichMarked = marked + numberColumns_;
+    //int * save = whichOrbit_+4*numberColumns_;
+    memset(marked,0,numberColumns_*sizeof(int));
+    int maxMarked = 0;
+    for (int iPerm = 0;iPerm < numberPermutations_;iPerm++) {
+      if (!permutations_[iPerm].numberPerms)
+	continue; // summary permutation
+      const int * orbit = permutations_[iPerm].orbits;
+      int nIn = 0;
+      for (int i=0;i<numberColumns_;i++) {
+	if (orbit[i]>=0) {
+	  nIn++;
+	  marked[i]++;
+	  maxMarked = CoinMax(maxMarked,marked[i]);
+	}
+      }
+      printf("Generator %d has %d\n",iPerm,nIn);
+    }
+    for (int iMark=1;iMark<=maxMarked;iMark++) {
+      int n=0;
+      for (int i=0;i<numberColumns_;i++) {
+	if (marked[i]==iMark)
+	  n++;
+      }
+      if (n)
+	printf("%d are in %d generators\n",n,iMark);
+    }
+    delete [] marked;
+  }
+#endif
   //Print_Orbits ();
 }
 
@@ -134,6 +231,8 @@ int CbcSymmetry::statsOrbits(CbcModel *model, int type) const
   char general[200];
   int returnCode = 0;
   bool printSomething = true;
+  if (type == 1 && (model->moreSpecialOptions2()&(131072|262144)) != 131072) 
+    return 0;
   if (type) {
     double branchSuccess = 0.0;
     if (nautyBranchSucceeded_)
@@ -141,12 +240,21 @@ int CbcSymmetry::statsOrbits(CbcModel *model, int type) const
     double fixSuccess = 0.0;
     if (nautyFixSucceeded_)
       fixSuccess = nautyFixes_ / nautyFixSucceeded_;
-    if (nautyBranchCalls_ > lastNautyBranchCalls_ || nautyFixCalls_ > lastNautyFixCalls_) {
+    if (nautyBranchSucceeded_ > lastNautyBranchSucceeded_ || nautyFixSucceeded_ > lastNautyFixSucceeded_) {
       sprintf(general, "Orbital branching tried %d times, succeeded %d times - average extra %7.3f, fixing %d times (%d, %7.3f)",
         nautyBranchCalls_, nautyBranchSucceeded_, branchSuccess,
         nautyFixCalls_, nautyFixSucceeded_, fixSuccess);
-      lastNautyBranchCalls_ = nautyBranchCalls_;
-      lastNautyFixCalls_ = nautyFixCalls_;
+      if ((model->moreSpecialOptions2()&(131072|262144)) == 131072) {
+	sprintf(general, "Orbital branching succeeded %d times - average extra %7.3f, fixing (%d, %7.3f)",
+		nautyBranchSucceeded_, branchSuccess,
+		nautyFixSucceeded_, fixSuccess);
+	model->messageHandler()->message(CBC_GENERAL,
+					 model->messages())
+	  << general << CoinMessageEol;
+	return 0;
+      }
+      lastNautyBranchSucceeded_ = nautyBranchSucceeded_;
+      lastNautyFixSucceeded_ = nautyFixSucceeded_;
     } else {
       printSomething = false;
     }
@@ -154,16 +262,27 @@ int CbcSymmetry::statsOrbits(CbcModel *model, int type) const
     returnCode = nauty_info_->getNumGenerators();
     if (!nauty_info_->errorStatus()) {
       if (returnCode && numberUsefulOrbits_) {
-        sprintf(general, "Nauty: %d orbits (%d useful covering %d variables), %d generators, group size: %g - dense size %d, sparse %d - took %g seconds",
+	if ((model->moreSpecialOptions2()&(131072|262144)) != 131072) 
+	  model->messageHandler()->message(CBC_GENERAL,
+					   model->messages())
+	    << message_ << CoinMessageEol;
+        sprintf(general, "Nauty: %d orbits (%d useful covering %d variables), %d generators, group size: %g - sparse size %d - took %g seconds",
           nauty_info_->getNumOrbits(), numberUsefulOrbits_, numberUsefulObjects_,
           nauty_info_->getNumGenerators(),
           nauty_info_->getGroupSize(),
-          whichOrbit_[0], whichOrbit_[1], nautyTime_);
+          stats_[1], nautyTime_);
       } else {
-        if ((model->moreSpecialOptions2() & (128 | 256)) != (128 | 256))
+	int options2 = model->moreSpecialOptions2();
+        if ((options2 & (128 | 256)) != (128 | 256)) {
           sprintf(general, "Nauty did not find any useful orbits in time %g", nautyTime_);
-        else
-          sprintf(general, "Nauty did not find any useful orbits - but keeping Nauty on");
+        } else {
+	  if ((options2 & 131072) == 0) {
+	    sprintf(general, "Nauty did not find any useful orbits - but keeping Nauty on");
+	  } else {
+	    sprintf(general, "Nauty did not find any useful orbits in time %g", nautyTime_);
+	    model->setMoreSpecialOptions2(options2 & ~(128 | 256 | 131072));
+	  }
+	}
       }
     } else {
       // error
@@ -176,21 +295,69 @@ int CbcSymmetry::statsOrbits(CbcModel *model, int type) const
     model->messageHandler()->message(CBC_GENERAL,
       model->messages())
       << general << CoinMessageEol;
+  if (!type && (model->moreSpecialOptions2()&(131072|262144)) !=
+		131072)
+    Print_Orbits ();
+#if 0
+  if (!type && (model->moreSpecialOptions2()&(131072|262144)) != 0) {
+    printf("Setting priorities on symmetric\n");
+    int * priorities = new int [numberColumns_];
+    for (int i=0;i<numberColumns_;i++)
+      priorities[i] = -1;
+    for (int iOrbit=0;iOrbit<numberColumns_;iOrbit++) {
+      int n = 0;
+      for (int i=0;i<numberColumns_;i++) {
+	if (whichOrbit_[i]==iOrbit)
+	  n++;
+      }
+      if (!n)
+	break;
+      for (int i=0;i<numberColumns_;i++) {
+	if (whichOrbit_[i]==iOrbit)
+	  priorities[i] = 1000-n;
+      }
+    }	  
+    OsiObject **objects = model->objects();
+    int numberObjects = model->numberObjects();
+    for (int iObj = 0; iObj < numberObjects; iObj++) {
+      CbcSimpleInteger *obj = dynamic_cast< CbcSimpleInteger * >(objects[iObj]);
+      if (!obj)
+	continue;
+      int iColumn = obj->columnNumber();
+      int iPriority = priorities[iColumn];
+      if (iPriority > 0)
+	obj->setPriority(iPriority);
+    }
+    delete [] priorities;
+  }
+#endif
   return returnCode;
 }
 
-void CbcSymmetry::Print_Orbits() const
+void
+CbcSymmetry::fixSuccess(int nFixed)
+{
+  nautyFixSucceeded_++;
+  nautyFixes_+=nFixed;
+}
+// Adjust statistics from threads
+void
+CbcSymmetry::adjustStats(const CbcSymmetry * other)
 {
+  nautyFixes_ += other->nautyFixes_;
+  nautyFixSucceeded_ += other->nautyFixSucceeded_;
+  nautyBranchCalls_ += other->nautyBranchCalls_;
+  nautyBranchSucceeded_ += other->nautyBranchSucceeded_;
+}
 
-  //printf ("num gens = %d, num orbits = %d \n", nauty_info_ -> getNumGenerators(), nauty_info_ -> getNumOrbits() );
+void CbcSymmetry::Print_Orbits(int type) const
+{
 
+  //printf ("num gens = %d, num orbits = %d \n", nauty_info_ -> getNumGenerators(), nauty_info_ -> getNumOrbits() );
+  if (!nauty_info_->getN())
+    return;
   std::vector< std::vector< int > > *new_orbits = nauty_info_->getOrbits();
 
-  printf("Nauty: %d generators, group size: %.0g",
-    //  nauty_info_->getNumOrbits(),
-    nauty_info_->getNumGenerators(),
-    nauty_info_->getGroupSize());
-
   int nNonTrivialOrbits = 0;
 
   for (unsigned int i = 0; i < new_orbits->size(); i++) {
@@ -206,7 +373,7 @@ void CbcSymmetry::Print_Orbits() const
     // printf("] \n");
   }
 
-  printf(" (%d non-trivial orbits).\n", nNonTrivialOrbits);
+  //printf(" (%d non-trivial orbits).\n", nNonTrivialOrbits);
 
 #if 1
   if (nNonTrivialOrbits) {
@@ -214,16 +381,38 @@ void CbcSymmetry::Print_Orbits() const
     int orbCnt = 0;
 
     std::vector< std::vector< int > > *orbits = nauty_info_->getOrbits();
+    if (type) {
+      for (std::vector< std::vector< int > >::iterator i = orbits->begin(); i != orbits->end(); ++i) {
 
-    for (std::vector< std::vector< int > >::iterator i = orbits->begin(); i != orbits->end(); ++i) {
-
-      printf("Orbit %d: ", orbCnt++);
+	printf("Orbit %d: ", orbCnt++);
 
-      for (std::vector< int >::iterator j = i->begin(); j != i->end(); ++j)
-        printf(" %d", *j);
-
-      printf("\n");
+	for (std::vector< int >::iterator j = i->begin(); j != i->end(); ++j)
+	  printf(" %d", *j);
+	
+	printf("\n");
+      }
+    } else {
+      for (std::vector< std::vector< int > >::iterator i = orbits->begin(); i != orbits->end(); ++i) {
+	bool useful=false;
+	if (i->size() > 1) {
+	  for (std::vector< int >::iterator j = i->begin(); j != i->end(); ++j) {
+	    if (*j < numberColumns_) {
+	      useful = true;
+	      break;
+	    }
+	  }
+	  if (useful) {
+	    printf("Orbit %d: ", orbCnt++);
+	    
+	    for (std::vector< int >::iterator j = i->begin(); j != i->end(); ++j)
+	      printf(" %d", *j);
+	    
+	    printf("\n");
+	  }
+	}
+      }
     }
+    delete orbits;
   }
 #endif
 
@@ -246,8 +435,9 @@ void CbcSymmetry::Print_Orbits() const
 }
 void CbcSymmetry::fillOrbits()
 {
-  for (int i = 0; i < numberColumns_; i++)
+  for (int i = 0; i < numberColumns_; i++) {
     whichOrbit_[i] = -1;
+  }
   numberUsefulOrbits_ = 0;
   numberUsefulObjects_ = 0;
 
@@ -256,6 +446,7 @@ void CbcSymmetry::fillOrbits()
   for (std::vector< std::vector< int > >::iterator i = orbits->begin(); i != orbits->end(); ++i) {
     int nUseful = 0;
     int jColumn = -2;
+    
     for (std::vector< int >::iterator j = i->begin(); j != i->end(); ++j) {
       int iColumn = *j;
       if (iColumn < numberColumns_) {
@@ -345,9 +536,605 @@ void CbcSymmetry::ChangeBounds(const double *new_lb, const double *new_ub,
     //printf("Var %d  INPUT lower bound: %f   upper bound %f \n", i, node_info_[i].get_lb(), node_info_[i].get_ub());
   }
 }
+/* for simple stuff - returns number if can use saved orbit (mode 1)
+   otherwise may fix and return number (mode 0) */
+int
+CbcSymmetry::changeBounds(int iColumn, double * saveLower,
+			  double * saveUpper,
+			  OsiSolverInterface * solver,
+			  int mode) const
+{
+  if (saveUpper[iColumn]>1.0e12 || whichOrbit_[iColumn]<0 || saveLower[iColumn])
+    return 0; // only 0-1 at present
+  if (mode>0)
+    nautyBranchCalls_++;
+  int nFixed = 0;
+  int * originalUpper = whichOrbit_ + numberColumns_;
+  double * columnLower = saveLower;
+  double * columnUpper = saveUpper;
+  const double * currentLower = solver->getColLower();
+  double saveUp = columnUpper[iColumn];
+  columnUpper[iColumn] = 0.0;//solver->getColUpper()[iColumn];
+  int * marked = originalUpper + numberColumns_;
+  int * whichMarked = marked + numberColumns_;
+  int * save = whichOrbit_+4*numberColumns_;
+  memset(marked,0,numberColumns_*sizeof(int));
+  for (int iPerm = 0;iPerm < numberPermutations_;iPerm++) {
+    if (!permutations_[iPerm].numberPerms)
+      continue; // summary permutation
+    const int * orbit = permutations_[iPerm].orbits;
+    if (orbit[iColumn]<0)
+      continue;
+    int nMarked = 0;
+    int nTotalOdd = 0;
+    int goodOddOne = -1;
+    for (int i=0;i<numberColumns_;i++) {
+      if (orbit[i]>=0 && !marked[i]) {
+	// OK is all same or one fixed to 0 and rest same
+	int oddOne = -1;
+	int nOdd = 0;
+	int first = i;
+	marked[i] = 1;
+	whichMarked[nMarked++] = i;
+	int j = orbit[i];
+	int lower = static_cast<int>(columnLower[i]);
+	if (lower) nOdd=999; //temp
+	int upper = static_cast<int>(columnUpper[i]);
+	if (upper==0) {
+	  int upperj = static_cast<int>(columnUpper[j]);
+	  if (upperj) {
+	    oddOne = i;
+	    nOdd = 1;
+	    upper = upperj;
+	  }
+	}
+	while (j!=i) {
+	  marked[j] = 1;
+	  whichMarked[nMarked++] = j;
+	  int lowerj = static_cast<int>(columnLower[j]);
+	  if (lowerj) nOdd=999; //temp
+	  int upperj = static_cast<int>(columnUpper[j]);
+	  if (lower!=lowerj || upper != upperj) {
+	    if (nOdd) {
+	      // bad
+	      nOdd = numberColumns_;
+	    } else {
+	      oddOne = j;
+	      nOdd = 1;
+	    }
+	  }
+	  j = orbit[j];
+	}
+	if (!nOdd) {
+	} else if (nOdd==1) {
+	  if (!nTotalOdd)
+	    goodOddOne = oddOne;
+	  nTotalOdd ++;
+	} else {
+	  nTotalOdd = -2*numberColumns_;
+	}
+      }
+    }
+    //printf("permutation %d had %d odd\n",iPerm,nTotalOdd);
+    for (int i=0;i<nMarked;i++) 
+      marked[whichMarked[i]]=0;
+    if (nTotalOdd==1) {
+      int j = orbit[goodOddOne];
+      if (columnUpper[goodOddOne]&&!currentLower[goodOddOne]) {
+	save[nFixed++]=goodOddOne;
+	if (mode<=0) {
+	  //printf("setting goodOddOne %d to zero\n",goodOddOne);
+	  solver->setColUpper(goodOddOne,0.0);
+	  if (mode<0)
+	    columnUpper[goodOddOne] = 0.0;
+	}
+      }
+      while (j!=goodOddOne) {
+	if (columnUpper[j]&&!currentLower[j]) {
+	  //printf("setting %d to zero\n",j);
+	  if (mode<=0) 
+	    solver->setColUpper(j,0.0);
+	  if (mode<0)
+	    columnUpper[j] = 0.0;
+	  save[nFixed++]=j;
+	}
+	j = orbit[j];
+      }
+    }
+  }
+  columnUpper[iColumn] = saveUp;
+  if (mode>0 && nFixed>0) {
+    // done in CbcOrbital nautyBranchSucceeded_++;
+    nautyOtherBranches_+=nFixed;
+  }
+  return nFixed;
+}
+// fix some and return number
+int
+CbcSymmetry::fixSome(int iColumn, double * columnLower,
+			  double * columnUpper) const
+{
+  if (columnUpper[iColumn]>1.0 || whichOrbit_[iColumn]<0 || columnLower[iColumn])
+    return 0; // only 0-1 at present
+  int nFixed = 0;
+  int * originalUpper = whichOrbit_ + numberColumns_;
+  int * marked = originalUpper + numberColumns_;
+  int * whichMarked = marked + numberColumns_;
+  int * save = whichOrbit_+4*numberColumns_;
+  memset(marked,0,numberColumns_*sizeof(int));
+  for (int iPerm = 0;iPerm < numberPermutations_;iPerm++) {
+    if (!permutations_[iPerm].numberPerms)
+      continue; // summary permutation
+    const int * orbit = permutations_[iPerm].orbits;
+    if (orbit[iColumn]<0)
+      continue;
+    int nMarked = 0;
+    int nTotalOdd = 0;
+    int goodOddOne = -1;
+    for (int i=0;i<numberColumns_;i++) {
+      if (orbit[i]>=0 && !marked[i]) {
+	// OK is all same or one fixed to 0 and rest same
+	int oddOne = -1;
+	int nOdd = 0;
+	int first = i;
+	marked[i] = 1;
+	whichMarked[nMarked++] = i;
+	int j = orbit[i];
+	int lower = static_cast<int>(columnLower[i]);
+	if (lower) nOdd=999; //temp
+	int upper = static_cast<int>(columnUpper[i]);
+	if (upper==0) {
+	  int upperj = static_cast<int>(columnUpper[j]);
+	  if (upperj) {
+	    oddOne = i;
+	    nOdd = 1;
+	    upper = upperj;
+	  }
+	}
+	while (j!=i) {
+	  marked[j] = 1;
+	  whichMarked[nMarked++] = j;
+	  int lowerj = static_cast<int>(columnLower[j]);
+	  if (lowerj) nOdd=999; //temp
+	  int upperj = static_cast<int>(columnUpper[j]);
+	  if (lower!=lowerj || upper != upperj) {
+	    if (nOdd) {
+	      // bad
+	      nOdd = numberColumns_;
+	    } else {
+	      oddOne = j;
+	      nOdd = 1;
+	    }
+	  }
+	  j = orbit[j];
+	}
+	if (!nOdd) {
+	} else if (nOdd==1) {
+	  if (!nTotalOdd)
+	    goodOddOne = oddOne;
+	  nTotalOdd ++;
+	} else {
+	  nTotalOdd = -2*numberColumns_;
+	}
+      }
+    }
+    //printf("permutation %d had %d odd\n",iPerm,nTotalOdd);
+    for (int i=0;i<nMarked;i++) 
+      marked[whichMarked[i]]=0;
+    if (nTotalOdd==1) {
+      int j = orbit[goodOddOne];
+      if (columnUpper[goodOddOne]&&!columnLower[goodOddOne]) {
+	save[nFixed++]=goodOddOne;
+      }
+      while (j!=goodOddOne) {
+	if (columnUpper[j]&&!columnLower[j]) {
+	  //printf("setting %d to zero\n",j);
+	  save[nFixed++]=j;
+	}
+	j = orbit[j];
+      }
+    }
+  }
+  return nFixed;
+}
+int
+CbcSymmetry::changeBounds(double *saveLower,
+			  double *saveUpper,
+			  OsiSolverInterface * solver) const
+{
+  int nFixed = 0;
+  int * originalUpper = whichOrbit_ + numberColumns_;
+  int * marked = originalUpper + numberColumns_;
+  int * whichMarked = marked + numberColumns_;
+  int * save = whichOrbit_+4*numberColumns_;
+  double * columnLower = saveLower;
+  double * columnUpper = saveUpper;
+  int numberColumns = solver->getNumCols();
+  // Do faster later (i.e. use orbits more)
+  for (int iColumn = 0;iColumn<numberColumns;iColumn++) {
+    if (whichOrbit_[iColumn] < 0 || saveUpper[iColumn])
+      continue;
+    double saveUp = columnUpper[iColumn];
+    columnUpper[iColumn] = 0.0;//solver->getColUpper()[iColumn];
+    memset(marked,0,numberColumns_*sizeof(int));
+    for (int iPerm = 0;iPerm < numberPermutations_;iPerm++) {
+      if (!permutations_[iPerm].numberPerms)
+	continue; // summary permutation
+      const int * orbit = permutations_[iPerm].orbits;
+      if (orbit[iColumn]<0)
+	continue;
+      int nMarked = 0;
+      int nTotalOdd = 0;
+      int goodOddOne = -1;
+      for (int i=0;i<numberColumns_;i++) {
+	if (orbit[i]>=0 && !marked[i]) {
+	  // OK is all same or one fixed to 0 and rest same
+	  int oddOne = -1;
+	  int nOdd = 0;
+	  int first = i;
+	  marked[i] = 1;
+	  whichMarked[nMarked++] = i;
+	  int j = orbit[i];
+	  int lower = static_cast<int>(columnLower[i]);
+	  if (lower) nOdd=999; //temp
+	  int upper = static_cast<int>(columnUpper[i]);
+	  if (upper==0) {
+	    int upperj = static_cast<int>(columnUpper[j]);
+	    if (upperj) {
+	      oddOne = i;
+	      nOdd = 1;
+	      upper = upperj;
+	    }
+	  }
+	  while (j!=i) {
+	    marked[j] = 1;
+	    whichMarked[nMarked++] = j;
+	    int lowerj = static_cast<int>(columnLower[j]);
+	    if (lowerj) nOdd=999; //temp
+	    int upperj = static_cast<int>(columnUpper[j]);
+	    if (lower!=lowerj || upper != upperj) {
+	      if (nOdd) {
+		// bad
+		nOdd = numberColumns_;
+	      } else {
+		oddOne = j;
+		nOdd = 1;
+	      }
+	    }
+	    j = orbit[j];
+	  }
+	  if (!nOdd) {
+	  } else if (nOdd==1) {
+	    if (!nTotalOdd)
+	      goodOddOne = oddOne;
+	    nTotalOdd ++;
+	  } else {
+	    nTotalOdd = -2*numberColumns_;
+	  }
+	}
+      }
+      //printf("permutation %d had %d odd\n",iPerm,nTotalOdd);
+      for (int i=0;i<nMarked;i++) 
+	marked[whichMarked[i]]=0;
+      if (nTotalOdd==1) {
+	int j = orbit[goodOddOne];
+	if (columnUpper[goodOddOne]) {
+	  save[nFixed++]=goodOddOne;
+	  solver->setColUpper(goodOddOne,0.0);
+	}
+	while (j!=goodOddOne) {
+	  if (columnUpper[j]) {
+	    //printf("setting %d to zero\n",j);
+	    solver->setColUpper(j,0.0);
+	    save[nFixed++]=j;
+	  }
+	  j = orbit[j];
+	}
+      }
+    }
+    columnUpper[iColumn] = saveUp;
+  }
+  return nFixed;
+}
+int
+CbcSymmetry::changeBounds2(double *saveLower,
+			  double *saveUpper,
+			  OsiSolverInterface * solver) const
+{
+  int nFixed = 0;
+  int * originalUpper = whichOrbit_ + numberColumns_;
+  int * marked = originalUpper + numberColumns_;
+  int * whichMarked = marked + numberColumns_;
+  int * save = whichOrbit_+4*numberColumns_;
+  double * columnLower = saveLower;
+  double * columnUpper = saveUpper;
+  int numberColumns = solver->getNumCols();
+  // Do faster later (i.e. use orbits more)
+  for (int iColumn = 0;iColumn<numberColumns;iColumn++) {
+    if (whichOrbit_[iColumn] < 0 || saveUpper[iColumn])
+      continue;
+    double saveUp = columnUpper[iColumn];
+    columnUpper[iColumn] = 0.0;//solver->getColUpper()[iColumn];
+    memset(marked,0,numberColumns_*sizeof(int));
+    for (int iPerm = 0;iPerm < numberPermutations_;iPerm++) {
+      if (!permutations_[iPerm].numberPerms)
+	continue; // summary permutation
+      const int * orbit = permutations_[iPerm].orbits;
+      if (orbit[iColumn]<0)
+	continue;
+      int nMarked = 0;
+      int nTotalOdd = 0;
+      int goodOddOne = -1;
+      for (int i=0;i<numberColumns_;i++) {
+	if (orbit[i]>=0 && !marked[i]) {
+	  // OK is all same or one fixed to 0 and rest same
+	  int oddOne = -1;
+	  int nOdd = 0;
+	  int first = i;
+	  marked[i] = 1;
+	  whichMarked[nMarked++] = i;
+	  int j = orbit[i];
+	  int lower = static_cast<int>(columnLower[i]);
+	  if (lower) nOdd=999; //temp
+	  int upper = static_cast<int>(columnUpper[i]);
+	  if (upper==0) {
+	    int upperj = static_cast<int>(columnUpper[j]);
+	    if (upperj) {
+	      oddOne = i;
+	      nOdd = 1;
+	      upper = upperj;
+	    }
+	  }
+	  while (j!=i) {
+	    marked[j] = 1;
+	    whichMarked[nMarked++] = j;
+	    int lowerj = static_cast<int>(columnLower[j]);
+	    if (lowerj) nOdd=999; //temp
+	    int upperj = static_cast<int>(columnUpper[j]);
+	    if (lower!=lowerj || upper != upperj) {
+	      if (nOdd) {
+		// bad
+		nOdd = numberColumns_;
+	      } else {
+		oddOne = j;
+		nOdd = 1;
+	      }
+	    }
+	    j = orbit[j];
+	  }
+	  if (!nOdd) {
+	  } else if (nOdd==1) {
+	    if (!nTotalOdd)
+	      goodOddOne = oddOne;
+	    nTotalOdd ++;
+	  } else {
+	    nTotalOdd = -2*numberColumns_;
+	  }
+	}
+      }
+      //printf("permutation %d had %d odd\n",iPerm,nTotalOdd);
+      for (int i=0;i<nMarked;i++) 
+	marked[whichMarked[i]]=0;
+      if (nTotalOdd==1) {
+	int j = orbit[goodOddOne];
+	if (columnUpper[goodOddOne]) {
+	  save[nFixed++]=goodOddOne;
+	  columnUpper[goodOddOne] = 0.0;
+	}
+	while (j!=goodOddOne) {
+	  if (columnUpper[j]) {
+	    //printf("setting %d to zero\n",j);
+	    columnUpper[j] = 0.0;
+	    save[nFixed++]=j;
+	  }
+	  j = orbit[j];
+	}
+      }
+    }
+    columnUpper[iColumn] = saveUp;
+  }
+  return nFixed;
+}
+// return number of orbits if worth branching
+int
+CbcSymmetry::worthBranching(const double *columnLower, const double *columnUpper,
+		     int iColumn, int & nFixed) const
+{
+  cbc_permute *permute  = permutations_+numberPermutations_-1;
+  assert (!permute->numberPerms);
+  int * allMarked = permute->orbits;
+  if (!allMarked[iColumn] || columnLower[iColumn])
+    return 0;
+  nFixed = 0;
+  int * originalUpper = whichOrbit_ + numberColumns_;
+  int * marked = originalUpper + numberColumns_;
+  int * whichMarked = marked + numberColumns_;
+  int * save = whichOrbit_+4*numberColumns_;
+  memset(marked,0,numberColumns_*sizeof(int));
+  for (int iPerm = 0;iPerm < numberPermutations_;iPerm++) {
+    if (!permutations_[iPerm].numberPerms)
+      continue; // summary permutation
+    const int * orbit = permutations_[iPerm].orbits;
+    if (orbit[iColumn]<0)
+      continue;
+    int nMarked = 0;
+    int nTotalOdd = 0;
+    int goodOddOne = -1;
+    for (int i=0;i<numberColumns_;i++) {
+      if (orbit[i]>=0 && !marked[i]) {
+	// OK is all same or one fixed to 0 and rest same
+	int oddOne = -1;
+	int nOdd = 0;
+	int first = i;
+	marked[i] = 1;
+	whichMarked[nMarked++] = i;
+	int j = orbit[i];
+	int lower = static_cast<int>(columnLower[i]);
+	if (lower) nOdd=999; //temp
+	int upper = (i != iColumn) ? static_cast<int>(columnUpper[i]) : 0.0;
+	if (upper==0) {
+	  int upperj = (j != iColumn) ? static_cast<int>(columnUpper[j]) : 0.0;
+	  if (upperj) {
+	    oddOne = i;
+	    nOdd = 1;
+	    upper = upperj;
+	  }
+	}
+	while (j!=i) {
+	  marked[j] = 1;
+	  whichMarked[nMarked++] = j;
+	  int lowerj = static_cast<int>(columnLower[j]);
+	  if (lowerj) nOdd=999; //temp
+	  int upperj = (j != iColumn) ? static_cast<int>(columnUpper[j]) : 0.0;
+	  if (lower!=lowerj || upper != upperj) {
+	    if (nOdd) {
+	      // bad
+	      nOdd = numberColumns_;
+	    } else {
+	      oddOne = j;
+	      nOdd = 1;
+	    }
+	  }
+	  j = orbit[j];
+	}
+	if (!nOdd) {
+	} else if (nOdd==1) {
+	  if (!nTotalOdd)
+	    goodOddOne = oddOne;
+	  nTotalOdd ++;
+	} else {
+	  nTotalOdd = -2*numberColumns_;
+	}
+      }
+    }
+    //printf("permutation %d had %d odd\n",iPerm,nTotalOdd);
+    for (int i=0;i<nMarked;i++) 
+      marked[whichMarked[i]]=0;
+    if (nTotalOdd==1) {
+      int j = orbit[goodOddOne];
+      if (columnUpper[goodOddOne]&&!columnLower[goodOddOne]) {
+	nFixed++;
+      }
+      while (j!=goodOddOne) {
+	if (columnUpper[j]&&!columnLower[j]) {
+	  nFixed++;
+	}
+	j = orbit[j];
+      }
+    }
+  }
+  return allMarked[iColumn];
+  //return nFixed;
+}
+
+int
+CbcSymmetry::orbitalFixing2(OsiSolverInterface * solver) 
+{
+  int nFixed = 0;
+  int iCheck;
+  const double * columnLower = solver->getColLower();
+  const double * columnUpper = solver->getColUpper();
+  for (iCheck=0;iCheck<numberColumns_;iCheck++) {
+    if (whichOrbit_[iCheck]>=0 && !columnUpper[iCheck])
+      break;
+  }
+  if (iCheck==numberColumns_)
+    return 0; 
+  nautyFixCalls_ ++;
+  int * originalUpper = whichOrbit_ + numberColumns_;
+  int * marked = originalUpper + numberColumns_;
+  int * whichMarked = marked + numberColumns_;
+  int * save = whichOrbit_+4*numberColumns_;
+  memset(marked,0,numberColumns_*sizeof(int));
+  int possibleNauty = 0;
+  for (int iPerm = 0;iPerm < numberPermutations_;iPerm++) {
+    if (!permutations_[iPerm].numberPerms)
+      continue; // summary permutation
+    const int * orbit = permutations_[iPerm].orbits;
+    int nMarked = 0;
+    int nTotalOdd = 0;
+    int goodOddOne = -1;
+    for (int i=0;i<numberColumns_;i++) {
+      if (orbit[i]>=0 && !marked[i]) {
+	// OK is all same or one fixed to 0 and rest same
+	int oddOne = -1;
+	int nOdd = 0;
+	int first = i;
+	marked[i] = 1;
+	whichMarked[nMarked++] = i;
+	int j = orbit[i];
+	int lower = static_cast<int>(columnLower[i]);
+	if (lower) nOdd=999; //temp
+	int upper = static_cast<int>(columnUpper[i]);
+	if (upper==0) {
+	  int upperj = static_cast<int>(columnUpper[j]);
+	  if (upperj) {
+	    oddOne = i;
+	    nOdd = 1;
+	    upper = upperj;
+	  }
+	}
+	while (j!=i) {
+	  marked[j] = 1;
+	  whichMarked[nMarked++] = j;
+	  int lowerj = static_cast<int>(columnLower[j]);
+	  if (lowerj) nOdd=999; //temp
+	  int upperj = static_cast<int>(columnUpper[j]);
+	  if (lower!=lowerj || upper != upperj) {
+	    if (nOdd) {
+	      // bad
+	      nOdd = numberColumns_;
+	    } else {
+	      oddOne = j;
+	      nOdd = 1;
+	    }
+	  }
+	  j = orbit[j];
+	}
+	if (!nOdd) {
+	} else if (nOdd==1) {
+	  if (!nTotalOdd)
+	    goodOddOne = oddOne;
+	  nTotalOdd ++;
+	} else {
+	  nTotalOdd = -2*numberColumns_;
+	}
+      }
+    }
+    //printf("permutation %d had %d odd\n",iPerm,nTotalOdd);
+    for (int i=0;i<nMarked;i++) 
+      marked[whichMarked[i]]=0;
+    if (nTotalOdd==1) {
+      nautyFixSucceeded_++;
+      int j = orbit[goodOddOne];
+      if (columnUpper[goodOddOne]) {
+	nautyFixes_++;
+	save[nFixed++]=goodOddOne;
+	solver->setColUpper(goodOddOne,0.0); 
+      }
+      while (j!=goodOddOne) {
+	if (columnUpper[j]) {
+	  //printf("setting %d to zero\n",j);
+	  nautyFixes_++;
+	  solver->setColUpper(j,0.0);
+	  save[nFixed++]=j;
+	}
+	j = orbit[j];
+      }
+      possibleNauty++;
+    } else if (!nTotalOdd) {
+      possibleNauty++;
+    }
+  }
+  if (!nFixed && !possibleNauty)
+    nFixed = -1; // say no good from here on
+  return nFixed;
+}
 void CbcSymmetry::setupSymmetry(CbcModel * model)
 {
   OsiSolverInterface * solver = model->continuousSolver();
+  if (!solver)
+    solver = model->solver();
   double startCPU = CoinCpuTime();
   const double *objective = solver->getObjCoefficients();
   const double *columnLower = solver->getColLower();
@@ -355,22 +1142,22 @@ void CbcSymmetry::setupSymmetry(CbcModel * model)
   int numberColumns = solver->getNumCols();
   int numberRows = solver->getNumRows();
   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();
-
+  
   const double *rowLower = solver->getRowLower();
   const double *rowUpper = solver->getRowUpper();
   //  // Find Coefficients
-
+  
   /// initialize nauty
-
+  
   int num_affine = 0;
-
+  
   for (iColumn = 0; iColumn < numberColumns; iColumn++) {
     if (objective[iColumn] && objective[iColumn] != 1.0)
       num_affine++;
@@ -384,7 +1171,7 @@ void CbcSymmetry::setupSymmetry(CbcModel * model)
         num_affine++;
     }
   }
-
+  
   // Create Nauty object
 
   int coef_count = numberRows + numberColumns + 1;
@@ -414,169 +1201,192 @@ void CbcSymmetry::setupSymmetry(CbcModel * model)
   spaceDense *= nc + WORDSIZE - 1;
   spaceDense /= WORDSIZE;
   int spaceSparse = 0;
-  {
-    size_t numberElements = 0;
-    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
-      double value = objective[iColumn];
-      if (value) {
-        if (value == 1.0) {
-          numberElements += 2;
-        } else {
-          numberElements += 4;
-          coef_count++;
-        }
+  size_t numberElements = 0;
+  for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+    double value = objective[iColumn];
+    if (value) {
+      if (value == 1.0) {
+	numberElements += 2;
+      } else {
+	numberElements += 4;
+	coef_count++;
       }
     }
-    for (iRow = 0; iRow < numberRows; iRow++) {
-      for (CoinBigIndex j = rowStart[iRow];
-           j < rowStart[iRow] + rowLength[iRow]; j++) {
-        int jColumn = column[j];
-        double value = elementByRow[j];
-        if (value == 1.0) {
-          numberElements += 2;
-        } else {
-          numberElements += 4;
-          coef_count++;
-        }
+  }
+  for (iRow = 0; iRow < numberRows; iRow++) {
+    for (CoinBigIndex j = rowStart[iRow];
+	 j < rowStart[iRow] + rowLength[iRow]; j++) {
+      int jColumn = column[j];
+      double value = elementByRow[j];
+      if (value == 1.0) {
+	numberElements += 2;
+      } else {
+	numberElements += 4;
+	coef_count++;
       }
     }
-    spaceSparse = 2 * nc + numberElements;
-    //printf("Space for sparse is %d for dense %g\n",
-    //	   spaceSparse,spaceDense);
+  }
+  spaceSparse = 2 * nc + numberElements;
+  double maxNauty1 = 1.0e8;
+  double maxNauty2 = 1.0e11;
+  int options2 = model->moreSpecialOptions2();
+  if ((options2&(131072|262144)) == 262144) {
+    // lightweight
+    options2 &= ~262144;
+    options2 |= 131072;
+    model->setMoreSpecialOptions2(options2);
+    maxNauty1 = 1.0e7;
+    maxNauty2 = 1.0e9;
+  }
+  double n_squared = static_cast<double>(coef_count)*coef_count;
+  if (spaceSparse > maxNauty1/100 || n_squared > maxNauty2/100) {
+    char general[200];
+    sprintf(general,"Nauty sparseSpace %d affine %d coefficient count %d",
+	    spaceSparse,num_affine,coef_count);
+    model->messageHandler()->message(CBC_GENERAL,
+				     model->messages())
+      << general << CoinMessageEol;
+  }
+  if (spaceSparse > maxNauty1 || n_squared > maxNauty2) {
+    // too big
+    options2 &= ~(128|256|131072|262144);
+    model->setMoreSpecialOptions2(options2);
+    nauty_info_ = new CbcNauty(0,NULL,NULL,NULL);
+    return;
+  }
 #ifdef NTY_TRACES
-    bool goSparse = true;
+  bool goSparse = true;
 #else
-    bool goSparse = (spaceSparse < spaceDense);
+  bool goSparse = (spaceSparse < spaceDense);
 #endif
-    // for now always sparse
-    goSparse = true;
-    if (goSparse) {
-      sparse = true;
-      v = new size_t[nc + 1];
-      d = new int[nc];
-      e = new int[numberElements];
-      size_t *counts = new size_t[coef_count + 1];
-      memset(counts, 0, coef_count * sizeof(size_t));
-      coef_count = numberRows + numberColumns + 1;
-      // create graph (part 2)
-      for (iColumn = 0; iColumn < numberColumns; iColumn++) {
-        double value = objective[iColumn];
-        if (value) {
-          if (value == 1.0) {
-            counts[index]++;
-            counts[iColumn]++;
-          } else {
-            counts[index]++;
-            counts[coef_count] += 2;
-            counts[iColumn]++;
-            coef_count++;
-          }
-        }
+  // for now always sparse
+  goSparse = true;
+  if (goSparse) {
+    sparse = true;
+    v = new size_t[nc + 1];
+    d = new int[nc];
+    e = new int[numberElements];
+    size_t *counts = new size_t[coef_count + 1];
+    memset(counts, 0, coef_count * sizeof(size_t));
+    coef_count = numberRows + numberColumns + 1;
+    // create graph (part 2)
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+      double value = objective[iColumn];
+      if (value) {
+	if (value == 1.0) {
+	  counts[index]++;
+	  counts[iColumn]++;
+	} else {
+	  counts[index]++;
+	  counts[coef_count] += 2;
+	  counts[iColumn]++;
+	  coef_count++;
+	}
       }
-      index++;
-      for (iRow = 0; iRow < numberRows; iRow++) {
-        for (CoinBigIndex j = rowStart[iRow];
-             j < rowStart[iRow] + rowLength[iRow]; j++) {
-          int jColumn = column[j];
-          double value = elementByRow[j];
-          if (value == 1.0) {
-            counts[index]++;
-            counts[jColumn]++;
-          } else {
-            counts[index]++;
-            counts[coef_count] += 2;
-            counts[jColumn]++;
-            coef_count++;
-          }
-        }
-        index++;
+    }
+    index++;
+    for (iRow = 0; iRow < numberRows; iRow++) {
+      for (CoinBigIndex j = rowStart[iRow];
+	   j < rowStart[iRow] + rowLength[iRow]; j++) {
+	int jColumn = column[j];
+	double value = elementByRow[j];
+	if (value == 1.0) {
+	  counts[index]++;
+	  counts[jColumn]++;
+	} else {
+	  counts[index]++;
+	  counts[coef_count] += 2;
+	  counts[jColumn]++;
+	  coef_count++;
+	}
       }
-      // create graph (part 3)
-      assert(nc == coef_count);
-      numberElements = 0;
-      v[0] = 0;
-      for (int i = 0; i < nc; i++) {
-        int count = counts[i];
-        d[i] = count;
-        counts[i] = v[i];
-        numberElements += count;
-        ;
-        v[i + 1] = numberElements;
+      index++;
+    }
+    // create graph (part 3)
+    assert(nc == coef_count);
+    numberElements = 0;
+    v[0] = 0;
+    for (int i = 0; i < nc; i++) {
+      int count = counts[i];
+      d[i] = count;
+      counts[i] = v[i];
+      numberElements += count;
+      ;
+      v[i + 1] = numberElements;
+    }
+    index = numberColumns;
+    coef_count = numberRows + numberColumns + 1;
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+      double value = objective[iColumn];
+      if (value) {
+	int where;
+	if (value == 1.0) {
+	  where = counts[index];
+	  counts[index]++;
+	  e[where] = iColumn;
+	  where = counts[iColumn];
+	  counts[iColumn]++;
+	  e[where] = index;
+	} else {
+	  Node coef_vertex;
+	  coef_vertex.node(coef_count, value, value, value, -2, 0);
+	  node_info_.push_back(coef_vertex);
+	  where = counts[index];
+	  counts[index]++;
+	  e[where] = coef_count;
+	  where = counts[coef_count];
+	  counts[coef_count]++;
+	  e[where] = index;
+	  where = counts[coef_count];
+	  counts[coef_count]++;
+	  e[where] = iColumn;
+	  where = counts[iColumn];
+	  counts[iColumn]++;
+	  e[where] = coef_count;
+	  coef_count++;
+	}
       }
-      index = numberColumns;
-      coef_count = numberRows + numberColumns + 1;
-      for (iColumn = 0; iColumn < numberColumns; iColumn++) {
-        double value = objective[iColumn];
-        if (value) {
-          int where;
-          if (value == 1.0) {
-            where = counts[index];
-            counts[index]++;
-            e[where] = iColumn;
-            where = counts[iColumn];
-            counts[iColumn]++;
-            e[where] = index;
-          } else {
-            Node coef_vertex;
-            coef_vertex.node(coef_count, value, value, value, -2, 0);
-            node_info_.push_back(coef_vertex);
-            where = counts[index];
-            counts[index]++;
-            e[where] = coef_count;
-            where = counts[coef_count];
-            counts[coef_count]++;
-            e[where] = index;
-            where = counts[coef_count];
-            counts[coef_count]++;
-            e[where] = iColumn;
-            where = counts[iColumn];
-            counts[iColumn]++;
-            e[where] = coef_count;
-            coef_count++;
-          }
-        }
+    }
+    index++;
+    for (iRow = 0; iRow < numberRows; iRow++) {
+      Node vertex;
+      vertex.node(index, 0.0, rowLower[iRow], rowUpper[iRow],
+		  COUENNE_HACKED_EXPRGROUP, 0);
+      node_info_.push_back(vertex);
+      for (CoinBigIndex j = rowStart[iRow];
+	   j < rowStart[iRow] + rowLength[iRow]; j++) {
+	int jColumn = column[j];
+	double value = elementByRow[j];
+	int where;
+	if (value == 1.0) {
+	  where = counts[index];
+	  counts[index]++;
+	  e[where] = jColumn;
+	  where = counts[jColumn];
+	  counts[jColumn]++;
+	  e[where] = index;
+	} else {
+	  Node coef_vertex;
+	  coef_vertex.node(coef_count, value, value, value, -2, 0);
+	  node_info_.push_back(coef_vertex);
+	  where = counts[index];
+	  counts[index]++;
+	  e[where] = coef_count;
+	  where = counts[coef_count];
+	  counts[coef_count]++;
+	  e[where] = index;
+	  where = counts[coef_count];
+	  counts[coef_count]++;
+	  e[where] = jColumn;
+	  where = counts[jColumn];
+	  counts[jColumn]++;
+	  e[where] = coef_count;
+	  coef_count++;
+	}
       }
       index++;
-      for (iRow = 0; iRow < numberRows; iRow++) {
-        Node vertex;
-        vertex.node(index, 0.0, rowLower[iRow], rowUpper[iRow],
-          COUENNE_HACKED_EXPRGROUP, 0);
-        node_info_.push_back(vertex);
-        for (CoinBigIndex j = rowStart[iRow];
-             j < rowStart[iRow] + rowLength[iRow]; j++) {
-          int jColumn = column[j];
-          double value = elementByRow[j];
-          int where;
-          if (value == 1.0) {
-            where = counts[index];
-            counts[index]++;
-            e[where] = jColumn;
-            where = counts[jColumn];
-            counts[jColumn]++;
-            e[where] = index;
-          } else {
-            Node coef_vertex;
-            coef_vertex.node(coef_count, value, value, value, -2, 0);
-            node_info_.push_back(coef_vertex);
-            where = counts[index];
-            counts[index]++;
-            e[where] = coef_count;
-            where = counts[coef_count];
-            counts[coef_count]++;
-            e[where] = index;
-            where = counts[coef_count];
-            counts[coef_count]++;
-            e[where] = jColumn;
-            where = counts[jColumn];
-            counts[jColumn]++;
-            e[where] = coef_count;
-            coef_count++;
-          }
-        }
-        index++;
-      }
-      delete[] counts;
     }
+    delete[] counts;
   }
 
   nauty_info_ = new CbcNauty(nc, v, d, e);
@@ -632,7 +1442,12 @@ void CbcSymmetry::setupSymmetry(CbcModel * model)
     }
   }
   numberColumns_ = numberColumns;
-  whichOrbit_ = new int[2 * numberColumns_];
+  whichOrbit_ = new int[5*numberColumns_];
+  for (int i = 0; i < 2*numberColumns_; i++)
+    whichOrbit_[i] = -1;
+  // zero out static stuff
+  calls = 0;
+  maxLevel = 0;
   nautyBranchCalls_ = 0;
   nautyBranchSucceeded_ = 0;
   nautyFixCalls_ = 0;
@@ -640,6 +1455,12 @@ void CbcSymmetry::setupSymmetry(CbcModel * model)
   nautyTime_ = 0.0;
   nautyFixes_ = 0.0;
   nautyOtherBranches_ = 0.0;
+  lastNautyBranchSucceeded_ = 0;
+  lastNautyFixSucceeded_ = 0;
+  if ((options2&131072)!=0) {
+    baseSymmetry = this;
+    nauty_info_->options()->userautomproc = userautomproc;
+  }
   try {
     Compute_Symmetry();
   } catch (CoinError &e) {
@@ -650,14 +1471,36 @@ void CbcSymmetry::setupSymmetry(CbcModel * model)
       <<general <<CoinMessageEol;
   }
   fillOrbits();
-  //whichOrbit_[2]=numberUsefulOrbits_;
+  if (numberUsefulOrbits_ && (options2&131072)!=0) {
+    // store original bounds for integers
+    // only do for 0 lower bound
+    int nPossible = 0;
+    int * originalUpper = whichOrbit_ + numberColumns_;
+    for (int i=0;i<numberColumns_;i++) {
+      int kUpper = -1;
+      if (!columnLower[i]) 
+	kUpper = static_cast<int>(columnUpper[i]);
+      if (kUpper>0) {
+	originalUpper[i] = kUpper;
+	nPossible++;
+      } else {
+	originalUpper[i] = -1;
+      }
+    }
+    if (!nPossible) 
+      model->setMoreSpecialOptions2(options2 & ~(128 | 256 | 131072));
+  } else {
+    if ((options2&131072)!=0)
+      options2 &= ~(128 | 256);
+    model->setMoreSpecialOptions2(options2 & ~131072);
+  }
   //Print_Orbits ();
   // stats in array
   if (spaceDense < COIN_INT_MAX)
-    whichOrbit_[0] = spaceDense;
+    stats_[0] = spaceDense;
   else
-    whichOrbit_[0] = COIN_INT_MAX;
-  whichOrbit_[1] = spaceSparse;
+    stats_[0] = COIN_INT_MAX;
+  stats_[1] = spaceSparse;
   double endCPU = CoinCpuTime();
   nautyTime_ = endCPU - startCPU;
 }
@@ -723,13 +1566,35 @@ int CbcSymmetry::orbitalFixing(OsiSolverInterface *solver)
   }
   return n;
 }
+// takes ownership of cbc_permute (orbits part)
+void
+CbcSymmetry::addPermutation(cbc_permute permutation)
+{
+  cbc_permute * temp = new cbc_permute[numberPermutations_+1];
+  memcpy(temp,permutations_,numberPermutations_*sizeof(cbc_permute));
+  delete [] permutations_;
+  permutations_=temp;
+  permutations_[numberPermutations_] = permutation;
+  numberPermutations_++;
+}
 // Default Constructor
 CbcSymmetry::CbcSymmetry()
   : nauty_info_(NULL)
   , numberColumns_(0)
   , numberUsefulOrbits_(0)
   , numberUsefulObjects_(0)
+  , numberPermutations_(0)
+  , permutations_(NULL)
   , whichOrbit_(NULL)
+  , nautyTime_(0.0)
+  , nautyFixes_(0.0)
+  , nautyOtherBranches_(0.0)
+  , nautyBranchCalls_(0)
+  , lastNautyBranchSucceeded_(0)
+  , nautyBranchSucceeded_(0)
+  , nautyFixCalls_(0)
+  , lastNautyFixSucceeded_(0)
+  , nautyFixSucceeded_(0)
 {
 }
 // Copy constructor
@@ -741,11 +1606,29 @@ CbcSymmetry::CbcSymmetry(const CbcSymmetry &rhs)
   numberUsefulObjects_ = rhs.numberUsefulObjects_;
   numberColumns_ = rhs.numberColumns_;
   if (rhs.whichOrbit_)
-    whichOrbit_ = CoinCopyOfArray(rhs.whichOrbit_, numberColumns_);
+    whichOrbit_ = CoinCopyOfArray(rhs.whichOrbit_, 5*numberColumns_);
   else
     whichOrbit_ = NULL;
+  numberPermutations_ = rhs.numberPermutations_;
+  if (numberPermutations_) {
+    permutations_ = CoinCopyOfArray(rhs.permutations_, numberPermutations_);
+    for (int i=0;i<numberPermutations_;i++) {
+      permutations_[i].orbits = CoinCopyOfArray(permutations_[i].orbits,
+						numberColumns_);
+    }
+  } else {
+    permutations_ = NULL;
+  }
+  nautyTime_ = rhs.nautyTime_;
+  nautyFixes_ = rhs.nautyFixes_;
+  nautyOtherBranches_ = rhs.nautyOtherBranches_;
+  nautyBranchCalls_ = rhs.nautyBranchCalls_;
+  lastNautyBranchSucceeded_ = rhs.lastNautyBranchSucceeded_;
+  nautyBranchSucceeded_ = rhs.nautyBranchSucceeded_;
+  nautyFixCalls_ = rhs.nautyFixCalls_;
+  lastNautyFixSucceeded_ = rhs.lastNautyFixSucceeded_;
+  nautyFixSucceeded_ = rhs.nautyFixSucceeded_;
 }
-
 // Assignment operator
 CbcSymmetry &
 CbcSymmetry::operator=(const CbcSymmetry &rhs)
@@ -755,13 +1638,38 @@ CbcSymmetry::operator=(const CbcSymmetry &rhs)
     node_info_ = rhs.node_info_;
     nauty_info_ = new CbcNauty(*rhs.nauty_info_);
     delete[] whichOrbit_;
+    if (numberPermutations_) {
+      for (int i=0;i<numberPermutations_;i++) {
+	delete [] permutations_[i].orbits;
+      }
+      delete [] permutations_;
+    }
     numberColumns_ = rhs.numberColumns_;
     numberUsefulOrbits_ = rhs.numberUsefulOrbits_;
     numberUsefulObjects_ = rhs.numberUsefulObjects_;
     if (rhs.whichOrbit_)
-      whichOrbit_ = CoinCopyOfArray(rhs.whichOrbit_, numberColumns_);
+      whichOrbit_ = CoinCopyOfArray(rhs.whichOrbit_, 5*numberColumns_);
     else
       whichOrbit_ = NULL;
+    numberPermutations_ = rhs.numberPermutations_;
+    if (numberPermutations_) {
+      permutations_ = CoinCopyOfArray(rhs.permutations_, numberPermutations_);
+      for (int i=0;i<numberPermutations_;i++) {
+	permutations_[i].orbits = CoinCopyOfArray(permutations_[i].orbits,
+						  numberColumns_);
+      }
+    } else {
+      permutations_ = NULL;
+    }
+    nautyTime_ = rhs.nautyTime_;
+    nautyFixes_ = rhs.nautyFixes_;
+    nautyOtherBranches_ = rhs.nautyOtherBranches_;
+    nautyBranchCalls_ = rhs.nautyBranchCalls_;
+    lastNautyBranchSucceeded_ = rhs.lastNautyBranchSucceeded_;
+    nautyBranchSucceeded_ = rhs.nautyBranchSucceeded_;
+    nautyFixCalls_ = rhs.nautyFixCalls_;
+    lastNautyFixSucceeded_ = rhs.lastNautyFixSucceeded_;
+    nautyFixSucceeded_ = rhs.nautyFixSucceeded_;
   }
   return *this;
 }
@@ -771,6 +1679,12 @@ CbcSymmetry::~CbcSymmetry()
 {
   delete nauty_info_;
   delete[] whichOrbit_;
+  if (numberPermutations_) {
+    for (int i=0;i<numberPermutations_;i++) {
+      delete [] permutations_[i].orbits;
+    }
+    delete [] permutations_;
+  }
 }
 
 CbcNauty::CbcNauty(int vertices, const size_t *v, const int *d, const int *e)
@@ -881,6 +1795,8 @@ CbcNauty::CbcNauty(int vertices, const size_t *v, const int *d, const int *e)
   vstat_ = new int[n_];
   clearPartitions();
   afp_ = NULL;
+  if (!n_)
+    stats_->errstatus=1; // deliberate error
 }
 
 CbcNauty::~CbcNauty()
@@ -1149,6 +2065,10 @@ void CbcNauty::computeAuto()
   // Need to make sure all generators are written
   if (afp_)
     fflush(afp_);
+  // make sure memory freed (was not on some failures)
+  nautil_freedyn();
+  nauty_freedyn();
+  nausparse_freedyn();
 }
 
 void CbcNauty::deleteElement(int ix, int jx)
@@ -1315,14 +2235,14 @@ CbcOrbitalBranchingObject::CbcOrbitalBranchingObject(CbcModel *model, int column
   int iOrbit = orbit[column];
   assert(iOrbit >= 0);
   int numberColumns = model->getNumCols();
-  numberOther_ = -1;
+  numberOther_=-1;
   for (int i = 0; i < numberColumns; i++) {
     if (orbit[i] == iOrbit)
       numberOther_++;
   }
   assert(numberOther_ > 0);
-  nautyBranchSucceeded_++;
-  nautyOtherBranches_ += numberOther_;
+  symmetryInfo->incrementBranchSucceeded();
+  symmetryInfo->incrementNautyBranches(numberOther_);
   numberExtra_ = numberExtra;
   fixToZero_ = new int[numberOther_ + numberExtra_];
   int n = 0;
@@ -1335,6 +2255,24 @@ CbcOrbitalBranchingObject::CbcOrbitalBranchingObject(CbcModel *model, int column
   }
 }
 
+// Useful constructor
+CbcOrbitalBranchingObject::CbcOrbitalBranchingObject(CbcModel *model,
+						     int column,
+						     int nFixed)
+  : CbcBranchingObject(model, -1, 1, 0.5)
+  , column_(column)
+  , numberOther_(nFixed)
+  , numberExtra_(0)
+  , fixToZero_(NULL)
+{
+  CbcSymmetry *symmetryInfo = model->rootSymmetryInfo();
+  assert(symmetryInfo);
+  symmetryInfo->incrementBranchSucceeded();
+  
+  fixToZero_ = CoinCopyOfArray(model->rootSymmetryInfo()->fixedToZero(),
+			       nFixed);
+}
+
 // Copy constructor
 CbcOrbitalBranchingObject::CbcOrbitalBranchingObject(const CbcOrbitalBranchingObject &rhs)
   : CbcBranchingObject(rhs)
@@ -1462,6 +2400,3 @@ CbcOrbitalBranchingObject::compareBranchingObject(const CbcBranchingObject *brOb
   return CbcRangeDisjoint;
 }
 #endif
-
-/* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
-*/
diff --git a/Cbc/src/CbcSymmetry.hpp b/Cbc/src/CbcSymmetry.hpp
index 2eae482..496a2b9 100644
--- a/Cbc/src/CbcSymmetry.hpp
+++ b/Cbc/src/CbcSymmetry.hpp
@@ -24,21 +24,21 @@
 
   To use it is -orbit on
 
-  Nauty has this -
-*   Permission 
-*   is hereby given for use and/or distribution with the exception of        *
-*   sale for profit or application with nontrivial military significance.    *
-  so you can use it internally even if you are a company.
  */
 #ifndef CBC_SYMMETRY_HPP
 #define CBC_SYMMETRY_HPP
+
+#include "CbcConfig.h"
+
+#ifdef COIN_HAS_NTY
 extern "C" {
-#include "nauty.h"
-#include "nausparse.h"
+#include "nauty/nauty.h"
+#include "nauty/nausparse.h"
 #ifdef NTY_TRACES
-#include "traces.h"
+#include "nauty/traces.h"
 #endif
 }
+#endif
 
 #include <vector>
 #include <map>
@@ -49,9 +49,14 @@ extern "C" {
 class OsiObject;
 // when to give up (depth since last success)
 #ifndef NTY_BAD_DEPTH
-#define NTY_BAD_DEPTH 10
+#define NTY_BAD_DEPTH 4
 #endif
 class CbcNauty;
+typedef struct {
+  int numberInPerm;
+  int numberPerms;
+  int * orbits;
+} cbc_permute;
 
 #define COUENNE_HACKED_EPS 1.e-07
 #define COUENNE_HACKED_EPS_SYMM 1e-8
@@ -138,14 +143,20 @@ public:
   void Compute_Symmetry() const;
   int statsOrbits(CbcModel *model, int type) const;
   //double timeNauty () const;
-  void Print_Orbits() const;
+  void Print_Orbits(int type=0) const;
   void fillOrbits();
   /// Fixes variables using orbits (returns number fixed)
   int orbitalFixing(OsiSolverInterface *solver);
+  /// Fixes variables using root orbits (returns number fixed)
+  int orbitalFixing2(OsiSolverInterface *solver);
   inline int *whichOrbit()
   {
     return numberUsefulOrbits_ ? whichOrbit_ : NULL;
   }
+  inline int *fixedToZero() const
+  {
+    return whichOrbit_+4*numberColumns_;
+  }
   inline int numberUsefulOrbits() const
   {
     return numberUsefulOrbits_;
@@ -157,6 +168,24 @@ public:
   int largestOrbit(const double *lower, const double *upper) const;
   void ChangeBounds(const double *lower, const double *upper,
     int numberColumns, bool justFixedAtOne) const;
+  /** for simple stuff - returns number can fix if can use saved orbit (mode 1)
+      otherwise may fix and return number can fix (mode 0) */
+  int changeBounds(int kColumn, double * saveLower,
+		    double * saveUpper,
+		    OsiSolverInterface * solver,int mode) const;
+  int changeBounds(double *saveLower, double *saveUpper,
+		   OsiSolverInterface * solver) const;
+  int changeBounds2(double *saveLower, double *saveUpper,
+		   OsiSolverInterface * solver) const;
+  int fixSome(int iColumn, double *columnLower, double *columnUpper) const;
+  /// return number of orbits if worth branching
+  int worthBranching(const double *saveLower, const double *saveUpper,
+		     int iColumn, int & numberCouldFix) const;
+  void fixSuccess(int nFixed);
+  /// Adjust statistics from threads
+  void adjustStats(const CbcSymmetry * other);
+  inline int numberColumns() const
+  { return numberColumns_;}
   inline bool compare(register Node &a, register Node &b) const;
   CbcNauty *getNtyInfo() { return nauty_info_; }
 
@@ -166,13 +195,39 @@ public:
   /// empty if no NTY, symmetry data structure setup otherwise
   void setupSymmetry(CbcModel * model);
 
+  /// takes ownership of cbc_permute (orbits part)
+  void addPermutation(cbc_permute permutation);
+  /// Number of permutation arrays
+  inline int numberPermutations() const
+  { return numberPermutations_;}
+  /// Permutation arrays
+  inline int * permutation(int which) const
+  { return permutations_[which].orbits;}
+  inline int numberInPermutation(int which) const
+  { return permutations_[which].numberInPerm;}
+  inline void incrementNautyBranches(int n)
+  { nautyOtherBranches_ += n;}
+  inline void incrementBranchSucceeded()
+  { nautyBranchSucceeded_ ++;}
 private:
   mutable std::vector< Node > node_info_;
   mutable CbcNauty *nauty_info_;
   int numberColumns_;
   int numberUsefulOrbits_;
   int numberUsefulObjects_;
+  int numberPermutations_;
+  cbc_permute * permutations_;
   int *whichOrbit_;
+  int stats_[5];
+  double nautyTime_;
+  double nautyFixes_;
+  mutable double nautyOtherBranches_;
+  mutable int nautyBranchCalls_;
+  mutable int lastNautyBranchSucceeded_;
+  int nautyBranchSucceeded_;
+  mutable int nautyFixCalls_;
+  mutable int lastNautyFixSucceeded_;
+  int nautyFixSucceeded_;
 };
 
 class CbcNauty {
@@ -309,6 +364,8 @@ public:
   CbcOrbitalBranchingObject(CbcModel *model, int column,
     int way,
     int numberExtra, const int *extraToZero);
+  // Useful constructor (uses stored list)
+  CbcOrbitalBranchingObject(CbcModel *model, int column, int nFixed);
 
   // Copy constructor
   CbcOrbitalBranchingObject(const CbcOrbitalBranchingObject &);
@@ -379,8 +436,5 @@ private:
   /// Fix to zero
   int *fixToZero_;
 };
-
+//#define PRINT_CBCAUTO
 #endif
-
-/* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
-*/
diff --git a/Cbc/src/CbcThread.cpp b/Cbc/src/CbcThread.cpp
index 5bdffa0..61eb5f0 100644
--- a/Cbc/src/CbcThread.cpp
+++ b/Cbc/src/CbcThread.cpp
@@ -243,7 +243,10 @@ void CbcSpecificThread::setStatus(int value)
 #else
 #endif
 }
-// Parallel heuristics
+// Parallel heuristics, used in CbcModel.cpp
+void parallelHeuristics(int numberThreads,
+  int sizeOfData,
+  void *argBundle);
 void parallelHeuristics(int numberThreads,
   int sizeOfData,
   void *argBundle)
diff --git a/Cbc/src/config_cbc_default.h b/Cbc/src/config_cbc_default.h
index 976807d..b949da1 100644
--- a/Cbc/src/config_cbc_default.h
+++ b/Cbc/src/config_cbc_default.h
@@ -5,7 +5,7 @@
 /***************************************************************************/
 
 /* Version number of project */
-#define CBC_VERSION "2.10.8"
+#define CBC_VERSION "2.10.10"
 
 /* Major Version number of project */
 #define CBC_VERSION_MAJOR 2
@@ -14,7 +14,7 @@
 #define CBC_VERSION_MINOR 10
 
 /* Release Version number of project */
-#define CBC_VERSION_RELEASE 8
+#define CBC_VERSION_RELEASE 10
 
 /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
 */
diff --git a/Cbc/src/unitTestClp.cpp b/Cbc/src/unitTestClp.cpp
index 1379a1e..8e05102 100644
--- a/Cbc/src/unitTestClp.cpp
+++ b/Cbc/src/unitTestClp.cpp
@@ -337,6 +337,7 @@ int CbcClpUnitTest(const CbcModel &saveModel, const std::string &dirMiplib,
 */
     CbcModel *model = NULL;
     std::string fn = dirMiplib + mpsName[m];
+    //std::string fn = "/tmp/" + mpsName[m] + "_max.mps";
     if (!CbcTestMpsFile(fn)) {
       std::cout << "ERROR: Cannot find MPS file " << fn << "." << std::endl;
       continue;
@@ -368,9 +369,16 @@ int CbcClpUnitTest(const CbcModel &saveModel, const std::string &dirMiplib,
 
       CbcMain1(newArgc, newArgv, *model, callBack, parameterData);
     }
-
-    assert(model->getNumRows() == nRows[m]);
-    assert(model->getNumCols() == nCols[m]);
+    // warn if sizes do not match
+    if ((model->getNumRows() != nRows[m] ||
+	 model->getNumCols() != nCols[m]) && model->getNumRows()) {
+      printf("WARNING - model has %d row, %d columns - expected %d, %d\n",
+	     model->getNumRows(),model->getNumCols(),
+	     nRows[m],nCols[m]);
+      fprintf(stderr, "WARNING - model has %d row, %d columns - expected %d, %d\n",
+	     model->getNumRows(),model->getNumCols(),
+	     nRows[m],nCols[m]);
+    }
 
     if (oldStyle) {
 
diff --git a/README.md b/README.md
index 55ff5f0..710e892 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
-# Cbc 2.10.8
+# Cbc 2.10.10
 
 [![A COIN-OR Project](https://coin-or.github.io/coin-or-badge.png)](https://www.coin-or.org)
 
 Projects such as this one are maintained by a small group of volunteers under
 the auspices of the non-profit [COIN-OR Foundation](https://www.coin-or.org)
 and we need your help! Please consider [sponsoring our
-activities](https://github.com/sponsors/coin-or).
+activities](https://github.com/sponsors/coin-or) or [volunteering](mailto:volunteer@coin-or.org) to help!
 
 [![Latest Release](https://img.shields.io/github/v/release/coin-or/Cbc?sort=semver)](https://github.com/coin-or/Cbc/releases)
 
@@ -70,9 +70,9 @@ Code: [![DOI](https://zenodo.org/badge/173509563.svg)](https://zenodo.org/badge/
 
 ## CURRENT BUILD STATUS
 
-[![Windows Builds](https://github.com/coin-or/Cbc/actions/workflows/windows-ci.yml/badge.svg?branch=releases/2.10.8)](https://github.com/coin-or/Cbc/actions/workflows/windows-ci.yml?query=branch%3Areleases/2.10.8)
+[![Windows Builds](https://github.com/coin-or/Cbc/actions/workflows/windows-ci.yml/badge.svg?branch=releases/2.10.10)](https://github.com/coin-or/Cbc/actions/workflows/windows-ci.yml?query=branch%3Areleases/2.10.10)
 
-[![Linux and MacOS Builds](https://github.com/coin-or/Cbc/actions/workflows/linux-ci.yml/badge.svg?branch=releases/2.10.8)](https://github.com/coin-or/Cbc/actions/workflows/linux-ci.yml?query=branch%3Areleases/2.10.8)
+[![Linux and MacOS Builds](https://github.com/coin-or/Cbc/actions/workflows/linux-ci.yml/badge.svg?branch=releases/2.10.10)](https://github.com/coin-or/Cbc/actions/workflows/linux-ci.yml?query=branch%3Areleases/2.10.10)
 
 ## DOWNLOAD
 
@@ -163,7 +163,7 @@ following on the command line.
 ```
 wget https://raw.githubusercontent.com/coin-or/coinbrew/master/coinbrew
 chmod u+x coinbrew
-./coinbrew fetch Cbc@2.10.8
+./coinbrew fetch Cbc@2.10.10
 ./coinbrew build Cbc
 ```
 For more detailed instructions on coinbrew, see https://coin-or.github.io/coinbrew.
@@ -241,7 +241,7 @@ If you have `Doxygen` available, you can build a HTML documentation by typing
 `make doxygen-docs` 
 
 in the build directory. If Cbc was built via `coinbrew`, then the build
-directory will be `./build/Cbc/2.10.8` by default. The doxygen documentation main file
+directory will be `./build/Cbc/2.10.10` by default. The doxygen documentation main file
 is found at `<build-dir>/doxydoc/html/index.html`.
 
 If you don't have `doxygen` installed locally, you can use also find the
@@ -323,6 +323,13 @@ documentation [here](http://coin-or.github.io/Cbc/Doxygen).
           - `oddwext`: strategy used to search for wheel centers for the cuts found by CglOddWheel - 0=off, 1=one variable, 2=clique - default=2.
       - CglClique was replaced by CglBKClique as the default clique separator in CbcSolver.cpp.
 
+ * Release 2.10.10
+   * Fix for accidental introduction of private symbol into public header.
+
+ * Release 2.10.9
+   * Improvements to symmetry handling.
+   * Maintenance release to push out accumulates patches.
+
  * Release 2.10.8
    * Re-generate binaries due to mistake in Github Actions configuration and 
      incorporate new release of Cgl. 
diff --git a/configure b/configure
index 2a32fd0..a84f35c 100755
--- a/configure
+++ b/configure
@@ -1,7 +1,7 @@
 #! /bin/sh
 # From configure.ac 0.9.
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for Cbc 2.10.8.
+# Generated by GNU Autoconf 2.59 for Cbc 2.10.10.
 #
 # Report bugs to <cbc@lists.coin-or.org>.
 #
@@ -430,8 +430,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='Cbc'
 PACKAGE_TARNAME='cbc'
-PACKAGE_VERSION='2.10.8'
-PACKAGE_STRING='Cbc 2.10.8'
+PACKAGE_VERSION='2.10.10'
+PACKAGE_STRING='Cbc 2.10.10'
 PACKAGE_BUGREPORT='cbc@lists.coin-or.org'
 
 ac_unique_file="configure.ac"
@@ -1042,7 +1042,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures Cbc 2.10.8 to adapt to many kinds of systems.
+\`configure' configures Cbc 2.10.10 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1108,7 +1108,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Cbc 2.10.8:";;
+     short | recursive ) echo "Configuration of Cbc 2.10.10:";;
    esac
   cat <<\_ACEOF
 
@@ -1336,7 +1336,7 @@ fi
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-Cbc configure 2.10.8
+Cbc configure 2.10.10
 generated by GNU Autoconf 2.59
 
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1356,7 +1356,7 @@ cat >&5 <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by Cbc $as_me 2.10.8, which was
+It was created by Cbc $as_me 2.10.10, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   $ $0 $@
@@ -5113,7 +5113,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='cbc'
- VERSION='2.10.8'
+ VERSION='2.10.10'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -23559,7 +23559,7 @@ _ASBOX
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by Cbc $as_me 2.10.8, which was
+This file was extended by Cbc $as_me 2.10.10, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -23617,7 +23617,7 @@ _ACEOF
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-Cbc config.status 2.10.8
+Cbc config.status 2.10.10
 configured by $0, generated by GNU Autoconf 2.59,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 
diff --git a/configure.ac b/configure.ac
index 7f2b606..ee1e6a1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,7 +12,7 @@
 
 AC_PREREQ(2.59)
 
-AC_INIT([Cbc],[2.10.8],[cbc@lists.coin-or.org])
+AC_INIT([Cbc],[2.10.10],[cbc@lists.coin-or.org])
 
 AC_COPYRIGHT([
 Copyright 2006 International Business Machines and others.
diff --git a/debian/changelog b/debian/changelog
index dc3874b..9c42329 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+coinor-cbc (2.10.10+ds1-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 19 Jun 2023 23:12:59 -0000
+
 coinor-cbc (2.10.8+ds1-1) unstable; urgency=medium
 
   * New upstream release.
diff --git a/debian/patches/find_Makefile_includes.patch b/debian/patches/find_Makefile_includes.patch
index 88a7831..8cd4ba2 100644
--- a/debian/patches/find_Makefile_includes.patch
+++ b/debian/patches/find_Makefile_includes.patch
@@ -2,9 +2,11 @@ Description: let Cbc/'s Makefile.* find their includes
 Author: Julien Puydt
 Forwarded: Debian-specific
 
---- coinor-cbc.orig/Cbc/Makefile.am
-+++ coinor-cbc/Cbc/Makefile.am
-@@ -158,4 +158,4 @@
+Index: coinor-cbc.git/Cbc/Makefile.am
+===================================================================
+--- coinor-cbc.git.orig/Cbc/Makefile.am
++++ coinor-cbc.git/Cbc/Makefile.am
+@@ -158,4 +158,4 @@ CLEANFILES =
  # Files that are generated and should be cleaned with make distclean
  DISTCLEANFILES =
  

More details

Full run details

Historical runs