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 ¶meterData)
{
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 =