text:
#include "PhotonSystematic/ReadMxAOD.h"
#include "PlotFunctions/Foncteurs.h"
#include "PlotFunctions/MapBranches.h"
#include "PlotFunctions/SideFunctions.h"

#include "TKey.h"
#include "TIterator.h"
#include "TFile.h"
#include "TTree.h"
#include "xAODRootAccess/TEvent.h"
#include "xAODEventInfo/EventInfo.h"
#include "TCanvas.h"
#include "RooPlot.h"
#include "RooGaussian.h"
#include "RooDataSet.h"
#include "RooRealVar.h"
#include "RooArgSet.h"
#include "xAODRootAccess/Init.h"

#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <sstream>
#include <map>
#include <iterator>
#include <algorithm>
#include <functional>
#include <ostream>
#include <iostream>
#include <vector>
#include <utility>
#include <stdexcept>
#include <string>
#include <fstream>
#include <math.h>
#include <chrono>

using namespace std;
using namespace std::chrono;
using namespace ChrisLib;

//#################
int ReadMxAOD( const vector<string> &rootFilesName, string outDirectory, const string &inConfFileName, int debug ) {
  vector<string> commonVarsName;
  vector<string> containersName;
  //  string outDirectory;
  po::options_description desc("LikelihoodProfiel Usage");
  //define all options in the program
  desc.add_options()
    ( "help", "Display this help message")
    //    ( "rootFileName", po::value<vector<string>>( &rootFilesName )->multitoken(), "Input ROOT MxAOD files" )
    ( "containerName", po::value<vector<string>>( &containersName )->multitoken(), "Names of the containers to copy" )
    ( "commonVarName", po::value<vector<string>>( &commonVarsName )->multitoken(), "Names of the variables in containers to copy" )
    //    ( "outDirectory", po::value<string>( &outDirectory ), "Name of the outputDirectory : File names will be generated automatically" )
    ;

  // create a map vm that contains options and all arguments of options
  po::variables_map vm;
  std::ifstream ifs( inConfFileName, std::ifstream::in );
  po::store(po::parse_config_file(ifs, desc), vm);
  po::notify(vm);

  if (vm.count("help")) {cout << desc; return 0;}
  //=============================================
  if ( !xAOD::Init().isSuccess() ) throw runtime_error( "xAOD Init Failed" );

  bool isOutputDirectory = ( outDirectory.substr(outDirectory.find_last_of( "." )) == ".root" );
  cout << "isOutputDirectory : " << isOutputDirectory << endl;
  if ( !isOutputDirectory && outDirectory.back() != '/' ) outDirectory+="/";

  ReplaceString repStr("HGamEventInfo_");
  /*Create the names of all the required branches
    For the input variables one must combine the name of the container with the name of the variables of interest
    For the output variables, the common variables have no prefix and the rest have the container name minus the HGamEventInfo_ prefix
  */
  const list<string> varsName = GetAnalysisVariables();

  sort( commonVarsName.begin(), commonVarsName.end() );

  list<string> unCommonVarsName;
  set_difference( varsName.begin(), varsName.end(), commonVarsName.begin(), commonVarsName.end(), back_inserter(unCommonVarsName) );

  //Stores the prefix output for a given container
  map<string,string> branchMatching;
  for ( auto itName = containersName.begin(); itName!=containersName.end(); ++itName )
    branchMatching[*itName] = repStr(*itName);

  list<list<string>> inCombineNames( 1, list<string>() );
  copy( containersName.begin(), containersName.end(), back_inserter( *inCombineNames.begin() ) );
  inCombineNames.push_back( unCommonVarsName );

  list<string> outBranchesName;
  CombineNames( inCombineNames, outBranchesName );
  outBranchesName.insert( outBranchesName.begin(), commonVarsName.begin(), commonVarsName.end() );
  transform( outBranchesName.begin(), outBranchesName.end(), outBranchesName.begin(), repStr );

  //Container with all names of variables of interest
  //In case of debug, look all variable which values remain the same in all systematic fluctuations

  list<string> duplicateVarsName;
  copy( varsName.begin(), varsName.end(), back_inserter(duplicateVarsName) );
  duplicateVarsName.insert( duplicateVarsName.end(), commonVarsName.begin(), commonVarsName.end() );
  duplicateVarsName.sort();
  duplicateVarsName.erase( unique( duplicateVarsName.begin(), duplicateVarsName.end() ), duplicateVarsName.end() );

  vector<string> allVarsName;
  copy( duplicateVarsName.begin(), duplicateVarsName.end(), back_inserter(allVarsName) );

  //Setting m_yy as first variable for optimization
  vector<string>::iterator mGamPos = find( allVarsName.begin(), allVarsName.end(), "m_yy" );
  swap( *mGamPos, *allVarsName.begin() );

  map<string,double> defaultVarValues;
  defaultVarValues["catCoup"]=-1;
  defaultVarValues["catXS"]=-1;
  defaultVarValues["catXSPhi"]=-1;

  map<string, double> mapVal;
  const list<string> processes = GetAnalysisProcesses();

  double lumiWeight=1e4;//Normalize total events to 10fb-1
  //  lumiWeight=1e3;
  //GetThe weights for the datasets
  map<string, double> mapDatasetWeights;

  //Retrieve the total sum of weight of a given generated process for reweighting
  TotalSumWeights( rootFilesName, mapDatasetWeights );

  int totEntry = 0;
  int nFile=0;
  TTree *outTree = 0;
  map<string, const xAOD::EventInfo* > mapEvent;
  double datasetWeight = 1;

  for ( vector<string>::const_iterator itFileName = rootFilesName.begin(); itFileName != rootFilesName.end(); ++itFileName ) {
    cout << *itFileName << endl;

    //Check the process to which this MC contributes. The process should be in the name
    string process = FindProcessName( *itFileName );

    TFile *inFile = new TFile( itFileName->c_str() );

    //Initialize the reading of the xAOD
    xAOD::TEvent* tevent = new xAOD::TEvent(xAOD::TEvent::kClassAccess);
    if ( !tevent->readFrom( inFile ).isSuccess() ) throw runtime_error( "xAOD readFrom failed : " + string(inFile->GetName() ) );

    datasetWeight = mapDatasetWeights[process];
    //A bug have been found in the cross section tHjb.
    if ( process == "tHjb" && itFileName->find("h013") != string::npos ) {
      datasetWeight/=10.;
      cout << "correcting tHjb" << endl;
    }

    //Loop on all events of the TFile
    int nentries = tevent->getEntries();
    if ( debug == 2 ) nentries = 100;
    for (int i_event = 0 ; i_event < nentries ; i_event++) {
      //      high_resolution_clock::time_point t1 = high_resolution_clock::now();

      if ( !outTree ) {
  	outTree = new TTree( "outTree", "outTree" );
  	outTree->SetDirectory(0);
  	for ( auto itVarName = outBranchesName.begin(); itVarName!=outBranchesName.end(); ++itVarName ) {
	  mapVal[*itVarName] = -99;
	  outTree->Branch(itVarName->c_str(), &mapVal[*itVarName] );
	}
      }

      //Reinitialize common variables to -99
      for ( auto it = commonVarsName.begin(); it!=commonVarsName.end(); ++it ) mapVal[*it] = -99;

      if ( totEntry % 100000 == 0 )  cout << "totEntry : " << totEntry << endl;
      tevent->getEntry( i_event );

      //Them pt of the Higgs must be recomputed with jet multiplicity
      string truthName = "HGamTruthEventInfo";
      if ( !tevent->retrieve( mapEvent[truthName], truthName.c_str() ).isSuccess() ) throw runtime_error( "xAOD retrieve failed : " + truthName );
      double ptWeight=( mapEvent[truthName]->auxdata<int>( "N_j" ) < 2 && itFileName->find("ggH")!=string::npos ) ? ReweightPtGgh( mapEvent[truthName]->auxdata<float>( "pT_yy" )/1e3 ): 1;

      map<string,double> valVarsConstCheck;
      bool keepEvent = false;
      for ( auto itName = containersName.begin(); itName != containersName.end(); ++itName ) {
	const xAOD::EventInfo* currentEventInfo = mapEvent[*itName];

  	if ( !tevent->retrieve( currentEventInfo, itName->c_str() ).isSuccess() ) throw runtime_error( "xAOD retrieve failed : " + *itName );
	double commonWeight = ptWeight*lumiWeight/datasetWeight;

	list<string> outName;

	//nominal case with empty container name
	if ( *itName == repStr( *itName ) ) copy( allVarsName.begin(), allVarsName.end(), back_inserter(outName) );
	else {
	  Prefix outPrefix( repStr( *itName )+"_" );
	  transform( allVarsName.begin(), allVarsName.end(), back_inserter(outName), outPrefix );
	}

	bool isGoodEvent=true;
	for ( auto itBranch = outName.begin(); itBranch!=outName.end(); ++itBranch ) {

	  if ( !isGoodEvent ) {
	    mapVal[*itBranch] = -99;
	  }
	  else {
	    bool isCommon = find( commonVarsName.begin(), commonVarsName.end(), ExtractVariable(*itBranch) ) != commonVarsName.end();
	    bool fillMapAnswer = FillMapFromEventInfo( *itBranch, mapVal, currentEventInfo, commonWeight, isCommon );
	    keepEvent = fillMapAnswer || keepEvent;
	    if ( itBranch->find( "m_yy" ) != string::npos && mapVal[*itBranch] < 0 ) isGoodEvent = false;
	  }
	}

      }//end vName

      if ( keepEvent ) {
  	outTree->Fill();
	totEntry++;
      }

      // high_resolution_clock::time_point t2 = high_resolution_clock::now();
      // auto duration = duration_cast<microseconds>( t2 - t1 ).count();
      // if (totEntry==1) cout << "keptEventTime : " << duration << endl;

      if ( debug==1 ) UpdateDuplicateList( duplicateVarsName, mapVal, defaultVarValues );
      if ( ( totEntry%30000==0 && outTree->GetEntries() ) || ( itFileName == --rootFilesName.end() && i_event==nentries-1 ) ) {
  	string dumName = isOutputDirectory ? outDirectory : outDirectory + process + "_" + to_string(nFile) + ".root";
  	cout << "saving : " << dumName << endl;
  	cout << "entries : " << outTree->GetEntries() << endl;
  	TFile *dumFile = new TFile( dumName.c_str(), "recreate" );
  	outTree->Write();
  	dumFile->Close();
  	delete dumFile;
  	delete outTree;
  	outTree=0;
  	nFile++;
      }
    }//end _i_event

  }

  if ( debug ) {
    cout << "Degenerated variables : " << endl;
    copy( duplicateVarsName.begin(), duplicateVarsName.end(), ostream_iterator<string>( cout, "\n" ) );
  }

  return 0;
}
//######################################################
double ReweightPtGgh( double const initPt ) {
  	if (initPt<20) return 1.11;
	if (initPt<45) return 1.11 - (initPt-20)/25*0.2; // -> 0.91
  	if (initPt<135) return 0.91 - (initPt-45)/90*0.36; // -> 0.55
  	return 0.55;

}
//######################################################
string FindNoDalitzHist( const TFile *inFile ) {
  if ( !inFile ) throw domain_error( "FindNoDalitzHist : Null *inFile " );
  string histName = "";
  TIter nextkey( inFile->GetListOfKeys());
  TKey *key=0;
  while ((key = (TKey*)nextkey())) {
    if (strcmp( "TH1F", key->GetClassName())) continue;
    string dumHistName = key->GetName();
    if ( dumHistName.find( "noDalitz_weighted" ) == string::npos ) continue;
    histName = dumHistName;
  }

  if ( histName == "" ) throw domain_error( "FindNoDalitzHist : No noDalitz_weighted histogram in "+ string(inFile->GetName()) );

  return histName;
}

//######################################################
bool FillMapFromEventInfo( const string &outName,
			   map<string,double> &mapVal,
			   const xAOD::EventInfo* eventInfo,
			   double commonWeight,
			   bool isCommon
			   ) {

  string varName = ExtractVariable( outName );

  //For general case, the variable does not give an information on the selection cut so in case of a OR return 0.
  //Only weight varaibles can eventually return true;
  bool keepEvent = 0;
  double currentVal = -99;

  if ( varName == "weightXS" ) //currentVal = static_cast<bool>(eventInfo->auxdata< char >( "isPassed" ))*eventInfo->auxdata<float>( "weight" )*eventInfo->auxdata<float>( "crossSectionBRfilterEff" )*commonWeight;
    currentVal = eventInfo->auxdata<float>( "weight" )*eventInfo->auxdata<float>( "crossSectionBRfilterEff" )*commonWeight;
  else if ( varName == "weight" ) {
    //    currentVal = static_cast<bool>( eventInfo->auxdata< char >( "isPassed" ))*eventInfo->auxdata<float>( "weightCatCoup_dev" )*eventInfo->auxdata<float>( "crossSectionBRfilterEff" )*commonWeight;
    currentVal = eventInfo->auxdata<float>( "weightCatCoup_dev" )*eventInfo->auxdata<float>( "crossSectionBRfilterEff" )*commonWeight;
  }
  else if ( varName == "m_yy" ) currentVal = eventInfo->auxdata<float>( "m_yy" );
  else if ( varName == "catCoup" ) {
    currentVal = eventInfo->auxdata<int>( "catCoup_dev" );
    if ( currentVal == -1 ) currentVal = -99;
  }
  else if ( varName == "pt_yy" ) currentVal = eventInfo->auxdata<float>( "pT_yy" );
  else if ( varName == "DPhi_yy" ) currentVal = eventInfo->auxdata<float>( "Dphi_yy" );
  else if ( varName == "catXS" ) {
    currentVal = eventInfo->auxdata<float>( "pT_yy" )/1e3;//in GeV
    const vector<double> XSCatPt = GetPtCategXS();
    unsigned int ptCat = 0;
    while ( XSCatPt[ptCat]<currentVal ) ++ptCat;
    if ( ptCat ) currentVal = ptCat;
    else currentVal = -99;
  }
  else if ( varName == "catXSPhi" ) {
    currentVal = eventInfo->auxdata<float>( "Dphi_yy" );
    const vector<double> XSCatPhi = GetPhiCategXS();
    unsigned int XSCat=0;
    while ( currentVal> XSCatPhi[XSCat] ) ++XSCat;
    if ( XSCat ) currentVal = XSCat;
    else currentVal=-99;
  }

  if ( currentVal != -99 && ( varName == "m_yy" || varName == "pt_yy" ) ) currentVal /=1e3;//Switch energies to GeV

  if ( !(isCommon && currentVal == -99) ) {
    //    if ( currentVal!= -99 && currentVal != 0 ) cout << "filling :" << outName << " " << currentVal << endl;
    mapVal[outName] = currentVal;
  }

  //  if ( varName.find( "weight" ) != string::npos ) cout << outName << " " << currentVal << endl;
  // if ( varName.find( "weight" ) != string::npos && currentVal!=0 ) keepEvent=1;
  if ( varName.find( "m_yy" ) != string::npos && currentVal>0 ) keepEvent=1;
//     if ( varName.find("weight")!=string::npos )  cout << outName << " " << isCommon << " " << currentVal << endl;
  return keepEvent;
}

//######################################################
void UpdateDuplicateList( list<string> &duplicateListName,  const map<string, double> &mapVal, const map<string,double> &defaultValues ) {

  map<string,double> checkVarVal;

  for ( map<string, double>::const_iterator itMapVal = mapVal.begin(); itMapVal != mapVal.end(); ++itMapVal ) {
    if ( itMapVal->second == -99 ) continue;

    string varName = ExtractVariable( itMapVal->first );

    list<string>::iterator posVar = find( duplicateListName.begin(), duplicateListName.end(), varName);
    if ( posVar == duplicateListName.end() ) continue;

    map<string,double>::const_iterator defaultValue = defaultValues.find(varName);
    if ( defaultValue != defaultValues.end() && fabs( itMapVal->second - defaultValue->second )/itMapVal->second < 1e-10 ) continue;
    map<string,double>::iterator posVarCheck = checkVarVal.find(varName);
    if ( posVarCheck != checkVarVal.end() && fabs( itMapVal->second - posVarCheck->second )/itMapVal->second > 1e-10 ) {
      cout << "removing non-duplicate variables : " << *posVar << endl;
      duplicateListName.erase( posVar );
    }
    else if ( posVarCheck == checkVarVal.end() ) checkVarVal[varName] = itMapVal->second;

  }//end for itMapVal

}

//######################################################
void TotalSumWeights( const vector<string> &rootFilesName, map<string,double> &datasetWeights ) {
  //Retrieve the total sum of weight of a given generated process for reweighting
  const list<string> processes = { "ggH", "VBF", "WH", "ZH", "ttH", "bbH125_yb2", "bbH125_ybyt", "tWH", "tHjb" };
  for ( vector<string>::const_iterator vFile = rootFilesName.begin(); vFile!=rootFilesName.end(); ++vFile ) {
    TFile *dumInFile = new TFile( vFile->c_str() );
    if ( !dumInFile ) throw domain_error( "ToTalSumWeights : inFile does not exist " + *vFile );

    string histName = FindNoDalitzHist( dumInFile );

    TH1F* hist = (TH1F*) dumInFile->Get( histName.c_str() );

    for ( list<string>::const_iterator vProc = processes.begin(); vProc!=processes.end(); ++vProc ) {
      if ( vFile->find( *vProc ) == string::npos ) continue;
      datasetWeights[*vProc]+=hist->GetBinContent(3);
      break;
    }
    delete dumInFile;
  }
}

//######################################################
string ExtractVariable( const string &inName ) {
  size_t separatorPos = inName.find_last_of( "_" );
  string branchName = inName.substr( 0, separatorPos );
  string varName = inName.substr( separatorPos+1 );
  if ( varName == "yy" ) {
    separatorPos = branchName.find_last_of( "_" );
    varName = inName.substr( separatorPos+1 );
  }
  return varName;
}

//#######################################################
string FindProcessName( const string &inFileName ) {
  list<string> foundProcesses;
  list<string> processes = GetAnalysisProcesses();
  for ( auto it = processes.begin(); it != processes.end(); ++it )
    if ( inFileName.find( *it ) != string::npos ) foundProcesses.push_back( *it );

  if ( foundProcesses.empty() ) throw runtime_error( "FindProcessInName : No process found in " + inFileName );
  if ( ++foundProcesses.begin() != foundProcesses.end() ) throw runtime_error( "FindProcessInName : Too many processes found in " + inFileName );
  return *foundProcesses.begin();
}

//######################################################

ext: cxx

max_stars_repo_name: cgoudet/PhotonSystematic

max_issues_repo_name: cgoudet/PhotonSystematic

max_forks_repo_name: cgoudet/PhotonSystematic


text:
#include <Access/RowPolicy.h>
#include <Interpreters/Context.h>
#include <Common/quoteString.h>
#include <boost/range/algorithm/equal.hpp>

namespace DB
{
namespace
{
    void generateFullNameImpl(const String & database_, const String & table_name_, const String & policy_name_, String & full_name_)
    {
        full_name_.clear();
        full_name_.reserve(database_.length() + table_name_.length() + policy_name_.length() + 6);
        full_name_ += backQuoteIfNeed(policy_name_);
        full_name_ += " ON ";
        if (!database_.empty())
        {
            full_name_ += backQuoteIfNeed(database_);
            full_name_ += '.';
        }
        full_name_ += backQuoteIfNeed(table_name_);
    }
}

String RowPolicy::FullNameParts::getFullName() const
{
    String full_name;
    generateFullNameImpl(database, table_name, policy_name, full_name);
    return full_name;
}

String RowPolicy::FullNameParts::getFullName(const Context & context) const
{
    String full_name;
    generateFullNameImpl(database.empty() ? context.getCurrentDatabase() : database, table_name, policy_name, full_name);
    return full_name;
}

void RowPolicy::setDatabase(const String & database_)
{
    database = database_;
    generateFullNameImpl(database, table_name, policy_name, full_name);
}

void RowPolicy::setTableName(const String & table_name_)
{
    table_name = table_name_;
    generateFullNameImpl(database, table_name, policy_name, full_name);
}

void RowPolicy::setName(const String & policy_name_)
{
    policy_name = policy_name_;
    generateFullNameImpl(database, table_name, policy_name, full_name);
}

void RowPolicy::setFullName(const String & database_, const String & table_name_, const String & policy_name_)
{
    database = database_;
    table_name = table_name_;
    policy_name = policy_name_;
    generateFullNameImpl(database, table_name, policy_name, full_name);
}

bool RowPolicy::equal(const IAccessEntity & other) const
{
    if (!IAccessEntity::equal(other))
        return false;
    const auto & other_policy = typeid_cast<const RowPolicy &>(other);
    return (database == other_policy.database) && (table_name == other_policy.table_name) && (policy_name == other_policy.policy_name)
        && boost::range::equal(conditions, other_policy.conditions) && restrictive == other_policy.restrictive
        && (roles == other_policy.roles);
}

const char * RowPolicy::conditionIndexToString(ConditionIndex index)
{
    switch (index)
    {
        case SELECT_FILTER: return "SELECT_FILTER";
        case INSERT_CHECK: return "INSERT_CHECK";
        case UPDATE_FILTER: return "UPDATE_FILTER";
        case UPDATE_CHECK: return "UPDATE_CHECK";
        case DELETE_FILTER: return "DELETE_FILTER";
    }
    __builtin_unreachable();
}

const char * RowPolicy::conditionIndexToColumnName(ConditionIndex index)
{
    switch (index)
    {
        case SELECT_FILTER: return "select_filter";
        case INSERT_CHECK: return "insert_check";
        case UPDATE_FILTER: return "update_filter";
        case UPDATE_CHECK: return "update_check";
        case DELETE_FILTER: return "delete_filter";
    }
    __builtin_unreachable();
}

}

ext: cpp

max_stars_repo_name: rodrigargar/ClickHouse

max_issues_repo_name: rodrigargar/ClickHouse

max_forks_repo_name: rodrigargar/ClickHouse


text:
/*  Sirikata Transfer
 *  DiskManager.cpp
 *
 *  Copyright (c) 2010, Jeff Terrace
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sirikata/core/transfer/DiskManager.hpp>
#include <boost/filesystem/fstream.hpp>

AUTO_SINGLETON_INSTANCE(Sirikata::Transfer::DiskManager);

namespace Sirikata {
namespace Transfer {

DiskManager& DiskManager::getSingleton() {
    return AutoSingleton<DiskManager>::getSingleton();
}
void DiskManager::destroy() {
    AutoSingleton<DiskManager>::destroy();
}

DiskManager::ScanRequest::ScanRequest(Filesystem::Path path, DiskManager::ScanRequest::ScanRequestCallback cb)
    : mCb(cb), mPath(path) {
}

void DiskManager::ScanRequest::execute() {
    std::tr1::shared_ptr<DirectoryListing> badResult;
    std::tr1::shared_ptr<DirectoryListing> dirListing(new DirectoryListing());

    if(!fs::exists(mPath)) {
        mCb(badResult);
        return;
    }

    for(fs::directory_iterator it(mPath); it != fs::directory_iterator(); it++) {
        Filesystem::PathInfo pi(it->path(), it->status());
        dirListing->push_back(pi);
    }

    mCb(dirListing);
}

DiskManager::ReadRequest::ReadRequest(Filesystem::Path path, DiskManager::ReadRequest::ReadRequestCallback cb)
    : mCb(cb), mPath(path) {
}

void DiskManager::ReadRequest::execute() {
    std::tr1::shared_ptr<DenseData> badResult;

    if(!fs::exists(mPath)) {
        SILOG(transfer, warn, "File '" << mPath.file_string() << "' didn't exist in ReadRequest.");
        mCb(badResult);
        return;
    }

    if(!fs::is_regular_file(mPath)) {
        SILOG(transfer, warn, "File '" << mPath.file_string() << "' was not a regular file in ReadRequest.");
        mCb(badResult);
        return;
    }

    fs::ifstream file(mPath, fs::ifstream::in | fs::ifstream::binary);
    if(!file.is_open()) {
        SILOG(transfer, warn, "File '" << mPath.file_string() << "' was not open in ReadRequest.");
        mCb(badResult);
        return;
    }

    std::tr1::shared_ptr<DenseData> fileContents(new DenseData(Range(true)));
    char buff[5000];
    while(file.good()) {
        file.read(buff, 5000);
        if(file.fail() && file.eof() && !file.bad()) {
            //Read past EoF, so clear the fail bit
            file.clear(std::ios::goodbit | std::ios::eofbit);
        }
        if(file.gcount() > 0) {
            fileContents->append(buff, file.gcount(), true);
        }
    }

    if(file.bad() || file.fail()) {
        SILOG(transfer, warn, "File '" << mPath.file_string() << "' got error while reading in ReadRequest.");
        mCb(badResult);
        return;
    }

    file.close();

    mCb(fileContents);
}

DiskManager::WriteRequest::WriteRequest(Filesystem::Path path,
        std::tr1::shared_ptr<DenseData> fileContents,
        DiskManager::WriteRequest::WriteRequestCallback cb)
    : mCb(cb), mPath(path), mFileContents(fileContents) {
}

void DiskManager::WriteRequest::execute() {
    if(!mFileContents) {
        mCb(false);
        return;
    }

    fs::ofstream file(mPath, fs::ofstream::out | fs::ofstream::binary);
    if(!file.is_open() || !file.good()) {
        mCb(false);
        return;
    }

    file.write((const char *)mFileContents->data(), mFileContents->length());

    if(file.bad() || file.fail()) {
        mCb(false);
        return;
    }

    file.close();

    mCb(true);
}

DiskManager::DiskManager() {
    mWorkerThread = new Thread(std::tr1::bind(&DiskManager::workerThread, this));
}

DiskManager::~DiskManager() {
    //Add an empty request to the queue and then wait for workerThread to finish
    std::tr1::shared_ptr<DiskRequest> nullReq;
    boost::unique_lock<boost::mutex> sleep_cv(destroyLock);
    mRequestQueue.push(nullReq);
    destroyCV.wait(sleep_cv);

    delete mWorkerThread;
}

void DiskManager::addRequest(std::tr1::shared_ptr<DiskRequest> req) {
    mRequestQueue.push(req);
}

void DiskManager::workerThread() {
    while(true) {
        std::tr1::shared_ptr<DiskRequest> req;
        mRequestQueue.blockingPop(req);

        if(!req) break;

        req->execute();
    }

    {
        boost::unique_lock<boost::mutex> wake_cv(destroyLock);
        destroyCV.notify_one();
    }
}

}
}

max_stars_repo_name: pathorn/sirikata

max_issues_repo_name: pathorn/sirikata

max_forks_repo_name: pathorn/sirikata


text:
/* Copyright Institue of Sound and Vibration Research - All rights reserved. */

#include <librbbl/sparse_gain_routing.hpp>

#include <boost/test/unit_test.hpp>

#include <algorithm>
#include <ciso646>
#include <limits>
#include <stdexcept>
#include <vector>

namespace visr
{
namespace rbbl
{
namespace test
{

BOOST_AUTO_TEST_CASE( InstantiateSparseGainRouting )
{
  using namespace visr::rbbl;

  SparseGainRouting::IndexType const entryIdx{ 0 };
  SparseGainRouting::IndexType const inIdx{ 2 };
  SparseGainRouting::IndexType const outIdx{ 5 };
  float const gain = 0.375f;

  SparseGainRouting const routing{ entryIdx, inIdx, outIdx, gain };

  BOOST_CHECK( routing.entryIndex == entryIdx );

}

} // namespace test
} // namespace rbbl
} // namespace visr


text:
// -----------------------------------------------------------------------------
// Fern © Geoneric
//
// This file is part of Geoneric Fern which is available under the terms of
// the GNU General Public License (GPL), version 2. If you do not want to
// be bound by the terms of the GPL, you may purchase a proprietary license
// from Geoneric (http://www.geoneric.eu/contact).
// -----------------------------------------------------------------------------
#define BOOST_TEST_MODULE fern algorithm algebra elementary pow
#include <boost/test/unit_test.hpp>
#include "fern/core/data_customization_point/scalar.h"
#include "fern/core/type_traits.h"
#include "fern/algorithm/algebra/elementary/pow.h"

namespace fa = fern::algorithm;

template<
    class Value1,
    class Value2>
using OutOfDomainPolicy = fa::pow::OutOfDomainPolicy<Value1, Value2>;

BOOST_AUTO_TEST_CASE(out_of_domain_policy)
{
    {
        OutOfDomainPolicy<double, double> policy;
        BOOST_CHECK(policy.within_domain(3.0, 4.0));
        BOOST_CHECK(policy.within_domain(0.0, 0.0));

        BOOST_CHECK(!policy.within_domain(-3.0, 4.1));
        BOOST_CHECK(!policy.within_domain(0.0, -1.0));
    }
}

template<
    class Value1,
    class Value2,
    class Result>
using OutOfRangePolicy = fa::pow::OutOfRangePolicy<Value1, Value2, Result>;

template<
    class Value1,
    class Value2,
    class Result>
struct VerifyWithinRange
{
    bool operator()(
        Value1 const& value1,
        Value2 const& value2)
    {
        fa::SequentialExecutionPolicy sequential;

        OutOfRangePolicy<Value1, Value2, Result> policy;
        Result result;

        fa::algebra::pow(sequential, value1, value2, result);

        return policy.within_range(value1, value2, result);
    }
};

BOOST_AUTO_TEST_CASE(out_of_range_policy)
{
    {
        float max_float = fern::max<float>();

        VerifyWithinRange<float, float, float> verify;
        BOOST_CHECK_EQUAL(verify(0.0, 0.0), true);

        BOOST_CHECK_EQUAL(verify(max_float, max_float), false);
    }
}

template<
    class Value1,
    class Value2,
    class Result>
void verify_value(
    Value1 const& value1,
    Value2 const& value2,
    Result const& result_we_want)
{
    fa::SequentialExecutionPolicy sequential;

    Result result_we_get;
    fa::algebra::pow(sequential, value1, value2, result_we_get);
    BOOST_CHECK_EQUAL(result_we_get, result_we_want);
}

BOOST_AUTO_TEST_CASE(algorithm)
{
    verify_value<float, float, float>( 0.0f, 0.0f, 1.0f);
    verify_value<float, float, float>( 1.0f, 1.0f, 1.0f);
    verify_value<float, float, float>( 2.0f, 2.0f, 4.0f);
}

ext: cc

max_stars_repo_name: quanpands/wflow

max_issues_repo_name: quanpands/wflow

max_forks_repo_name: quanpands/wflow


text:
////////////////////////////////////////////////////////////////////////////////
// cursor.cc
////////////////////////////////////////////////////////////////////////////////
/*! @file
//      Writes an ASCII MSH field to stdout with "cursor" geometry at the
//      specified points.
*/
//  Author:  Julian Panetta (jpanetta), julian.panetta@gmail.com
//  Company:  New York University
//  Created:  06/01/2016 11:54:42
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <cstdlib>

#include <boost/algorithm/string.hpp>
#include <MeshFEM/filters/gen_cursor.hh>

#include <MeshFEM/MeshIO.hh>

double CURSOR_RADIUS = 1;

using namespace std;
using namespace MeshIO;

[[noreturn]] void usage() {
    cerr << "usage: cursor \"x1 y1 z1\" ..." << endl;
    exit(EXIT_FAILURE);
}

int main(int argc, char *argv[])
{
    if (argc < 2) usage();
    std::vector<IOVertex> pts;

    for (int i = 1; i < argc; ++i) {
        string ptString(argv[i]);
        boost::trim(ptString);
        std::vector<string> componentStrings;
        boost::split(componentStrings, ptString, boost::is_any_of("\t "),
                     boost::token_compress_on);
        if (componentStrings.size() == 2)
            pts.emplace_back(stod(componentStrings[0]), stod(componentStrings[1]));
        else if (componentStrings.size() == 3)
            pts.emplace_back(stod(componentStrings[0]), stod(componentStrings[1]), stod(componentStrings[2]));
        else throw std::runtime_error("Invalid point specifier: " + ptString);
    }

    // Create crosshair cursor geometry
    std::vector<IOVertex> vertices;
    std::vector<IOElement> elements;
    for (const auto &p : pts)
        gen_cursor(CURSOR_RADIUS, p, vertices, elements);

    MeshIO_MSH io;
    io.setBinary(false);
    io.save(std::cout, vertices, elements, MESH_LINE);

    return 0;
}

max_stars_repo_name: pbedenbaugh/MeshFEM

max_issues_repo_name: pbedenbaugh/MeshFEM

max_forks_repo_name: pbedenbaugh/MeshFEM


text:
#include <atomic>
#include <condition_variable>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <list>
#include <mutex>
#include <thread>

#include <ilcplex/cplex.h>

#include <boost/program_options.hpp>

#include "cluster.h"
#include "problem.h"
#include "env.h"
#include "lockingvars.h"
#include "symgroup.h"
#include "result.h"
#include "solutions.h"
#include "errors.h"
#include "thread.h"

#ifdef DEBUG
std::mutex debug_mutex;
#endif

extern std::string HASH;

int num_threads;
int cplex_threads;

/**
 * Are we splitting up the range of values an objective can take, such that
 * individual threads only find solutions in their own pre-determined range?
 */
bool split;

/**
 * If we are splitting, are we giving each thread the same sized range, or are
 * we assuming that the last objective is distributed normally, with a mean of
 * (highest+lowest)/2 and a std-dev of (highest-lowest)/6?
 */
bool split_normal;

/**
 * If we are assuming a normal distribution, here are the values we use. Only
 * have numbers for <= 12 threads, feel free to generate more.
 *
 * thread i, from X threads all together, has boundss normal_values[X][i] and
 * normal_values[X][i+1]
 */

double normal_values[13][13] {
  {0}, // 0 threads, to allow direct indexing
  {0, 1},
  {0, 0.5, 1},
  {0, 0.356, 0.644, 1},
  {0, 0.275, 0.5, 0.725, 1},
  {0, 0.219, 0.416, 0.584, 0.781, 1},
  {0, 0.178, 0.256, 0.5, 0.644, 0.822, 1},
  {0, 0.144, 0.311, 0.44, 0.56, 0.689, 0.856, 1},
  {0, 0.117, 0.275, 0.394, 0.5, 0.606, 0.725, 0.883, 1},
  {0, 0.093, 0.245, 0.356, 0.453, 0.547, 0.644, 0.755, 0.907, 1},
  {0, 0.073, 0.219, 0.325, 0.416, 0.5, 0.584, 0.675, 0.781, 0.927, 1},
  {0, 0.055, 0.197, 0.298, 0.384, 0.462, 0.538, 0.616, 0.702, 0.803, 0.945, 1},
  {0, 0.039, 0.178, 0.275, 0.356, 0.430, 0.5, 0.570, 0.644, 0.725, 0.822, 0.961, 1}
};

/**
 * Since normal values are pre-computed, we also have a limit on the number of
 * threads.
 */
const int MAX_THREADS_NORMAL_SPLIT = 12;

/**
 * Has a thread completed its search. If one thread is finished, it will have
 * synchronised along the way, and therefore it (and possibly its
 * cluster-friends) will have the complete list of solutions. That is, if
 * completed is true, then the search may exit.
 */
bool completed;

/**
 * Track how many individual IPs we solve.
 */
std::atomic<int> ipcount;

/**
 * Solves a CLMOIP and returns the status and result.
 * Variables:
 *
 * \param e An Env object holding an environment suitable for solving IPs
 * \param p The Problem object to be solved
 * \param result An array of ints of size p.objcnt where the result will be
 * stored
 * \param rhs An array of doubles holding the right hand side of the problem
 * \param perm_id The index of the permutation which denotes the hierarchy or
 * ordering of the objectives, from most significant to least.
 * \param t A thread object, which itself includes the permutation, as well as
 * how many objectives to optimise.
 *
 * Note that objectives that are not optimised will still be calculated, they
 * just won't be optimised in any way.
 */
int solve(Env & e, Problem & p, int * result, double * rhs, Thread * t);

/**
 * Sets up the optimisation based on splitting the value of the final
 * objective.
 * \param e The relevant Env object
 * \param p The relevant Problem object
 * \param s A list in which to store solutions.
 * \param obj The objective to be optimised
 */
void split_setup(Env &e, Problem &p, std::list<int *> &s, int nObj);

/**
 * Finds out the limit (either maximum or minimum) of one objective in the
 * problem. This is only used to set up the splitting algorithm correctly.
 */
void get_limit(Env & e, Problem & p, int obj, double * rhs, int * result,
    const Sense sense);

/**
 * Optimise!
 * This function runs through the selected algorithm of Pettersson and
 * Ozlen[1]. It is designed to be run multi-threaded, hence using locking
 * mechanisms.
 *
 * \pram pFilename The file name of the file holding the problem description
 * \param all A Solutions object into which all solutions will be placed
 * \param infeasibles A Solutions object containing all infeasible problems
 * \param t A pointer to a Thread object that describes how this particular
 * thread should approach the problem.
 **/

/* Note that this function is templated. There's no evidence that this does
 * increase running time, but it's not like it decreases it either. */
template<Sense sense>
void optimise(const char * pFilename, Solutions & all, Solutions & infeasibles,
              Thread *t);

namespace po = boost::program_options;

int main (int argc, char *argv[])
{

  int status = 0; /* Operation status */

  Env e;

  std::string pFilename, outputFilename;

  /* Timing */
  clock_t starttime, endtime;
  double cpu_time_used, elapsedtime, startelapsed;
  int solcount;

  bool spread = false;
  split = false;

  po::variables_map v;
  po::options_description opt("Options for aira");
  opt.add_options()
    ("help,h", "Show this help.")
    ("lp,p",
      po::value<std::string>(&pFilename),
     "The LP file to solve. Required.")
    ("output,o",
      po::value<std::string>(&outputFilename),
     "The output file. Optional.")
    ("split,",
     po::bool_switch(&split),
     "Split the range of the first objective into one strip per thread\n"
     "Optional, defaults to False.")
    ("split-normal,",
     po::bool_switch(&split_normal),
     "If splitting, assume a normal distribution for objective values\n"
     "Optional, defaults to False.")
    ("spread,s",
     po::bool_switch(&spread)->default_value(true),
     "Spread threads out over various subgroups of the symmetries (as opposed to clustering inside subgroups).\n"
     "Optional, defaults to True")
    ("threads,t",
      po::value<int>(&num_threads)->default_value(1),
     "Number of threads to use internally. Optional, default to 1.")
    ("cplex_threads,c",
        po::value<int>(&cplex_threads)->default_value(1),
     "Number of threads to allocate to CPLEX.\n"
     "Note that each internal thread calls CPLEX, so the total number of "
     "threads used is threads*cplex_threads.\n"
     "Optional, defaults to 1.")
  ;

  po::store(po::parse_command_line(argc, argv, opt), v);
  po::notify(v);

  if (v.count("help")) {
    // usage();
    std::cout << opt << std::endl;
    return(1);
  }

  if (split_normal && (num_threads > MAX_THREADS_NORMAL_SPLIT)) {
    std::cerr << "Error: split_normal can only handle at most "
      << MAX_THREADS_NORMAL_SPLIT << " threads." << std::endl;
    return(1);
  }

  if (v.count("lp") == 0) {
    // usage();
    std::cerr << "Error: You must pass in a problem file. All other parameters are optional." << std::endl;
    std::cout << opt << std::endl;
    return(1);
  }

  std::ofstream outFile;

  if (v.count("output")) {
    outFile.open(outputFilename);
  } else {
    /* Output file: <filename>.out */
    size_t last = pFilename.find_last_of(".");
    outFile.open(pFilename.substr(0, last).append(".out"));
  }

  /* Initialize the CPLEX environment */
  e.env = CPXopenCPLEX (&status);

  Problem p(pFilename.c_str(), e);

  if (p.objcnt >= maxObjCount) {
    std::cerr << "Error: This version of moip_aira has been compiled to support at most " << maxObjCount << " objectives." << std::endl;
    return -ERR_AIRA;
  }

  /* Set to deterministic parallel mode */
  status=CPXsetintparam(e.env, CPXPARAM_Parallel, CPX_PARALLEL_DETERMINISTIC);

  /* Set to only one thread */
  CPXsetintparam(e.env, CPXPARAM_Threads, cplex_threads);

  if (e.env == NULL) {
    std::cerr << "Could not open CPLEX environment." << std::endl;
    return -ERR_CPLEX;
  }

  status = CPXsetintparam(e.env, CPX_PARAM_SCRIND, CPX_OFF);
  if (status) {
    std::cerr << "Failure to turn off screen indicator, error." << std::endl ;
      return -ERR_CPLEX;
  }

  outFile << std::endl << "Using improved algorithm at " << HASH << std::endl;

  /* Start the timer */
  starttime = clock();
  timespec start;
  clock_gettime(CLOCK_MONOTONIC, &start);
  startelapsed = start.tv_sec + start.tv_nsec/1e9;

  if (num_threads > S[p.objcnt].size())
    num_threads = S[p.objcnt].size();

  Solutions all(p.objcnt);

  completed = false;

  std::list<Locking_Vars*> locking_var_list;

  std::list<Thread*> threads;
  if (split) {
    std::list<int *> sols;
    // Note that split_setup will farm out jobs to threads and everything.
    split_setup(e, p, sols, p.objcnt);
    double * lp = new double[p.objcnt];
    for(auto s : sols) {
      all.insert(lp, s, false /* infeasible */);
    }
  } else {
    // Not splitting.
    int * ordering = new int[p.objcnt];
    for (int c = 0; c < p.objcnt; ++c) {
      ordering[c] = c;
    }
    int ** share_from = new int*[p.objcnt] {nullptr};
    int ** share_to = new int*[p.objcnt] {nullptr};
    int ** share_bounds = new int*[p.objcnt] {nullptr};
    int ** share_limit = new int*[p.objcnt] {nullptr};
    Locking_Vars ** lvs = new Locking_Vars*[p.objcnt] {nullptr};
    Cluster c(num_threads, p.objcnt, p.objsen, spread, p.objcnt, ordering,
        share_from, share_to, share_bounds, share_limit, threads, lvs);
    delete[] ordering;
    delete[] share_to;
    delete[] share_from;
    delete[] share_bounds;
    delete[] share_limit;
  }
  Solutions infeasibles(p.objcnt);
  std::list<std::thread> threadList;
  if (p.objsen == MIN) {
    for(Thread* thread: threads) {
      threadList.emplace_back(optimise<MIN>, pFilename.c_str(),
          std::ref(all), std::ref(infeasibles), thread);
    }
  } else {
    for(Thread* & thread: threads) {
      threadList.emplace_back(optimise<MAX>, pFilename.c_str(),
          std::ref(all), std::ref(infeasibles), thread);
    }
  }
  /* Free up memory as all we needed was a count of the number of objectives. */
  if ( e.lp != NULL ) {
     status = CPXfreeprob (e.env, &e.lp);
     if ( status ) {
       std::cerr << "CPXfreeprob failed." << std::endl;
     }
  }
  if ( e.env != NULL ) {
     status = CPXcloseCPLEX (&e.env);

     if ( status ) {
       std::cerr << "Could not close CPLEX environment." << std::endl;
     }
  }
  for (auto& thread: threadList)
    thread.join();

  for (auto lv: locking_var_list)
    delete lv;

  /* Stop the clock. Sort and print results.*/
  endtime = clock();
  cpu_time_used=((double) (endtime - starttime)) / CLOCKS_PER_SEC;
  clock_gettime(CLOCK_MONOTONIC, &start);
  elapsedtime = (start.tv_sec + start.tv_nsec/1e9 - startelapsed);

  all.sort();
  solcount = 0;

  /* List of things we've printed */
  std::list<const Result *> printed;
  for (const Result* soln: all) {
    if (soln->infeasible)
      continue;
    bool printMe = true;
    for (auto& done: printed) {
      if (*done == *soln) {
        printMe = false;
        break;
      }
    }
    if (printMe) {
      for (int i = 0; i < p.objcnt; i++) {
        outFile << soln->result[i] << "\t";
      }
      outFile << std::endl;
      printed.push_back(soln);
      solcount++;
    }
  }

  constexpr int width = 8;
  constexpr int precision = 3;
  outFile << std::endl << "---" << std::endl;
  outFile << std::setw(width) << std::setprecision(precision) << std::fixed;
  outFile << cpu_time_used << " CPU seconds" << std::endl;
  outFile << std::setw(width) << std::setprecision(precision) << std::fixed;
  outFile << elapsedtime << " elapsed seconds" << std::endl;
  outFile << std::setw(width) << std::setprecision(precision) << std::fixed;
  outFile << ipcount << " IPs solved" << std::endl;
  outFile << std::setw(width) << std::setprecision(precision) << std::fixed;
  outFile << solcount << " Solutions found" << std::endl;

  outFile.close();

  return (status);
}

void get_limit(Env & e, Problem & p, int obj, double * rhs, int * result, const Sense sense) {

  int cur_numcols, status, solnstat;
  double objval;
  double * srhs;
  srhs = new double[p.objcnt];

  memcpy(srhs, rhs, p.objcnt * sizeof(double));

  cur_numcols = CPXgetnumcols(e.env, e.lp);

  status = CPXchgobj(e.env, e.lp, cur_numcols, p.objind[obj], p.objcoef[obj]);
  if (status) {
    std::cerr << "Failed to set objective." << std::endl;
  }

  status = CPXchgrhs (e.env, e.lp, p.objcnt, p.conind, srhs);
  if (status) {
    std::cerr << "Failed to change constraint srhs" << std::endl;
  }

  int i_sense;
  if (sense == MIN) {
    i_sense = 1;
  } else {
    i_sense = -1;
  }
  status = CPXchgobjsen (e.env, e.lp, i_sense);
  if (status) {
    std::cerr << "Failed to change constraint srhs" << std::endl;
  }

  /* solve for current objective*/
  status = CPXmipopt (e.env, e.lp);
  if (status) {
    std::cerr << "Failed to optimize LP." << std::endl;
  }

  // This is shared across threads, but it's an atomic integer (so read/writes
  // are atomic) and thus we don't need a lock/mutex
  ipcount++;

  solnstat = CPXgetstat (e.env, e.lp);
  if ((solnstat == CPXMIP_INFEASIBLE) || (solnstat == CPXMIP_INForUNBD)) {
    return;
  }
  status = CPXgetobjval (e.env, e.lp, &objval);
  if ( status ) {
    std::cerr << "Failed to obtain objective value." << std::endl;
    exit(0);
  }
  if ( abs(objval) > 1/p.mip_tolerance ) {
    while (abs(objval) > 1/p.mip_tolerance) {
      p.mip_tolerance /= 10;
    }
    CPXsetdblparam(e.env, CPXPARAM_MIP_Tolerances_MIPGap, p.mip_tolerance);
    status = CPXmipopt (e.env, e.lp);
    ipcount++;
    solnstat = CPXgetstat (e.env, e.lp);
    if ((solnstat == CPXMIP_INFEASIBLE) || (solnstat == CPXMIP_INForUNBD)) {
      return;
    }
    status = CPXgetobjval (e.env, e.lp, &objval);
    if ( status ) {
      std::cerr << "Failed to obtain objective value." << std::endl;
      exit(0);
    }
  }
  delete[] srhs;

  // Get the solution vector
  double * soln = new double[cur_numcols];
  CPXgetx(e.env, e.lp, soln, 0, cur_numcols - 1);
  // Now run through the rest of the objectives.
  for (int j = 0; j < p.objcnt; j++) {
    double res = 0;
    for(int i = 0; i < cur_numcols; ++i) {
      res += p.objcoef[j][i] * soln[i];
    }
    result[j] = round(res);
  }
  delete[] soln;
  return;
}

int solve(Env & e, Problem & p, int * result, double * rhs, Thread * t) {

  int cur_numcols, status, solnstat;
  double objval;
  double * srhs;
  srhs = new double[p.objcnt];

  //for(int i = 0; i < p.objcnt; ++i)
  //  srhs[i] = rhs[perm[i]];

  memcpy(srhs, rhs, p.objcnt * sizeof(double));

  cur_numcols = CPXgetnumcols(e.env, e.lp);

  // TODO Permutation applies here.
  for (int j_preimage = 0; j_preimage < t->nObj(); j_preimage++) {
    int j = t->perm(j_preimage);
    status = CPXchgobj(e.env, e.lp, cur_numcols, p.objind[j], p.objcoef[j]);
    if (status) {
      std::cerr << "Failed to set objective." << std::endl;
    }

    status = CPXchgrhs (e.env, e.lp, p.objcnt, p.conind, srhs);
    if (status) {
      std::cerr << "Failed to change constraint srhs" << std::endl;
    }

    /* solve for current objective*/
    status = CPXmipopt (e.env, e.lp);
    if (status) {
      std::cerr << "Failed to optimize LP." << std::endl;
    }

    // This is shared across threads, but it's an atomic integer (so read/writes
    // are atomic) and thus we don't need a lock/mutex
    ipcount++;

    solnstat = CPXgetstat (e.env, e.lp);
    if ((solnstat == CPXMIP_INFEASIBLE) || (solnstat == CPXMIP_INForUNBD)) {
       break;
    }
    status = CPXgetobjval (e.env, e.lp, &objval);
    if ( status ) {
      std::cerr << "Failed to obtain objective value." << std::endl;
      exit(0);
    }
    if ( abs(objval) > 1/p.mip_tolerance ) {
      while (abs(objval) > 1/p.mip_tolerance) {
        p.mip_tolerance /= 10;
      }
      CPXsetdblparam(e.env, CPXPARAM_MIP_Tolerances_MIPGap, p.mip_tolerance);
      status = CPXmipopt (e.env, e.lp);
      ipcount++;
      solnstat = CPXgetstat (e.env, e.lp);
      if ((solnstat == CPXMIP_INFEASIBLE) || (solnstat == CPXMIP_INForUNBD)) {
        break;
      }
      status = CPXgetobjval (e.env, e.lp, &objval);
      if ( status ) {
        std::cerr << "Failed to obtain objective value." << std::endl;
        exit(0);
      }
    }

    //p.result[j] = srhs[j] = round(objval);
    result[j] = srhs[j] = round(objval);
  }
  // Get the solution vector
  double * soln = new double[cur_numcols];
  CPXgetx(e.env, e.lp, soln, 0, cur_numcols - 1);
  // Now run through the rest of the objectives.
  for (int j_pre = t->nObj(); j_pre < p.objcnt; j_pre++) {
    int j = t->perm(j_pre);
    double res = 0;
    for(int i = 0; i < cur_numcols; ++i) {
      res += p.objcoef[j][i] * soln[i];
    }
    result[j] = round(res);
  }
  delete[] soln;

  delete[] srhs;

  return solnstat;
}

template<Sense sense>
void optimise(const char * pFilename, Solutions & all, Solutions & infeasibles,
    Thread *t) {
  Env e;
  const bool sharing = (t->share_to != nullptr);
#ifdef DEBUG
  debug_mutex.lock();
  if (split) {
    std::cout << "Thread " << t->id << " has start ";
    std::cout << t->split_start << " and stop " << t->split_stop << std::endl;
  }
  if (sharing) {
    std::cout << "Thread " << t->id << " is sharing" << std::endl;
  }
  debug_mutex.unlock();
#endif
#ifdef FINETIMING
  double cplex_time = 0;
  double wait_time = 0;
  timespec start;
  clock_gettime(CLOCK_MONOTONIC, &start);
  double total_time = start.tv_sec + start.tv_nsec/1e9;
#endif
  {
    int status; // Only need status here.
    /* Initialize the CPLEX environment */
    e.env = CPXopenCPLEX (&status);
    if (status != 0) {
      std::cerr << "Could not open CPLEX environment." << std::endl;
    }

    /* Set to deterministic parallel mode */
    status=CPXsetintparam(e.env, CPXPARAM_Parallel, CPX_PARALLEL_DETERMINISTIC);

    /* Set to only one thread */
    CPXsetintparam(e.env, CPXPARAM_Threads, cplex_threads);

    if (e.env == NULL) {
      std::cerr << "Could not open CPLEX environment." << std::endl;
    }

    status = CPXsetintparam(e.env, CPX_PARAM_SCRIND, CPX_OFF);
    if (status) {
      std::cerr << "Failure to turn off screen indicator." << std::endl;
    }
  }

  Problem p(pFilename, e);

  Solutions s(p.objcnt);

  int infcnt;
  bool inflast;
  bool infeasible;
  int * max, * min,  * result, *resultStore;
  double * rhs;

  result = resultStore = new int[p.objcnt];
  rhs = new double[p.objcnt];
  for(int i = 0; i < p.objcnt; ++i) {
    rhs[i] = p.rhs[i];
  }
  if (split) {
 #ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " splitting on ";
          std::cout << t->perm(t->nObj()-1) << std::endl;
          debug_mutex.unlock();
#endif
    rhs[t->perm(t->nObj()-1)] = t->split_start;
  }

#ifdef FINETIMING
  clock_gettime(CLOCK_MONOTONIC, &start);
  double starttime = (start.tv_sec + start.tv_nsec/1e9);
#endif
  int solnstat = solve(e, p, result, rhs, t);
#ifdef FINETIMING
  clock_gettime(CLOCK_MONOTONIC, &start);
  cplex_time += (start.tv_sec + start.tv_nsec/1e9) - starttime;
#endif
#ifdef DEBUG
  debug_mutex.lock();
  std::cout << "Thread " << t->id << " with constraints ";
  for(int i = 0; i < p.objcnt; ++i) {
    if (rhs[i] > 1e09)
      std::cout << "∞";
    else if (rhs[i] < -1e09)
      std::cout << "-∞";
    else
      std::cout << rhs[i];
    std::cout << ",";
  }
  std::cout << " found ";
  if (solnstat == CPXMIP_INFEASIBLE) {
    std::cout << "infeasible";
  } else {
    for(int i = 0; i < p.objcnt; ++i) {
      std::cout << result[i] << ",";
    }
  }
  std::cout << std::endl;
  debug_mutex.unlock();
#endif

  /* Need to add a result to the list here*/
  if (solnstat == CPXMIP_INFEASIBLE) {
    infeasibles.insert(rhs, result, true);
  } else {
    if (split)
      all.insert(rhs, result, solnstat == CPXMIP_INFEASIBLE);
    else
      s.insert(rhs, result, solnstat == CPXMIP_INFEASIBLE);
  }
  // Note that if we are splitting, we aren't sharing.
  if (split) {
    if (p.objsen == MIN)
      t->split_stop--;
    else
      t->split_stop++;
  } else {
    if (sharing && (solnstat != CPXMIP_INFEASIBLE)) {
      int *objectives = new int[p.objcnt];
      for (int i = 0; i < p.objcnt; ++i) {
        objectives[i] = result[i];
      }
    }
  }
  min = new int[p.objcnt];
  max = new int[p.objcnt];

#ifdef DEBUG
  debug_mutex.lock();
  std::cout << "Thread " << t->id << " using permutation ";
  for (int i = 0; i < p.objcnt; ++i) {
    std::cout << t->perm(i) <<  ", ";
  }
  std::cout << std::endl;
  debug_mutex.unlock();
#endif

  if (sharing && (solnstat != CPXMIP_INFEASIBLE) && (p.objcnt > 1)) {
    int i = t->perm(1);
    if (t->share_to[i] != nullptr) {
      if (sense == MIN) {
        if (*t->share_to[i] < result[i]) {
          *t->share_to[i] = result[i];
        }
      } else {
        if (*t->share_to[i] > result[i]) {
          *t->share_to[i] = result[i];
        }
      }
    }
  }
  if (solnstat != CPXMIP_INFEASIBLE) {
    for (int j = 0; j < p.objcnt; j++) {
      min[j] = max[j] = result[j];
    }
  }

  /**
   * objective_counter marks which objectives are currently active. Note that
   * the first objective (highest priority) is 0, which we never make active.
   *
   * That is, if the current permutation is 1,2,3,4,5 and objective_counter is
   * 1, then we are trying to optimise objective 2. In other words, objectives
   * 3,4,5 all have their limits set to +- infinity, and these won't change
   * until objective_counter increases.
   *
   * If objective_counter is 3, then we are changing objectives 2,3 and 4.
   */

  /**
   * depth tracks which of the active objectives is the one being currently
   * modified. If objective_counter is 3, then the active objectives are 2,3
   * and 4. If depth is 1, then objective 2 is the one for which we are
   * changing the RHS.
   */

  /**
   * onwalk is true if the current active depth (as indicated by the depth
   * variable) was just increased.
   */
  for (int objective_counter = 1; objective_counter < t->nObj(); objective_counter++) {
    int objective = t->perm(objective_counter);
    int depth_level = 1; /* Track current "recursion" depth */
    int depth = t->perm(depth_level); /* Track depth objective */
    bool onwalk = false; /* Are we on the move? */
    //bool * found_any = new bool[p.objcnt] {false};
    infcnt = 0; /* Infeasible count*/
    inflast = false; /* Last iteration infeasible?*/

    /* Set all constraints back to infinity*/
    for (int j_pre = 1; j_pre < p.objcnt; j_pre++) {
      int j = t->perm(j_pre);
      if ((!sharing) || (t->share_from[j] == nullptr)) {
        if (sense == MIN) {
          rhs[j] = CPX_INFBOUND;
        } else {
          rhs[j] = -CPX_INFBOUND;
        }
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "setting rhs[" << j << "] to ±inf" << std::endl;
          debug_mutex.unlock();
#endif
      } else {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "setting rhs[" << j << "] to " << *t->share_from[j] << std::endl;
          debug_mutex.unlock();
#endif
        rhs[j] = *t->share_from[j];
      }
    }
    if (split) {
        rhs[t->perm(t->nObj()-1)] = t->split_start;
    }
    /* Set rhs of current depth */
    if (sense == MIN) {
      rhs[objective] = max[objective]-1;
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "setting rhs[" << objective << "] to " << (max[objective]-1) << std::endl;
          debug_mutex.unlock();
#endif
    } else {
      rhs[objective] = min[objective]+1;
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "setting rhs[" << objective << "] to " << (min[objective]+1) << std::endl;
          debug_mutex.unlock();
#endif
    }
    if (split) {
      // check if we cross midpoint
      if (sense == MIN) {
        if (rhs[t->nObj()-1] < t->split_stop) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " reached split_stop";
          std::cout << " " << t->split_stop << std::endl;
          debug_mutex.unlock();
#endif
          break;
        }
      } else {
        if (rhs[t->nObj()-1] > t->split_stop) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " reached split_stop";
          std::cout << " " << t->split_stop << std::endl;
          debug_mutex.unlock();
#endif
          break;
        }
      }
    }
    max[objective] = (int) -CPX_INFBOUND;
    min[objective] = (int) CPX_INFBOUND;
    while (infcnt < objective_counter && !completed) {
      bool relaxed;
      int solnstat;
      /* Look for possible relaxations to the current problem*/
      const Result *relaxation;

#ifdef DEBUG_SOLUTION_SEARCH
      debug_mutex.lock();
      std::cout << "Thread " << t->id;
      debug_mutex.unlock();
#endif
      // First check if it's infeasible
      relaxation = infeasibles.find(rhs, p.objsen);
      if (relaxation == nullptr) {
        if (split) {
          relaxation = all.find(rhs, p.objsen);
        } else {
          relaxation = s.find(rhs, p.objsen);
        }
      }
      relaxed = (relaxation != nullptr);
      if (relaxed) {
        infeasible = relaxation->infeasible;
        result = relaxation->result;
      } else {
        /* Solve in the absence of a relaxation*/
        result = resultStore;
#ifdef FINETIMING
        clock_gettime(CLOCK_MONOTONIC, &start);
        double starttime = (start.tv_sec + start.tv_nsec/1e9);
#endif
        solnstat = solve(e, p, result, rhs, t);
#ifdef FINETIMING
        clock_gettime(CLOCK_MONOTONIC, &start);
        cplex_time += (start.tv_sec + start.tv_nsec/1e9) - starttime;
#endif
        infeasible = ((solnstat == CPXMIP_INFEASIBLE) || (solnstat == CPXMIP_INForUNBD));
        /* Store result */
        if (infeasible) {
          infeasibles.insert(rhs, result, true);
        } else {
          if (split) {
            all.insert(rhs, result, infeasible);
          } else {
            s.insert(rhs, result, infeasible);
          }
        }
      }
#ifdef DEBUG
      debug_mutex.lock();
      std::cout << "Thread " << t->id << " with constraints ";
      for(int i = 0; i < p.objcnt; ++i) {
        if (rhs[i] > 1e09)
          std::cout << "∞";
        else if (rhs[i] < -1e09)
          std::cout << "-∞";
        else
          std::cout << rhs[i];
        std::cout << ",";
      }
      std::cout << " found ";
      if (relaxed)
        std::cout << "relaxation ";
      if (infeasible) {
        std::cout << "infeasible." << std::endl;
      } else {
        for(int i = 0; i < p.objcnt; ++i) {
          std::cout << result[i] << ",";
        }
        std::cout << std::endl;
      }
      debug_mutex.unlock();
#endif
      if (split) {
        if (!infeasible) {
          // check if we cross midpoint
          if (infcnt == t->nObj() - 2) {
            if (sense == MIN) {
              if (rhs[t->nObj()-1] < t->split_stop) {
                infeasible = true;
#ifdef DEBUG
                debug_mutex.lock();
                std::cout << "Thread " << t->id << " reached split_stop";
                std::cout << " " << t->split_stop << std::endl;
                debug_mutex.unlock();
#endif
              }
            } else {
              if (rhs[t->nObj()-1] > t->split_stop) {
                infeasible = true;
#ifdef DEBUG
                debug_mutex.lock();
                std::cout << "Thread " << t->id << " reached split_stop";
                std::cout << " " << t->split_stop << std::endl;
                debug_mutex.unlock();
#endif
              }
            }
          }
          /* Update maxima */
          for (int j = 0; j < p.objcnt; j++) {
            if (result[j] > max[j]) {
              max[j] = result[j];
            }
          }
          /* Update minima */
          for (int j = 0; j < p.objcnt; j++) {
            if (result[j] < min[j]) {
              min[j] = result[j];
            }
          }
        }
        if (infeasible) {
          infcnt++;
          inflast = true;
        } else {
          infcnt = 0;
          inflast = false;
        }
      } else if (sharing && t->locks && t->locks[t->perm(infcnt+1)]) {
        std::unique_lock<std::mutex> lk(t->locks[t->perm(infcnt+1)]->status_mutex);
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << " got lock on " << t->perm(infcnt+1) << std::endl;
          debug_mutex.unlock();
#endif
        // Note that perm[1] is only shared with one other thread, that only
        // ever reads it, and that this thread always improves the value of
        // this shared limit, so we can use this faster update.
        if (!infeasible && (p.objcnt > 1)) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " updating first bound on " << t->perm(1);
          std::cout << " to " << result[t->perm(1)] << std::endl;
          debug_mutex.unlock();
#endif
          if (t->share_to[t->perm(1)] != nullptr)
            *t->share_to[t->perm(1)] = result[t->perm(1)];
        }

        if (!infeasible && (t->share_from[t->perm(0)] != nullptr)) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "result on " << t->perm(0) << " is " << result[t->perm(0)] << " and ";
          std::cout << "first bound on " << t->perm(0) << " is " << *t->share_from[t->perm(0)] <<std::endl;
          debug_mutex.unlock();
#endif
          if (sense == MIN) {
            if (result[t->perm(0)] >= *t->share_from[t->perm(0)]) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " smaller result found by partner, bailing." << std::endl;
          debug_mutex.unlock();
#endif
              // Check if our partner found something.
              if (t->locks) {
                int obj = t->perm(infcnt+1);
                Locking_Vars *lv = t->locks[obj];
                if (lv != nullptr) {
                  if (lv->found_any) {
#ifdef DEBUG
            debug_mutex.lock();
            std::cout << "Thread " << t->id << " ";
            std::cout << "partner found something." << std::endl;
            debug_mutex.unlock();
#endif
                    // Partner found something
                    infcnt = 0;
                    inflast = true;
                    depth_level = 1;
                    depth = t->perm(depth_level);
                  }
                }
              }
              // Pretend infeasible to backtrack properly
              infeasible = true;
            }
          } else {
            if (result[t->perm(0)] <= *t->share_from[t->perm(0)]) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " bigger result found by partner, bailing." << std::endl;
          debug_mutex.unlock();
#endif
              // Check if our partner found something.
              if (t->locks) {
                int obj = t->perm(infcnt+1);
                Locking_Vars *lv = t->locks[obj];
                if (lv != nullptr) {
                  if (lv->found_any) {
#ifdef DEBUG
            debug_mutex.lock();
            std::cout << "Thread " << t->id << " ";
            std::cout << "partner found something." << std::endl;
            debug_mutex.unlock();
#endif
                    // Partner found something
                    infcnt = 0;
                    inflast = true;
                    depth_level = 1;
                    depth = t->perm(depth_level);
                  }
                }
              }
              // Pretend infeasible to backtrack properly
              infeasible = true;
            }
          }
          // Duplicate code as we are marking this result infeasible
          /* Update maxima */
          for (int j = 0; j < p.objcnt; j++) {
            if (result[j] > max[j]) {
              max[j] = result[j];
            }
          }
          /* Update minima */
          for (int j = 0; j < p.objcnt; j++) {
            if (result[j] < min[j]) {
              min[j] = result[j];
            }
          }
        }
        if (!infeasible) {
          if (t->locks) {
            int obj = t->perm(infcnt+1);
            Locking_Vars *lv = t->locks[obj];
            if (lv != nullptr) {
              lv->found_any = true;
#ifdef DEBUG
            debug_mutex.lock();
            std::cout << "Thread " << t->id << " ";
            std::cout << "found something at infcnt=" << infcnt << std::endl;
            debug_mutex.unlock();
#endif
            }
          }
          infcnt = 0;
          inflast = false;
          /* Update maxima */
          for (int j = 0; j < p.objcnt; j++) {
            if (result[j] > max[j]) {
              max[j] = result[j];
            }
          }
          /* Update minima */
          for (int j = 0; j < p.objcnt; j++) {
            if (result[j] < min[j]) {
              min[j] = result[j];
            }
          }
        }
        if (infeasible) {
          if (t->locks) {
            int obj = t->perm(infcnt+1);
            Locking_Vars *lv = t->locks[obj];
            if (lv != nullptr) {
              if (lv->found_any) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "apparently partner found something ";
          std::cout << "on obj " << obj << std::endl;
          debug_mutex.unlock();
#endif
                infcnt = 0;
              }
            }
          }
          infcnt++;
          inflast = true;
        } else {
          infcnt = 0;
          inflast = false;
        }
      } else {
        if (infeasible) {
          infcnt++;
          inflast = true;
        } else {
          infcnt = 0;
          inflast = false;
          /* Update maxima */
          for (int j = 0; j < p.objcnt; j++) {
            if (result[j] > max[j]) {
              max[j] = result[j];
            }
          }
          /* Update minima */
          for (int j = 0; j < p.objcnt; j++) {
            if (result[j] < min[j]) {
              min[j] = result[j];
            }
          }
        }
      }

      // If we are sharing, and there are other threads, and this result
      // is infeasible, and it's a 2-objective problem
      if (sharing && infeasible && (infcnt+1) < p.objcnt) {
        int updated_objective = t->perm(infcnt+1);
#ifdef DEBUG
        debug_mutex.lock();
        std::cout << "Thread " << t->id <<  " done, ";
        std::cout << "infcnt is " << infcnt;
        std::cout << ", objective_counter is " << objective_counter;
        std::cout << ", updated_objective is " << updated_objective;
        if (sense == MIN) {
          std::cout << " and max[" << updated_objective << "] is " << max[updated_objective];
        } else {
          std::cout << " and min[" << updated_objective << "] is " << min[updated_objective];
        }
        std::cout << std::endl;
        debug_mutex.unlock();
#endif
        bool wait = false;
        Locking_Vars *lv = nullptr;
        if (t->locks && !completed)
          lv = t->locks[updated_objective];
        if ( lv != nullptr) {
          std::unique_lock<std::mutex> lk(lv->status_mutex);
          if ( lv->num_running_threads > 1) {
            lv->num_running_threads--; // This thread is no longer running.
#ifdef DEBUG_SYNC
            debug_mutex.lock();
            std::cout << "Thread " << t->id <<  " done, at " << __LINE__ << " w/ ";
            std::cout << lv->num_running_threads << " threads still going." << std::endl;
            debug_mutex.unlock();
#endif
            // Share all bounds!
            for(int pre_i=0; pre_i < p.objcnt; ++pre_i) {
              int i = t->perm(pre_i);
              if (t->share_bounds[i] != nullptr) {
                if (sense == MIN) {
                  if (*t->share_bounds[i] < max[i]) {
                    *t->share_bounds[i] = max[i];
                  }
                } else {
                  if (*t->share_bounds[i] > min[i]) {
                    *t->share_bounds[i] = min[i];
                  }
                }
              }
            }
            wait = true;
#ifdef FINETIMING
            clock_gettime(CLOCK_MONOTONIC, &start);
            double start_wait = start.tv_sec + start.tv_nsec/1e9;
#endif
            if (!completed) {
#ifdef DEBUG_SYNC
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "waiting on lock " << lv << " at " << __LINE__ << std::endl;
          debug_mutex.unlock();
#endif
              lv->cv.wait(lk); // Wait for all other threads to update limits.
            }
#ifdef FINETIMING
            clock_gettime(CLOCK_MONOTONIC, &start);
            wait_time += (start.tv_sec + start.tv_nsec/1e9) - start_wait;
#endif
            // Share min/max values
            if (t->share_to[updated_objective] != nullptr) {
              if (sense == MIN) {
                if (*t->share_to[updated_objective] > max[updated_objective]) {
                  max[updated_objective] = *t->share_to[updated_objective];
                }
              } else {
                if (*t->share_to[updated_objective] < min[updated_objective]) {
                  min[updated_objective] = *t->share_to[updated_objective];
                }
              }
            }
            // Share bounds on all objectives
            for(int pre_i=0; pre_i < p.objcnt; ++pre_i) {
              int i = t->perm(pre_i);
              if (t->share_bounds[i] != nullptr) {
                if (sense == MIN) {
                  if (*t->share_bounds[i] > max[i]) {
                    max[i] = *t->share_bounds[i];
                  }
                } else {
                  if (*t->share_bounds[i] < min[i]) {
                    min[i] = *t->share_bounds[i];
                  }
                }
              }
            }
          } else {
            // This thread is last.
#ifdef DEBUG_SYNC
            debug_mutex.lock();
            std::cout << "Thread " << t->id <<  " done at " << __LINE__ << ", ";
            std::cout << "last in." << std::endl;
            debug_mutex.unlock();
#endif
            // Sharing bounds on all objectives
            for(int pre_i=0; pre_i < p.objcnt; ++pre_i) {
              int i = t->perm(pre_i);
              if (t->share_bounds[i] != nullptr) {
                if (sense == MIN) {
                  if (*t->share_bounds[i] < max[i]) {
                    *t->share_bounds[i] = max[i];
                  } else {
                    max[i] = *t->share_bounds[i];
                  }
                } else {
                  if (*t->share_bounds[i] > min[i]) {
                    *t->share_bounds[i] = min[i];
                  } else {
                    min[i] = *t->share_bounds[i];
                  }
                }
              }
            }
            // Sharing min/max
            if (t->share_to[updated_objective] != nullptr) {
              if (sense == MIN) {
                if (max[updated_objective] != (int)-CPX_INFBOUND) {
                  *t->share_to[updated_objective] = max[updated_objective];
                }
              } else {
                if (min[updated_objective] != (int)CPX_INFBOUND) {
                  *t->share_to[updated_objective] = min[updated_objective];
                }
              }
            }
            // Reset value of found_any for next time we visit this level.
            lv->found_any = false;
            // Update shared_limits for updated_objective
            int * limit = t->share_limit[updated_objective];
            if ((limit != nullptr) && (t->share_from[updated_objective] != nullptr)) {
              *limit = *t->share_from[updated_objective];
#ifdef DEBUG
              debug_mutex.lock();
              std::cout << "Thread " << t->id << " ";
              std::cout << "set limit[" << updated_objective << "] to ";
              std::cout << *limit << std::endl;
              debug_mutex.unlock();
#endif
            }
            lv->reset_num_running_threads(); // These threads are starting up again.
#ifdef DEBUG
            debug_mutex.lock();
            std::cout << "Thread " << t->id << ", ";
            std::cout << "max is " << max[updated_objective] << ", ";
            if (t->share_bounds[updated_objective] != nullptr)
              std::cout << "share_to is " << *t->share_to[updated_objective] << ", ";
            std::cout << lv->num_running_threads << " threads going." << std::endl;
            debug_mutex.unlock();
#endif
#ifdef DEBUG_SYNC
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "releasing on lock " << lv << " at " << __LINE__ << std::endl;
          debug_mutex.unlock();
#endif
            lk.unlock();
            lv->cv.notify_all();
          }
        }
        if (!completed && lv != nullptr) {
          for(int i = 0; i <= infcnt; ++i) {
            if (sense == MIN) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "setting max[" << t->perm(i) << "] to -inf" << std::endl;
          debug_mutex.unlock();
#endif
              max[t->perm(i)] = (int)-CPX_INFBOUND;
              if (t->share_to[t->perm(i)] != nullptr) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "setting share_to[" << t->perm(i) << "] to inf" << std::endl;
          debug_mutex.unlock();
#endif
                *t->share_to[t->perm(i)] = (int)CPX_INFBOUND;
              }
              if (t->share_limit[t->perm(i)] != nullptr) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "setting limit_to[" << t->perm(i) << "] to inf" << std::endl;
          debug_mutex.unlock();
#endif
                *t->share_limit[t->perm(i)] = (int)CPX_INFBOUND;
              }
            } else {
              min[t->perm(i)] = (int)CPX_INFBOUND;
              if (t->share_to[t->perm(i)] != nullptr) {
                *t->share_to[t->perm(i)] = (int)-CPX_INFBOUND;
              }
              if (t->share_limit[t->perm(i)] != nullptr) {
                *t->share_limit[t->perm(i)] = (int)-CPX_INFBOUND;
              }
            }
          }

          // Reset share_bounds to their limit. First, reset to ±infinity.
            {
              std::unique_lock<std::mutex> lk(lv->status_mutex);
              lv->num_running_threads--;
              if (lv->num_running_threads > 0) {
                if (completed)
                  break;
#ifdef DEBUG_SYNC
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "waiting on lock " << lv << " at " << __LINE__ << std::endl;
          debug_mutex.unlock();
#endif
                lv->cv.wait(lk);
              } else {
                // Last in. Reset the shared_bounds here.
                for(int pre_i = 0; pre_i <= infcnt+1; ++pre_i) {
                  int i = t->perm(pre_i);
                  if (t->share_bounds[i] != nullptr) {
                    if (sense == MIN) {
                      *t->share_bounds[i] = (int)-CPX_INFBOUND;
                    } else {
                      *t->share_bounds[i] = (int)CPX_INFBOUND;
                    }
                  }
                }
                lv->reset_num_running_threads();
#ifdef DEBUG_SYNC
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "releasing on lock " << lv << " at " << __LINE__ << std::endl;
          debug_mutex.unlock();
#endif
                lk.unlock();
                lv->cv.notify_all();
              }
            }
          do {
            {
              std::unique_lock<std::mutex> lk(lv->status_mutex);
              lv->num_running_threads--;
              if (lv->num_running_threads > 0) {
                if (completed)
                  break;
#ifdef DEBUG_SYNC
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "waiting on lock " << lv << " at " << __LINE__ << std::endl;
          debug_mutex.unlock();
#endif
                lv->cv.wait(lk);
              } else {
                // Last in
                lv->changed = false;
                lv->reset_num_running_threads();
#ifdef DEBUG_SYNC
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "releasing on lock " << lv << " at " << __LINE__ << std::endl;
          debug_mutex.unlock();
#endif
                lk.unlock();
                lv->cv.notify_all();
              }
            }
            for (int i = 0; i <= infcnt; ++i) {
              int obj = t->perm(i);
              if (sense == MIN) {
                if (t->share_from[obj] != nullptr) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << " share_from[" << obj << "] is " << *t->share_from[obj] << std::endl;
          debug_mutex.unlock();
#endif
                  if (t->share_limit[obj] != nullptr) {
                    if (*t->share_limit[obj] > *t->share_from[obj]) {
                      lv->changed = true;
                      *t->share_limit[obj] = *t->share_from[obj];
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "setting share_limit[" << obj << "] to " << max[obj] << std::endl;
          debug_mutex.unlock();
#endif
                    }
                  }
                  if (t->share_to[obj] != nullptr) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << " share_to[" << obj << "] is " << *t->share_to[obj] << std::endl;
          debug_mutex.unlock();
#endif
                    if (*t->share_to[obj] > *t->share_from[obj]) {
                      lv->changed = true;
                      *t->share_to[obj] = *t->share_from[obj];
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "setting share_to[" << obj << "] to " << max[obj] << std::endl;
          debug_mutex.unlock();
#endif
                    }
                  }
                }
              } else {
                if (t->share_from[obj] != nullptr) {
                  if (t->share_limit[obj] != nullptr) {
                    if (*t->share_limit[obj] < *t->share_from[obj]) {
                      lv->changed = true;
                      *t->share_limit[obj] = *t->share_from[obj];
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "setting share_limit[" << obj << "] to " << max[obj] << std::endl;
          debug_mutex.unlock();
#endif
                    }
                  }
                  if (t->share_to[obj] != nullptr) {
                    if (*t->share_to[obj] < *t->share_from[obj]) {
                      lv->changed = true;
                      *t->share_to[obj] = *t->share_from[obj];
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "setting share_to[" << obj << "] to " << max[obj] << std::endl;
          debug_mutex.unlock();
#endif
                    }
                  }
                }
              }
            }
            {
              std::unique_lock<std::mutex> lk(lv->status_mutex);
              lv->num_running_threads--;
              if (lv->num_running_threads > 0) {
                if (completed)
                  break;
#ifdef DEBUG_SYNC
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "waiting on lock " << lv << " at " << __LINE__ << std::endl;
          debug_mutex.unlock();
#endif
                lv->cv.wait(lk);
              } else {
                // Last in
                lv->reset_num_running_threads();
                lk.unlock();
#ifdef DEBUG_SYNC
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " ";
          std::cout << "releasing on lock " << lv << " at " << __LINE__ << std::endl;
          debug_mutex.unlock();
#endif
                lv->cv.notify_all();
              }
            }
          } while(lv->changed);
#ifdef DEBUG
          debug_mutex.lock();
          for (int i=0; i < p.objcnt; ++i) {
            std::cout << "Thread " << t->id << " ";
            std::cout << "max[" << i << "] is " << max[i] << std::endl;
          }
          for (int i=0; i < p.objcnt; ++i) {
            std::cout << "Thread " << t->id << " ";
            std::cout << "min[" << i << "] is " << min[i] << std::endl;
          }
          for (int i=0; i < p.objcnt; ++i) {
            if (t->share_bounds[i]) {
              std::cout << "Thread " << t->id << " ";
              std::cout << "share_bounds[" << i << "] is " << *t->share_bounds[i] << std::endl;
            }
          }
          for (int i=0; i < p.objcnt; ++i) {
            if (t->share_from[i]) {
              std::cout << "Thread " << t->id << " ";
              std::cout << "share_from[" << i << "] is " << *t->share_from[i] << std::endl;
            }
          }
          for (int i=0; i < p.objcnt; ++i) {
            if (t->share_limit[i]) {
              std::cout << "Thread " << t->id << " ";
              std::cout << "share_limit[" << i << "] is " << *t->share_limit[i] << std::endl;
            }
          }
          for (int i=0; i < p.objcnt; ++i) {
            std::cout << "Thread " << t->id << " ";
            std::cout << "rhs[" << i << "] is " << rhs[i] << std::endl;
          }
          if (lv->found_any)
            std::cout << "Thread " << t->id << " found_any is true" << std::endl;
          std::cout << "Thread " << t->id << " ";
          std::cout << "synced." << std::endl;
          debug_mutex.unlock();
#endif
        }
      }

      if (sharing && (p.objcnt > 2) && (infcnt == objective_counter) && (infcnt == p.objcnt - 2)) {
        if (t->share_to[t->perm(p.objcnt-1)] == nullptr)
          continue;
#ifdef DEBUG
        debug_mutex.lock();
        std::cout << "Thread " << t->id << " updating bound on " << t->perm(p.objcnt-1);
        std::cout << " to ";
        if (sense == MIN) {
          std::cout << max[t->perm(p.objcnt-1)];
        } else {
          std::cout << min[t->perm(p.objcnt-1)];
        }
        std::cout << std::endl;
        debug_mutex.unlock();
#endif
        if (sense == MIN) {
          *t->share_to[t->perm(p.objcnt-1)] = max[t->perm(p.objcnt-1)];
        } else {
          *t->share_to[t->perm(p.objcnt-1)] = min[t->perm(p.objcnt-1)];
        }
      }
      if (infeasible && (infcnt == objective_counter-1)) {
        if (sharing && (p.objcnt > 2) && (objective_counter == p.objcnt - 1)) {
          if (t->share_to[t->perm(p.objcnt-1)] != nullptr) {
            if (sense == MIN) {
              *t->share_to[objective] = max[objective];
            } else {
              *t->share_to[objective] = min[objective];
            }
          }
        }
        /* Set all constraints back to infinity */
        for (int pre_j = 0; pre_j < p.objcnt; pre_j++) {
          int j  = t->perm(pre_j);
          if ((pre_j < infcnt) || (!sharing) || (t->share_limit[j] == nullptr && t->share_from[j] == nullptr)) {
            if (sense == MIN) {
              rhs[j] = CPX_INFBOUND;
            } else {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "setting rhs[" << j << "] to " << "-inf" << std::endl;
          debug_mutex.unlock();
#endif
              rhs[j] = -CPX_INFBOUND;
            }
          } else {
            int * share_from;
            if (t->share_limit[j] == nullptr)
              share_from = t->share_from[j];
            else
              share_from = t->share_limit[j];
            if (sense == MIN) {
#ifdef DEBUG
              debug_mutex.lock();
              std::cout << "Thread " << t->id << " setting rhs[" << j;
              std::cout << "] to " << (*share_from - 1) << std::endl;
              debug_mutex.unlock();
#endif
              rhs[j] = *share_from - 1;
            } else {
#ifdef DEBUG
              debug_mutex.lock();
              std::cout << "Thread " << t->id << " setting rhs[" << j;
              std::cout << "] to " << (*share_from + 1) << std::endl;
              debug_mutex.unlock();
#endif
              rhs[j] = *share_from + 1;
            }
            if (t->share_to[j] != nullptr) {
              if (sense == MIN) {
                if (*t->share_to[j] > *share_from) {
                  *t->share_to[j] = *share_from;
#ifdef DEBUG
            debug_mutex.lock();
            std::cout << "Thread " << t->id << " setting share_to[" << j;
            std::cout << "] to " << *t->share_to[j] << std::endl;
            debug_mutex.unlock();
#endif
                }
              } else {
                if (*t->share_to[j] < *share_from) {
#ifdef DEBUG
            debug_mutex.lock();
            std::cout << "Thread " << t->id << " changing share_to[" << j;
            std::cout << "] from " << *share_from << " to " << *t->share_to[j] << std::endl;
            debug_mutex.unlock();
#endif
                  *t->share_to[j] = *share_from;
                }
              }
            }
          }
        }
        /* If splitting, use split_start and not +/- infinity */
        if (split) {
          rhs[t->nObj()-1] = t->split_start;
        }
        /* In the case of a minimisation problem
         * set current level to max objective function value  -1 else set
         * current level to min objective function value  +1 */
        if (sense == MIN) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "setting rhs[" << objective << "] to " << max[objective]-1 <<std::endl;
          debug_mutex.unlock();
#endif
          rhs[objective] = max[objective]-1;
          max[objective] = (int) -CPX_INFBOUND;
        } else {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "setting rhs[" << objective << "] to " << (min[objective]+1) << std::endl;
          debug_mutex.unlock();
#endif
          rhs[objective] = min[objective]+1;
          min[objective] = (int) CPX_INFBOUND;
        }

        /* Reset depth */
        depth_level = 1;
        depth = t->perm(depth_level);
        onwalk = false;
      } else if (inflast && infcnt != objective_counter) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "increasing depth from " << depth_level << std::endl;
          debug_mutex.unlock();
#endif
        if (sharing) {
          if (sense == MIN) {
            int * share_from = nullptr;
            if (t->share_limit[depth] != nullptr)
              share_from = t->share_limit[depth];
            else if (t->share_from[depth] != nullptr)
              share_from = t->share_from[depth];
            if (share_from != nullptr)
              rhs[depth] = *share_from - 1;
            else
              rhs[depth] = CPX_INFBOUND;
          } else {
            int * share_from = nullptr;
            if (t->share_limit[depth] != nullptr)
              share_from = t->share_limit[depth];
            else if (t->share_from[depth] != nullptr)
              share_from = t->share_from[depth];
            if (share_from != nullptr) {
#ifdef DEBUG
            debug_mutex.lock();
            std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
            std::cout << "setting rhs[" << depth << "] to " << (*share_from + 1) << std::endl;
            debug_mutex.unlock();
#endif
              rhs[depth] = *share_from + 1;
            } else {
#ifdef DEBUG
            debug_mutex.lock();
            std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
            std::cout << "setting rhs[" << depth << "] to " << -CPX_INFBOUND << std::endl;
            debug_mutex.unlock();
#endif
              rhs[depth] = -CPX_INFBOUND;
            }
          }
        } else {
          if (sense == MIN) {
            rhs[depth] = CPX_INFBOUND;
          } else {
            rhs[depth] = -CPX_INFBOUND;
          }
        }

        depth_level++;
        depth = t->perm(depth_level);
        if (sense == MIN) {
          // Use the shared limit if the shared limit is smaller than max, or
          // if max is infinity, which happens if this thread found nothing
          // last round but another thread did find something.
          if (sharing && t->share_limit[depth] &&
              ((*t->share_limit[depth] < max[depth]) || (max[depth] == (int) -CPX_INFBOUND))) {
#ifdef DEBUG
            debug_mutex.lock();
            std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
            std::cout << "setting rhs[" << depth << "] to " << (*t->share_limit[depth]+1) << std::endl;
            debug_mutex.unlock();
#endif
            rhs[depth] = *t->share_limit[depth] - 1;
          } else {
#ifdef DEBUG
            debug_mutex.lock();
            std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
            std::cout << "setting rhs[" << depth << "] to " << (max[depth]+1) << std::endl;
            debug_mutex.unlock();
#endif
            rhs[depth] = max[depth]-1;
          }
          max[depth] = (int) -CPX_INFBOUND;
        } else {
          if (sharing && t->share_limit[depth] &&
              ((*t->share_limit[depth] > min[depth]) || (min[depth] == (int)CPX_INFBOUND))) {
#ifdef DEBUG
            debug_mutex.lock();
            std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
            std::cout << "setting rhs[" << depth << "] to " << (*t->share_limit[depth]+1) << std::endl;
            debug_mutex.unlock();
#endif
            rhs[depth] = *t->share_limit[depth] + 1;
          } else {
#ifdef DEBUG
            debug_mutex.lock();
            std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
            std::cout << "setting rhs[" << depth << "] to " << (min[depth]+1) << std::endl;
            debug_mutex.unlock();
#endif
            rhs[depth] = min[depth]+1;
          }
          min[depth] = (int) CPX_INFBOUND;
        }
        onwalk = true;
      } else if (!onwalk && infcnt != 1) {
        if (sense == MIN) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "setting rhs[" << depth << "] to " << (max[depth]-1) << std::endl;
          debug_mutex.unlock();
#endif
          rhs[depth] = max[depth]-1;
          max[depth] = (int) -CPX_INFBOUND;
        } else {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "setting rhs[" << depth << "] to " << (min[depth]+1) << std::endl;
          debug_mutex.unlock();
#endif
          rhs[depth] = min[depth]+1;
          min[depth] = (int) CPX_INFBOUND;
        }
      } else if (onwalk && infcnt != 1)  {
        depth_level = 1;
        depth = t->perm(depth_level);
        if (sense == MIN) {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "setting rhs[" << depth << "] to " << -CPX_INFBOUND << std::endl;
          debug_mutex.unlock();
#endif
          rhs[depth] = max[depth]-1;
          max[depth] = (int) -CPX_INFBOUND;
        } else {
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "setting rhs[" << depth << "] to " << -CPX_INFBOUND << std::endl;
          debug_mutex.unlock();
#endif
          rhs[depth] = min[depth]+1;
          min[depth] = (int) CPX_INFBOUND;
        }
        onwalk = false;
      }
    }
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << " at end of loop with objective_counter = ";
          std::cout << objective_counter << std::endl;
          debug_mutex.unlock();
#endif

  }
#ifdef DEBUG
          debug_mutex.lock();
          std::cout << "Thread " << t->id << " at " << __LINE__ << " ";
          std::cout << "done!" << std::endl;
          debug_mutex.unlock();
#endif
  if (sharing) {
    completed = true;
    for(int i = 0; i < p.objcnt; ++i) {
      Locking_Vars *lv = nullptr;
      if (t->locks)
        lv = t->locks[i];
      if (lv != nullptr) {
        {
          std::unique_lock<std::mutex> lk(lv->status_mutex);
        }
        lv->cv.notify_all();
      }
    }
  }
#ifdef FINETIMING
  clock_gettime(CLOCK_MONOTONIC, &start);
  total_time = start.tv_sec + start.tv_nsec/1e9 - total_time;
  std::cout << "Thread " << t->id << " used " << cplex_time << "s in cplex";
  std::cout << ", waited for " << wait_time << "s";
  std::cout << " and " << total_time << "s overall." << std::endl;
#endif
  all.merge(s);
  delete[] resultStore;
  delete[] rhs;
  delete[] min;
  delete[] max;
}

void split_optimise(Problem &p, std::list<int *>& s, int nObj, int max, int min) {
  double start_point, stop_point;
  if (p.objsen == MIN) {
    start_point = max;
    stop_point = min;
  } else {
    start_point = min;
    stop_point = max;
  }
  double split_start = start_point;
  double split_stop;
  double step_size = (stop_point - start_point)/num_threads;
  std::list<Thread *> threads;
  for (int t = 0; t < num_threads; ++t) {
    if (split_normal) {
      double start, stop;
      if (p.objsen == MIN) {
        double gap = (start_point - stop_point);
        stop = normal_values[num_threads][t]*gap + stop_point;
        start = normal_values[num_threads][t+1]*gap + stop_point;
      } else {
        double gap = (stop_point - start_point);
        start = normal_values[num_threads][t]*gap + start_point;
        stop = normal_values[num_threads][t+1]*gap + start_point;
      }
      threads.push_back(new Thread(t, nObj, p.objcnt, start, stop));
    } else {
      split_stop = split_start + step_size;
      threads.push_back(new Thread(t, nObj, p.objcnt, split_start, split_stop));
      split_start = split_stop;
    }
  }
  Solutions here(p.objcnt);
  Solutions infeasibles(p.objcnt);
  std::list<std::thread> threadList;
  if (p.objsen == MIN) {
    for(Thread* thread: threads) {
      threadList.emplace_back(optimise<MIN>, p.filename(),
          std::ref(here), std::ref(infeasibles), thread);
    }
  } else {
    for(Thread* & thread: threads) {
      threadList.emplace_back(optimise<MAX>, p.filename(),
          std::ref(here), std::ref(infeasibles), thread);
    }
  }
  for (auto& thread: threadList)
    thread.join();
  for(auto sol: here) {
    if (sol->infeasible)
      continue;
    int * n = new int[p.objcnt];
    for(int i = 0; i < p.objcnt; ++i) {
      n[i] = sol->result[i];
    }
    s.push_back(n);
  }
}

void split_setup(Env &e, Problem &p, std::list<int *> &s, int nObj) {
  if (nObj == 1) {
    int *min = new int[p.objcnt];
    get_limit(e, p, nObj - 1, p.rhs, min, p.objsen);
    s.push_back(min);
  } else {
#ifdef DEBUG
    std::cout << "Splitting on " << nObj << " objectives ... ";
#endif
    std::list<int *> sols;
    split_setup(e, p, sols, nObj - 1);
    int * res = new int[p.objcnt];
    int biggest, smallest;
    if (p.objsen == MIN) {
      get_limit(e, p, nObj-1, p.rhs, res, p.objsen);
      smallest = res[nObj - 1];
      biggest = (int)-CPX_INFBOUND;
      for(int * sol: sols) {
        if (sol[nObj-1] > biggest) {
          biggest = sol[nObj-1];
        }
      }
      if (biggest == smallest) {
        biggest = (int)CPX_INFBOUND;
      }
    } else {
      get_limit(e, p, nObj-1, p.rhs, res, p.objsen);
      biggest = res[nObj - 1];
      smallest = (int)CPX_INFBOUND;
      for(int * sol: sols) {
        if (sol[nObj-1] < smallest) {
          smallest = sol[nObj-1];
        }
      }
      if (biggest == smallest) {
        smallest = (int)-CPX_INFBOUND;
      }
    }
    delete[] res;
#ifdef DEBUG
    std::cout << " found range [" << smallest << ", " << biggest << "]";
    std::cout << " for objective " << (nObj-1) << std::endl;
#endif
    split_optimise(p, s, nObj, biggest, smallest);
  }
}