text:
#include "../include/ParameterPopulation.h"
#include "../include/io_functions.h"
#include "../include/constants.h"

using namespace std;

////////////////////////////// Helper functions ///////////////////////////////

inline bool
floatsDiffer(const double & x, const double & y)
{
  return (abs(x - y) / (abs(x + y + 1.0)) > 1.0e-9);
}

inline double
randomParamValue(const ParameterDescription & param, RandGen & r)
{
  // return a random value consistant with the ranges and type of the parameter
  //  description, using random number generator r
  switch(param.type()) {
    case ParameterDescription::Constant:
      return param.defaultValue();
    case ParameterDescription::LogDistributed:
      return param.minRange * pow(param.maxRange / param.minRange,
                                  r.openUniform());
    case ParameterDescription::UniformDistributed:
      return param.minRange + (param.maxRange - param.minRange) *
                              r.openUniform();
    case ParameterDescription::Invalid:
    default:
      throw ParameterPopulationException("Invalid parameter ranges for " +
                                         param.name);
      return NaN;
  }
}

inline bool
compatible(const ParameterDescription & pd1,
           const ParameterDescription & pd2)
{
  // check if two parameter descriptions are compatible (i.e. one could
  // plausibly be from start-up, and the other from resuming

  // the names must be the same
  if(pd1.name != pd2.name) {
    cout << pd1.name << " != " << pd2.name << '\n';
    cout.flush();
    return false;
  }

  // the types must be the same
  if(pd1.type() != pd2.type()) {
    cout << "incompatible desc types\n"; cout.flush();
    return false;
  }

  if(pd1.type() == ParameterDescription::Constant) {
    if(floatsDiffer(pd1.defaultValue(), pd2.defaultValue())) {
        cout << "incompatible const\n"; cout.flush();
        cout << pd1 << '\n' << pd2 << '\n'; cout.flush();
      return false;
    }
  }
  else {
    if(floatsDiffer(pd1.minAllowed, pd2.minAllowed) ||
       floatsDiffer(pd1.maxAllowed, pd2.maxAllowed)) {
      // the min and max allowed values must be the same
      cout << "incompatible ranges\n"; cout.flush();
      cout << pd1 << '\n' << pd2 << '\n'; cout.flush();
      return false;
    }
  }

  // the ranges don't have to be the same, since that changes during fitting
  return true;
}

inline bool
compatible(const ParameterDescriptionList & pdlResume,
           const ParameterDescriptionList & pdlStartup)
{
  // check if two parameter description lists are compatible (i.e. one could
  // plausibly be from start-up, and the other from resuming

  // Check if they have the same length. The resume description may be longer
  // due to added state descriptions
  if(pdlResume.size() < pdlStartup.size()) {
    cout << "incompatible pdl sizes\n"; cout.flush();
    return false;
  }

  // loop through parameter descriptions and check if any of them are
  // incompatible. Loop over the startup descriptions
  ParameterDescriptionList::const_iterator pdItr1 = pdlStartup.begin();
  const ParameterDescriptionList::const_iterator end1 = pdlStartup.end();
  ParameterDescriptionList::const_iterator pdItr2 = pdlResume.begin();
  for(; pdItr1 != end1; ++pdItr1, ++pdItr2)
    if(!compatible(*pdItr1, *pdItr2)) {
      cout << "incompatible pds\n"; cout.flush();
      return false;
    }

  // All parameter descriptions compatible, so the lists are compatible
  return true;
}

inline void
jumpPastComment(istream & in)
{
  string dummy;
  while(in.good()) {
    switch(in.peek()) {
      case ' ':
      case '\t':
      case '\n':
        // ignore white-space
        in.ignore(1);
        break;

      case '#':
        // comment, remove rest of line
        getline(in, dummy);
        break;

      default:
        // non-comment, non-white-space
        return;
    }
  }
}

inline size_t
getSize(istream & in)
{
  // get a non-empty, non-comment line and read in a size_t

  string line, rawLine;
  SplitLine splitLine;
  while(splitLine.empty()) {
    if(in.bad())
      throw ParameterPopulationException("Error reading size from stream");

    getline(in, line);
    rawLine = line;
    in.peek();  //peek helps trip eof flag

      // look for comment
    size_t commentInd = line.find('#');
    if(commentInd != std::string::npos) {
      // remove everything after comment
      line.erase(commentInd);
    }

    if(line.empty())
      // empty line or just space
      continue;

    // split line up into words
    splitLine = split(line);
    if(splitLine.empty())
      // just empty space on line
      continue;
  }

  // should be just one element in line (the size_t)
  if(splitLine.size() != 1)
    throw ParameterPopulationException("Bad line reading ParameterPopulation: "
                                       + rawLine);

  // convert line to size_t
  return stringToSize(splitLine[0]);
}

inline size_t
numWordsInNextLine(istream & in)
{
  // compute the number of words left in the next line, but leave in unchanged

  // get the starting position of in stream
  streampos startPos = in.tellg();

  // read in the next line
  string line;
  getline(in, line);
  // split it into words
  SplitLine splitLine = split(line);
  // compute the number of words
  size_t numWords = splitLine.size();

  // rewind to starting position
  in.seekg(startPos, ios::beg);

  return numWords;
}

double
maxDistance(const ParameterSet & pS1, const ParameterSet & pS2,
            const ParameterDescriptionList & pDList)
{
  double maxDist = 0.0;
  for(size_t n = 0; n < pDList.size(); ++n) {
    switch(pDList[n].type()) {
      case ParameterDescription::UniformDistributed:
        maxDist = std::max( maxDist, abs(pS1.parameters[n] -
                                         pS2.parameters[n]) );
        break;

      case ParameterDescription::LogDistributed:
        maxDist = std::max( maxDist, abs(log(pS1.parameters[n] /
                                             pS2.parameters[n])) );
        break;

      default:
        ;
    }
  }
  return maxDist;
}

template <class T>
inline T
square(const T & x)
{
  return x*x;
}

inline double
pDistance(const ParameterSet & p1, const ParameterSet & p2,
          const ParameterDescriptionList & parameterDescriptions)
{
  double d = 0.0;
  auto p1Itr = p1.parameters.cbegin();
  auto p2Itr = p2.parameters.cbegin();
  for(const auto & desc : parameterDescriptions) {
    switch(desc.type()) {
      case ParameterDescription::LogDistributed:
        d += square(log(*p1Itr / *p2Itr));
        break;
      case ParameterDescription::UniformDistributed:
        d += square(*p1Itr - *p2Itr);
        break;
      default:
        ;
    }
    ++p1Itr;
    ++p2Itr;
  }
  return d;
}

///////////////////// GenerationSummary member functions //////////////////////
GenerationSummary::GenerationSummary(const ParameterSet & paramSet,
                                     const Timer & genTime,
                                     const Timer & totTime,
                                     const double & f,
                                     const double & logRange,
                                     const double & uniformRange) :
  fRange (f), maxLogRange (logRange), maxUniformRange (uniformRange)
{
  // assign bestParameters
  bestParameters = paramSet;

  // assign generationTime by:
  stringstream ssGen;
  //   -writing genTime's elapsed time to a stringstream
  ssGen << genTime;
  //   -saving as a string
  generationTime = ssGen.str();

  // similarly assing totalTime:
  stringstream ssTot;
  //   -writing genTime's elapsed time to a stringstream
  ssTot << totTime;
  //   -saving as a string
  totalTime = ssTot.str();
}

///////////////////// GenerationSummary friend functions //////////////////////
ostream &
operator<<(ostream & out, const GenerationSummary & genSum)
{
    // record format flags
  const ios_base::fmtflags formatFlags = out.flags();
  // record width;
  const streamsize width = out.width();
  // record precision
  const streamsize precision = out.precision();

  // calculate a few widths to ensure all the significant info in the double
  //  is output
  const streamsize doublePrecision = numeric_limits<double>::digits10 + 1;
  const streamsize expWidth = (streamsize)ceil(
    log10((double)numeric_limits<double>::max_exponent10));
  const streamsize doubleWidth = doublePrecision + expWidth + 4;

  // output the summary
  //   -output the two time strings
  out.width(24);
  out << left << genSum.generationTime;
  out.width(24);
  out << left << genSum.totalTime;

  //   -output the range descriptions
  //      -set output decimal precision
  out.precision(doublePrecision);
  // set to default-style output
  out.unsetf(ios_base::floatfield);

  //      -output fRange, maxLogRange, maxUniformRange
  out.width(doubleWidth);
  out << left << genSum.fRange;
  out.width(doubleWidth);
  out << left << genSum.maxLogRange;
  out.width(doubleWidth);
  out << left << genSum.maxUniformRange;

  //   -output the best parameter set
  out << genSum.bestParameters;

  // restore flags
  out.setf(formatFlags);
  // restore width
  out.width(width);
  // restore precision
  out.precision(precision);

  return out;
}

istream &
operator>>(istream & in, GenerationSummary & genSum)
{
  // skip whitespace
  in >> ws;
  // get the generation time (which ends in 's')
  getline(in, genSum.generationTime, 's');
  // the 's' is discarded by getline, so append it to the end
  genSum.generationTime += 's';

  // skip whitespace
  in >> ws;
  // get the total time (which ends in 's')
  getline(in, genSum.totalTime, 's');
  // the 's' is discarded by getline, so append it to the end
  genSum.totalTime += 's';

  // older versions of ParameterPopulation don't output fRange, maxLogRange,
  // maxUniformRange. To distinguish this, count the number of words left on
  // the line
  const size_t numWords = numWordsInNextLine(in);
  const size_t paramSize = 1 + genSum.bestParameters.parameters.size();
  if(numWords == paramSize) {
    // didn't output the range values
    genSum.fRange = NaN;
    genSum.maxLogRange = NaN;
    genSum.maxUniformRange = NaN;
  }
  else if(numWords == paramSize + 3) {
    // output the range values
    genSum.fRange = getDouble(in);
    genSum.maxLogRange = getDouble(in);
    genSum.maxUniformRange = getDouble(in);
  }
  else {
    // line is corrupted
    throw ParameterPopulationException("Invalid parameter history line");
  }

  // get the best parameters for this generation
  in >> genSum.bestParameters;

  return in;
}

///////////////// ParameterPopulation public member functions /////////////////

ParameterPopulation::ParameterPopulation(void)
{
  // initializing public values, these can be changed as convenient:
  logToDisk = true;
  logToTerminal = true;
  resumeFileName = "resume.txt";
  resultsFileName = "results.txt";

  tol = 1.0e-3;
  fTol = 1.0e-4;
  maxGenerationNum = 10000;
  maxDiffScale = 0.5;

  // initializing protected / public values, don't edit these:
  generationNum = 1;
  numEvaluations = 0;
  numGenEvaluations = 0;
  generationSize = 0;
  bestParameters.value = Inf;

  initialized = false;
  clean = false;
  resumed = false;
  optimal = false;
}

ParameterPopulation::~ParameterPopulation(void)
{
  cleanup();
}

void ParameterPopulation::geneticAlgorithm(void)
{
  // optimize population with genetic algorithm

  // start the overall timer
  totalTime.start();
  // initialize (load in parameter descriptions, derived-class data, etc)
  initialize();

  // this can't work with population size < 3
  if(populationSize < 3)
    throw ParameterPopulationException("Population size must be >= 3");

  if(generationSize == 0)
    generationSize = populationSize;

 maxGenerationNum = 1000 * parameterDescriptions.numFitParameters();

  try {
    // try to resume
    resume();
    if(resumed) {
      // resume a previous session

      if(numGenEvaluations >= populationSize) {
        // stopped after previous generation was complete, so start a new
        // generation
        numGenEvaluations = 0;
        if(generationNum == generationHistory.size())
          ++generationNum;
        // start generation timer
        generationTime.start();
      }
      // don't need to start generationTime generation is in progress so,
      // it's already started
    }
    else {
      // start a new session

      optimal = false;
      numEvaluations = 0;
      numGenEvaluations = 0;
      // start generation timer
      generationTime.start();
    }

    // make sure we have the parameter descriptions
    if(parameterDescriptions.size() == 0)
      throw ParameterPopulationException("No parameter descriptions loaded");

    // make sure the population size has been set
    if(populationSize == 0)
      throw ParameterPopulationException("Population size not set");

    // evaluate the first generation of THIS session
    evaluateGeneration();

    // continue until optimal (or interrupted)
    while(!optimal) {
      // start the timer for this generation
      generationTime.start();
      ++generationNum;

      // evaluate the population, indicate progress
      evaluateGeneration();
    }
  }
  catch(exception & e) {
    // best to quit without saving, because the state may be messed up
    // (also if signal is caught during evaluateGeneration(), progress will be
    // saved)
    cout << e.what() << '\n';
    cout.flush();
    // try to clean up before exit
    cleanup();
    // rethrow the exception
    exit(0);
    throw;
  }
}

const size_t &
ParameterPopulation::getGenerationNum(void) const
{
  return generationNum;
}

const size_t &
ParameterPopulation::getPopulationSize(void) const
{
  return populationSize;
}

const size_t &
ParameterPopulation::getNumEvaluations(void) const
{
  return numEvaluations;
}

const size_t &
ParameterPopulation::getNumGenEvaluations(void) const
{
  return numGenEvaluations;
}

const ParameterSet &
ParameterPopulation::getBestParameters(void) const
{
  return bestParameters;
}

void
ParameterPopulation::setParameterDescriptions(
                            const ParameterDescriptionList & paramDescriptions)
{
  // copy in the new list of parameter descriptions
  parameterDescriptions = paramDescriptions;

  // resize bestParameters
  bestParameters.parameters.resize(parameterDescriptions.size());
}

void
ParameterPopulation::setPopulationSize(const size_t & newPopulationSize)
{
  // set maximum population size, and reserve memory
  populationSize = newPopulationSize;

  if(population.size() <= populationSize)
    population.reserve(populationSize);
  else
    population.resize(populationSize);
}

//////////////////// ParameterPopulation friend functions /////////////////////

ostream &
operator<<(ostream & out, const ParameterPopulation & paramPop)
{
  // write out the list of parameter descriptions
  out << paramPop.parameterDescriptions;

  // write out the best parameters
  out << "# Current best parameters:\n";
  out << paramPop.bestParameters << '\n';

  // write out the timers
  out << "# Total time:\n";
  out << paramPop.totalTime << '\n';
  out << "# Current generation time:\n";
  out << paramPop.generationTime << '\n' << '\n';

  // write out the number of evaluations
  out << paramPop.numEvaluations << " # number of parameter sets evaluated\n";
  // write out the number of evaluations in this generation
  out << paramPop.numGenEvaluations
      << " # number of evaluations this generation\n";
  // write out the generation number
  out << paramPop.generationNum << " # current generation number\n\n";

  // write out the size of the generation history
  out << paramPop.generationHistory.size() << " # generation history\n";

  // write out the history of generation summaries
  for(const auto & genHist : paramPop.generationHistory)
    out << genHist;
  out << '\n';

  // write out the current population size
  out << paramPop.population.size() << " # population\n";

  // write out the members of the population
  for(const auto & pSet : paramPop.population)
    out << pSet;

  return out;
}

istream &
operator>>(istream & in, ParameterPopulation & paramPop)
{
  // read in the list of parameter descriptions
  ParameterDescriptionList resumeDescriptions;
  in >> resumeDescriptions;
  if(paramPop.parameterDescriptions.empty())
    // no existing parameter descriptions, so set them to the resume
    // descriptions
    paramPop.setParameterDescriptions(resumeDescriptions);
  if( compatible(resumeDescriptions, paramPop.parameterDescriptions) )
    // have parameter descriptions read in from start up that are compatible
    // with the resume descriptions. The resume descriptions are a refinement
    // due to fitting, so use them
    paramPop.parameterDescriptions = resumeDescriptions;
  else
    // inconsistent parameter descriptions
    throw ParameterPopulationException("Parameter descriptions in resume file "
                                       "are inconsistent with start up");

  // read in the best parameters
  jumpPastComment(in);
  in >> paramPop.bestParameters;

  // read in the timers
  jumpPastComment(in);
  in >> paramPop.totalTime;
  jumpPastComment(in);
  in >> paramPop.generationTime;

  // read in the number of evaluations
  paramPop.numEvaluations = getSize(in);
  jumpPastComment(in);
  // read in the number of evaluations this generation
  paramPop.numGenEvaluations = getSize(in);
  jumpPastComment(in);
  // read in the generation number
  paramPop.generationNum = getSize(in);

  // read in the size of the the generation history
  jumpPastComment(in);
  size_t len = getSize(in);
  paramPop.generationHistory.resize(len);

  // read in the history of best parameters
  jumpPastComment(in);
  const size_t numParams = paramPop.bestParameters.parameters.size();
  for(auto & genHist : paramPop.generationHistory) {
    genHist.bestParameters.parameters.resize(numParams);
    in >> genHist;
  }

  // read in the population size
  len = getSize(in);
  if(paramPop.populationSize == 0)
    // population not already resized
    paramPop.setPopulationSize(len);

  const size_t numRead = std::min(len, paramPop.populationSize);

  paramPop.population.resize(numRead);

  // read in the members of the population
  jumpPastComment(in);
  for(auto & pSet : paramPop.population) {
    pSet.parameters.resize(numParams);
    in >> pSet;
  }

  return in;
}

/////////////// ParameterPopulation protected member functions ////////////////

void
ParameterPopulation::evaluateGeneration(void)
{
  // Once-per-generation evaluation function:
  //   -evaluate the parameter population
  //   -maintain bestParameters and history,
  //   -test for optimality
  //   -save progress
  //   -spit out progress indicator

  try {
    signalHandler.check();  // throw exception if signal caught

    // evaluate the population (derived-class specific function)
    evaluatePopulation();

    // sort the population to be in order from best to worst
    signalHandler.check();  // throw exception if signal caught

    // test to see if this generation has achieved optimality
    //   (set this->optimal = true)
    testOptimal();

    // save history of this generation
    saveHistory();

    // save progress
    signalHandler.check();  // throw exception if signal caught
    saveProgress();
  }
  catch(SignalException & sigExcept) {
    // signal caught, save progress before quitting
    saveProgress();
    // try to clean up
    cleanup();
    // re-throw the exception
    throw;
  }
  catch(exception & e) {
    // some other exception, just try to clean up
    cleanup();
    // re-throw the exception
    throw;
  }

  // print out progress indicator
  summarizeGeneration(generationNum);
}

void
ParameterPopulation::randomPSet(ParameterSet & pSet, RandGen & randGen) const
{
  // randomly generate a parameter set consistent with parameter descriptions

  // set value to NaN (flag that it needs to be evaluated)
  pSet.value = NaN;
  pSet.diffScale = maxDiffScale;

  // loop through different parameters within pSet, assign random values
  auto paramDescriptionItr = parameterDescriptions.cbegin();
  for(double & paramVal : pSet.parameters) {
    // assign the parameter a random value within range
    paramVal = randomParamValue(*paramDescriptionItr, randGen);
    ++paramDescriptionItr;
  }
}

void
ParameterPopulation::appendIn(ParameterSet & newPSet)
{
  // Append in a newly evaluated parameter set into the population, keeping the
  // population ordered in increasing value.
  // Increase the population size by 1.

  if(population.empty()) {
    // this is the first parameter set
    population.push_back(newPSet);
    setBestParameters(newPSet);
    return;
  }
  // Add copy of parameter set to population
  population.push_back(newPSet);

  // make iterator to newly added pSet
  auto oldPSetItr1 = population.rbegin();
  auto oldPSetItr2 = oldPSetItr1;
  // keep swapping until the parameter sets are in value order
  for(++oldPSetItr2; oldPSetItr2 != population.rend(); ++oldPSetItr2) {
    if(oldPSetItr1->value >= oldPSetItr2->value)
      break;
    // swap parameter sets
    oldPSetItr2->swap(*oldPSetItr1);
    ++oldPSetItr1;
  }

  // Swapped all the way to the front, the new set is the best ParameterSet
  if(oldPSetItr2 == population.rend())
    setBestParameters(*oldPSetItr1);
}

void
ParameterPopulation::swapIn(ParameterSet & newPSet)
{
  // Swap in a newly evaluated parameter set into the population, keeping the
  // population ordered in increasing value.
  // Kicking out the worst parameterSet, keeping the population size constant.

  // Form iterator to worst existing member of the population
  auto oldPSetItr1 = population.rbegin();
  if(newPSet.value >= oldPSetItr1->value)
    // newPSet isn't good enough to join the population
    return;

  // swap the worst parameter set out, and the new one in
  std::swap(newPSet, *oldPSetItr1);
  //newPSet.swap(*oldPSetItr1);

  // keep swapping until the parameter sets are in value order
  auto oldPSetItr2 = oldPSetItr1;
  for(++oldPSetItr2; oldPSetItr2 != population.rend(); ++oldPSetItr2) {
    if(oldPSetItr1->value >= oldPSetItr2->value)
      break;
    // swap parameter sets
    std::swap(*oldPSetItr2, *oldPSetItr1);
    //oldPSetItr2->swap(*oldPSetItr1);
    ++oldPSetItr1;
  }

  // Swapped all the way to the front, the new set is the best ParameterSet
  if(oldPSetItr2 == population.rend())
    setBestParameters(*oldPSetItr1);
}

void
ParameterPopulation::differentialCross(ParameterSet & pSet, RandGen & randGen)
  const
{
  // produce a new member of the population by using a differential crossover
  //   -three parents chosen from breeding population
  //   -parent1 more fit than parent2
  //      -an improvement direction vector obtained from parent1 - parent2
  //      -this vector is scaled by a random uniform number "diffScale"
  //   -parent3 is a starting location updated by improvement vector
  //      -for uniform parameters update as:
  //         child = parent3 + diffScale * (parent1 - parent2)
  //      -for logarithmic parameters update as:
  //         child = parent3 * pow(parent1 / parent2, diffScale)

  // assign the new pSet an undefined value
  pSet.value = NaN;

  // get the three parents from the breeding population (weighted
  // preferentially to better fitness), chosen so that ind1 < ind2 (swap if
  // necessary), implying that the fitness of parent1 is better than the
  // fitness of parent2
  //   -pick ind2 using cutoff-1 and ind3 using cutoff-2 because we're
  //    excluding the possibility of any of the indices matching

  // Randomly draw indices to three members of the population
  size_t ind1, ind2, ind3;
  get3ParentInds(ind1, ind2, ind3, randGen);

  // get progenitors from the population, via the indices
  const ParameterSet & parent1 = population[ind1];
  const ParameterSet & parent2 = population[ind2];
  const ParameterSet & parent3 = population[ind3];

  // throw a uniform random number to scale the differential cross
  static const double minDiffScale = 0.01;
  /*
  static const double maxDiffScale2 = log(5.0) /
    log((double)parameterDescriptions.numFitParameters() + 1.0);
  */
  //static const double maxDiffScale2 = 12.0 /
  //  ((double)parameterDescriptions.numFitRegularParameters() + 2.0);
  static const double maxDiffScale2 = 0.5;

  const size_t compInd = ind3 == 0 ? 1 :
    (size_t) round( 0.1 * (double) ind3 );
  const double & compVal = population[compInd].value;
  const double valueFact =
    abs( (parent3.value - compVal) / (parent2.value - parent1.value) );
  const double diffScale = std::min(std::max(
    pow( 2.0, -1.0 + 2.0 * randGen.openUniform() ) * valueFact,
    minDiffScale
  ), maxDiffScale2);

  //static const double diffRange = maxDiffScale2 - minDiffScale;
  //const double diffScale = minDiffScale + diffRange * randGen.openUniform();

  pSet.diffScale = diffScale;

  // loop over each parameter, computing new value via differential crossover
  auto p1Itr = parent1.parameters.cbegin();
  auto p2Itr = parent2.parameters.cbegin();
  auto p3Itr = parent3.parameters.cbegin();
  auto paramDescriptionItr = parameterDescriptions.cbegin();
  for(auto & newParamVal : pSet.parameters) {
    switch(paramDescriptionItr->type()) {
      case ParameterDescription::Constant:
        // this parameter is constant, set to only allowed value
        newParamVal = paramDescriptionItr->maxAllowed;
        break;

      case ParameterDescription::LogDistributed:
        // use logarithmic differential crossover
        newParamVal = *p3Itr * pow(*p1Itr / *p2Itr, diffScale);

        // ensure newParamVal is in bounds
        if(newParamVal < paramDescriptionItr->minAllowed)
          newParamVal = paramDescriptionItr->minAllowed;
        else if(!(newParamVal <= paramDescriptionItr->maxAllowed))
          newParamVal = paramDescriptionItr->maxAllowed;
        break;

      case ParameterDescription::UniformDistributed:
        // use linear differential crossover
        newParamVal = *p3Itr + diffScale * (*p1Itr - *p2Itr);

        // ensure newParamVal is in bounds
        if(newParamVal < paramDescriptionItr->minAllowed)
          newParamVal = paramDescriptionItr->minAllowed;
        else if(!(newParamVal <= paramDescriptionItr->maxAllowed))
          newParamVal = paramDescriptionItr->maxAllowed;
        break;

      case ParameterDescription::Invalid:
      default:
        throw ParameterPopulationException("Invalid parameter \"" +
                                           paramDescriptionItr->name + "\"");
    }

    ++p1Itr;
    ++p2Itr;
    ++p3Itr;
    ++paramDescriptionItr;
  }
}

#ifdef USE_EXPERIMENTAL_CROSS
#include <Eigen/Eigenvalues>
using namespace Eigen;
void
ParameterPopulation::experimentalCross(ParameterSet & pSet, RandGen & randGen)
  const
{
  // try to implement stochastic quadratic optimizer

  const size_t numFitParameters = parameterDescriptions.numFitParameters();
  // How many parameter sets needed to exactly specify quadratic fit?
  // numQuad = numSecondDerivs + numFirstDerivs + 1
  //         = numHessian + numFitParameters + 1
  //         = numFitP * (NumFitP + 1) / 2 + numFitP + 1
  const size_t numQuad = (numFitParameters + 1) * (numFitParameters + 2) / 2;
  const size_t numExtra = 2; // max(2, 0.1 * numFitParameters)
  const size_t numParents = numQuad + numExtra;
  //const size_t numParents = min(numQuad + numExtra, (size_t)10);

  // Form list of numParents randomly-chosen parameter indices
  // redo this to use set?
  vector<size_t> parentInds (numParents);
  getNParentInds(parentInds, numParents, randGen);

  // 1. Find the best parent, then
  // 2. Fill out a matrix of parameter differences between the remaining parents
  //    and the best parent
  // 3. Fill out a vector of value differences between the remaining parents and
  //    the best parent
  // quadraticMinDataMatric = paramVecs - bestParamVec
  // quadraticMinDataVector = paramVals - bestParamVal
  quadraticMinDataMatrix.resize(numParents-1, numFitParameters);
  quadraticMinDataVector.resize(numParents-1);
  fillQuadraticMinData(parentInds);

  // Fill out a series of equations describing a quadratic fit to the
  //   quadraticMinData
  // Form a (numParents-1) x (numQuad-1) matrix (quadraticFitMatrix) where:
  //   -each row corresponds to a parameter difference from quadraticMinData
  //   -the first numFitParams columns are the data in quadraticMinDataMatrix
  //   -the next numHessian columns are quadratic combinations of this data
  //      e.g. minDataMat(column1) * minDataMat(column7)
  // Then quadraticFitMatrix * quadraticCombinedCoefs = quadraticMinDataVector
  //   is a forumula specifying coefficients for a quadratic fit to the parents
  quadraticFitMatrix.resize(numParents-1, numQuad-1);
  fillQuadraticFitMatrix();

  // Solve those equations to compute the coefficients of the quadratic fit
  // 1. Solve for quadraticCombinedCoefs:
  //    quadraticFitMatrix * quadraticCombinedCoefs = quadraticMinDataVector
  // 2. Break quadratic combined coefs into a matrix, so that for an arbitrary
  //    deviation from the bestParent dP, the change in value dV is:
  //    dV = dP' * quadCoefsMat * dP - 2 * quadCoefsVec * dP
  quadraticCombinedCoefs.resize(numQuad-1);
  quadraticCoefficientsMatrix.resize(numFitParameters, numFitParameters);
  quadraticCoefficientsVector.resize(numFitParameters);
  computeQuadraticFitCoefficients();

  // find reglarized "minimum" from quadraticFitCoefficients
  // Since dV = dP' * quadCoefsMat * dP - 2 * quadCoefsVec * dP,
  //  the unregularized extremum/saddlepoint is found by taking dV/dP = 0:
  //  minDP = quadCoefsMat^-1 * quadCoefsVec
  // Function is more complex because we need to regularize and guarantee
  // "minimum" (or at least decrease in value)
  quadExtremum.resize(numFitParameters);
  solveQuadraticFit();

  // quadExtremum now holds information about how to alter best parent pSet
  //   to get to minimum. Fill out a new pSet from that info
  fillPSetFromQuadraticFit(pSet, parentInds[0]);
}

inline void
ParameterPopulation::fillQuadraticMinData(const vector<size_t> & parentInds)
  const
{
  // Fill out a matrix of differences between randomly chosen parameters and
  //   the best pSet among them

  // the best (lowest value) parentInd is at the beginning of the vector
  const size_t minInd = parentInds[0];

  // 2. Fill out a matrix of parameter differences between the remaining parents
  //    and the best parent
  // 3. Fill out a vector of value differences between the remaining parents and
  //    the best parent
  // quadraticMinDataMatric = paramVecs - bestParamVec
  // quadraticMinDataVector = paramVals - bestParamVal
  const auto & minPSet = population[minInd];
  size_t row = 0;
  for(const size_t & ind : parentInds) {
    if(ind == minInd) {
      continue;
    }
    const auto & diffPSet = population[ind];
    size_t col = 0;
    for(size_t paramNum = 0; paramNum < minPSet.parameters.size(); ++paramNum){
      if(parameterDescriptions[paramNum].isConstant()) {
        continue;
      }
      else if(parameterDescriptions[paramNum].isLogDistributed()) {
        quadraticMinDataMatrix(row,col) =
          log(diffPSet.parameters[paramNum] / minPSet.parameters[paramNum]);
      }
      else {
        quadraticMinDataMatrix(row,col) =
          diffPSet.parameters[paramNum] - minPSet.parameters[paramNum];
      }
      ++col;
    }
    quadraticMinDataVector(row) = diffPSet.value - minPSet.value;
    ++row;
  }
}

inline void
ParameterPopulation::fillQuadraticFitMatrix(void) const
{
  // Fill out a series of equations describing a quadratic fit to the
  //   quadraticMinData

  // Form a (numParents-1) x (numQuad-1) matrix (quadraticFitMatrix) where:
  //   -each row corresponds to a parameter difference from quadraticMinData
  //   -the first numFitParams columns are the data in quadraticMinDataMatrix
  //   -the next numHessian columns are quadratic combinations of this data
  //      e.g. minDataMat(column1) * minDataMat(column7)
  // Then quadraticFitMatrix * quadCoefs = quadraticMinDataVector is a forumula
  //   specifying coefficients for a quadratic fit to the parents
  const size_t numFitParameters = parameterDescriptions.numFitParameters();
  for(size_t row = 0; row < (size_t)quadraticFitMatrix.rows(); ++row) {
    size_t col = 0;
    for(size_t dataCol = 0; dataCol < numFitParameters; ++dataCol, ++col) {
      quadraticFitMatrix(row, col) = quadraticMinDataMatrix(row, dataCol);
    }
    for(size_t dataCol1 = 0; dataCol1 < numFitParameters; ++dataCol1) {
      for(size_t dataCol2 = dataCol1;
          dataCol2 < numFitParameters;
          ++dataCol2, ++col) {
        quadraticFitMatrix(row, col) = quadraticMinDataMatrix(row, dataCol1)
                                     * quadraticMinDataMatrix(row, dataCol2);
      }
    }
  }
}

inline void
ParameterPopulation::computeQuadraticFitCoefficients(void) const
{
  // Solve equations to compute the coefficients of the quadratic fit
  // 1. Solve for quadraticCombinedCoefs:
  //    quadraticFitMatrix * quadraticCombinedCoefs = quadraticMinDataVector
  quadraticCombinedCoefs
    = quadraticFitMatrix.jacobiSvd(ComputeThinU | ComputeThinV).solve(quadraticMinDataVector);

  // 2. Break quadratic combined coefs into a matrix, so that for an arbitrary
  //    deviation from the bestParent dP, the change in value dV is:
  //    dV = dP' * quadCoefsMat * dP - 2 * quadCoefsVec * dP
  size_t vecInd;
  const size_t numFitParameters = parameterDescriptions.numFitParameters();
  for(vecInd = 0; vecInd < numFitParameters; ++vecInd) {
    // factor of -0.5 because we want dV ~ -2 * quadCoefsVec * dP, but
    //  dV ~ quadCombinedCoefs * dV
    quadraticCoefficientsVector[vecInd] = -0.5 * quadraticCombinedCoefs[vecInd];
  }
  for(size_t row = 0; row < numFitParameters; ++row) {
    quadraticCoefficientsMatrix(row,row) = quadraticCombinedCoefs[vecInd];
    ++vecInd;
    for(size_t col = row + 1; col < numFitParameters; ++col, ++vecInd) {
      // factor of +0.5 because dV ~ dP' * quadCoefsMat * dP, but that
      // counts each off-diagonal product twice (top and bottom triangle),
      // whereas quadraticCombinedCoefs counts each product once
      quadraticCoefficientsMatrix(row,col)
        = 0.5 * quadraticCombinedCoefs[vecInd];
      quadraticCoefficientsMatrix(col,row)
        = quadraticCoefficientsMatrix(row,col);
    }
  }
}

inline void
ParameterPopulation::solveQuadraticFit(void) const
{
  // find reglarized "minimum" from quadraticFitCoefficients
  // Since dV = dP' * quadCoefsMat * dP - 2 * quadCoefsVec * dP,
  //  the unregularized extremum/saddlepoint is found by taking dV/dP = 0:
  //  minDP = quadCoefsMat^-1 * quadCoefsVec
  // This function is more complicated because we need to regularize and
  // guarantee "minimum" (or at least decrease in value)

  // quadraticFitCoefficientsMatrix is real, symmetric, so can diagonalize:
  SelfAdjointEigenSolver<MatrixXd> es (quadraticCoefficientsMatrix);
  // now:
  // quadraticFitCoefficientsMatrix == es.eigenvectors()
  //                                 * es.eigenvalues().asDiagonal()
  //                                 * es.eigenvectors.transpose()
  // so the unregularized extremum is at:
  // ex = es.eigenvectors() * es.eigenvalues().asDiagonal().inverse()
  //      * es.eigenvectors.transpose() * quadraticFitCoefficientsVector;

  // To regularize and deal with local maxima/saddlepoints, work in the space
  // where quadraticFitCoefficientsMatrix is diagonal!
  // 1. Transform quadraticFitCoefficientsVector and quadraticMinDataMatrix into
  //    eigenspace of quadraticFitCoefficients
  quadraticCoefficientsVector
    = es.eigenvectors().transpose() * quadraticCoefficientsVector;
  quadraticMinDataMatrix = quadraticMinDataMatrix * es.eigenvectors();

  // 2. Find the smallest hyper-rectangle bounding that space evenly around
  //    the best parent. Then scale it up to allow modest expansion of space
  const double quadScaleFactor = 2.0;
  quadBounds = quadScaleFactor
    * quadraticMinDataMatrix.cwiseAbs().colwise().maxCoeff();

  // 3. Find "minimum" by dividing quadraticFitCoefficientsVector by
  //    abs(es.eigenvalues), while bounding to hyper-rectangle
  const size_t numFitParameters = parameterDescriptions.numFitParameters();
  for(size_t ind = 0; ind < numFitParameters; ++ind) {
    const double vec_n = quadraticCoefficientsVector[ind];

    if(vec_n > 0) {
      quadExtremum[ind] = min(vec_n / abs(es.eigenvalues()[ind]),
                              quadBounds[ind]);
    }
    else if(vec_n < 0) {
      quadExtremum[ind] = max(vec_n / abs(es.eigenvalues()[ind]),
                              -quadBounds[ind]);
    }
    else {
      // vec_n is exactly 0.0
      quadExtremum[ind] = 0.0;
    }
  }

  // 4. Transform solution back to original space
  quadExtremum = es.eigenvectors() * quadExtremum;
}

void
ParameterPopulation::fillPSetFromQuadraticFit(ParameterSet & pSet,
                                              const size_t minInd) const
{
  // quadExtremum now holds information about how to alter best parent pSet
  //   to get to minimum. Fill out a new pSet from that info

  // assign the new pSet an undefined value
  pSet.value = NaN;

  // modify minPSet according to the deltas in quadExtremum
  const auto & minPSet = population[minInd];

  size_t col = 0;
  auto paramDescItr = parameterDescriptions.cbegin();
  for(size_t paramNum = 0;
      paramNum < pSet.parameters.size();
      ++paramNum, ++paramDescItr) {
    double & newParamVal = pSet.parameters[paramNum];
    if(paramDescItr->isConstant()) {
      newParamVal = minPSet.parameters[paramNum];
      continue;
    }
    else if(paramDescItr->isLogDistributed()) {
      newParamVal = minPSet.parameters[paramNum] * exp(quadExtremum[col]);
    }
    else {
      newParamVal = minPSet.parameters[paramNum] + quadExtremum[col];
    }

    ++col;

    // ensure newParamVal is in bounds
    if(newParamVal < paramDescItr->minAllowed) {
      newParamVal = paramDescItr->minAllowed;
    }
    else if(!(newParamVal <= paramDescItr->maxAllowed)) {
      newParamVal = paramDescItr->maxAllowed;
    }
  }
}

#endif

void
ParameterPopulation::setBestParameters(const ParameterSet & newBestParameters)
{
  // set the best parameters and save them

  bestParameters = newBestParameters;
  saveBestParameters();
}

void
ParameterPopulation::saveBestParameters(void) const
{
  // save bestParameters to results file

  if(!initialized || !logToDisk)
    // don't bother trying if not initialized, or not logging to disk
    return;

  // these better be true
  assert(!bestParameters.parameters.empty());
  assert(!parameterDescriptions.empty());

    // open results file for writing
  ofstream out (resultsFileName.c_str());
  if(out.fail())
    throw ParameterPopulationException("Can't open " + resultsFileName +
                                       " for writing");

  try {
    // calculate a few widths to ensure all the significant info in the double
    //  is output
    const streamsize doublePrecision = numeric_limits<double>::digits10 + 1;
    const streamsize expWidth = (streamsize)ceil(
      log10((double)numeric_limits<double>::max_exponent10));
    const streamsize doubleWidth = doublePrecision + expWidth + 4;

    // set output decimal precision
    out.precision(doublePrecision);

    // get length of longest parameter description name
    ParameterDescriptionList::const_iterator descItr =
      parameterDescriptions.begin();
    streamsize nameWidth = 5;
    for(; descItr != parameterDescriptions.end(); ++descItr)
      if(descItr->name.size() > (size_t)nameWidth)
        nameWidth = descItr->name.size();
    nameWidth += 1;

    // write out the function value
    out.width(nameWidth);
    out << left << "value";
    out.width(doubleWidth);
    out << right << bestParameters.value << '\n';

    // write out the parameters
    vector<double>::const_iterator bestItr = bestParameters.parameters.begin();
    descItr = parameterDescriptions.begin();
    for(; descItr != parameterDescriptions.end(); ++descItr, ++bestItr) {
      out.width(nameWidth);
      out << left << descItr->name;
      out.width(doubleWidth);
      out << right << *bestItr << '\n';
    }

    out.close();
  }
  catch(exception & e){
    // close the file
    out.close();
    // re-throw error
    throw;
  }
}

//////////////// ParameterPopulation private member functions /////////////////

void
ParameterPopulation::saveProgress(void) const
{
  // save state of ParameterPopulation to resume file

  if(!initialized || !logToDisk)
    // don't bother trying if not initialized, or not logging to disk
    return;

  // these better be true
  assert(!population.empty());
  assert(!bestParameters.parameters.empty());
  assert(!parameterDescriptions.empty());

  // create a temporary resume file to avoid destroying old resume information
  // if shutdown occurs during saving
  const string tempResumeFileName = resumeFileName + ".temp";

  // move the old resume information to the temporary file
  rename(resumeFileName.c_str(), tempResumeFileName.c_str());

  // open resume file for writing
  ofstream fileOut (resumeFileName.c_str());
  if(fileOut.fail())
    throw ParameterPopulationException("Can't open " + resumeFileName +
                                       " for writing");
  try {
    // write out *this
    fileOut << *this;

    // derived-class specific save routine
    saveSpecific(fileOut);

    // close resume file
    fileOut.close();
  }
  catch(exception & e) {
    // close the file
    fileOut.close();

    // remove the resume file
    remove(resumeFileName.c_str());

    // copy the old version back
    rename(tempResumeFileName.c_str(), resumeFileName.c_str());

    // re-throw error
    throw;
  }

  // remove temporary file
  remove(tempResumeFileName.c_str());

  if(logToTerminal) {
    cout << "Progress saved to " << resumeFileName << '\n';
    cout.flush();
  }
}

void
ParameterPopulation::resume(void)
{
  // check to see if program was killed during saveProgress()
  // (can happen with kill -9, or pulled plug)
  const string tempResumeFileName = resumeFileName + ".temp";
  if(fileExists(tempResumeFileName)) {
    if(logToTerminal) {
      cout << "Cleaning up corrupted resume file...";
      cout.flush();
    }

    // remove the (presumably corrupt) permanent resume file
    remove(resumeFileName.c_str());
    // restore temporary resume file
    rename(tempResumeFileName.c_str(), resumeFileName.c_str());

    if(logToTerminal) {
      cout << "done.\n";
      cout.flush();
    }
  }

  ifstream fileIn (resumeFileName.c_str());
  if(fileIn.fail()) {
    // if resume file can't be opened, don't resume
    resumed = false;
    return;
  }

  if(logToTerminal) {
    cout << "Resuming previous session from " << resumeFileName << " ... ";
    cout.flush();
  }

  try {
    // read in *this
    fileIn >> *this;

    // derived-class specific resume routine
    resumeSpecific(fileIn);

    // close resume file
    fileIn.close();
  }
  catch(exception & e) {
    // close resume file
    fileIn.close();
    // re-throw error
    throw;
  }

  if(logToTerminal) {
    cout << "success.\n";
    cout.flush();
  }
  resumed = true;

  // test if population is optimal
  testOptimal();

  // re-display the progress from the previous session(s)
  for(size_t genNum = 1; genNum <= generationHistory.size(); ++genNum)
    summarizeGeneration(genNum);
  return;
}

void
ParameterPopulation::testOptimal(void)
{
  // Max current range of log-distributed params
  maxLogRange = 1.0;
  // Max current range of uniform-distributed params
  maxUniformRange = 0.0;

  // initialize the min and max range of each parameter description
  auto paramItr = population.front().parameters.cbegin();
  for(auto & paramDescription : parameterDescriptions) {
    if(paramDescription.isConstant()) {
      ++paramItr;
      continue;
    }

    // initialize this parameter description's min/max to the best parameter
    // set's value
    paramDescription.minRange = *paramItr;
    paramDescription.maxRange = paramDescription.minRange;

    ++paramItr;
  }

  // keep track if the population has been fully evaluted
  bool populationEvaluated = (population.size() >= populationSize);

  maxDiffScale = 0.0;
  // loop over parameter sets
  for(const auto & pSet : population) {
    // for each parameter set:
    //   1. check if it's been evaluated
    //   2. update ranges of each parameter description

    if(isNaN(pSet.value))
      populationEvaluated = false;
    else {
      if(pSet.diffScale > maxDiffScale) {
        maxDiffScale = pSet.diffScale;
      }
    }

    paramItr = pSet.parameters.cbegin();
    for(auto & paramDescription : parameterDescriptions) {
      if(!paramDescription.isConstant())
        paramDescription.updateRange(*paramItr);
      ++paramItr;
    }
  }

  // update the overall maxLogRange and maxUniformRange
  for(auto & paramDescription : parameterDescriptions) {
    if(paramDescription.isLogDistributed()) {
      // parameter is log-distributed, update maxLogRange
      if(paramDescription.range() > maxLogRange)
        maxLogRange = paramDescription.range();
    }
    else {
      // parameter is uniform-distributed, update maxUniformRange
      if(paramDescription.range() > maxUniformRange)
        maxUniformRange = paramDescription.range();
    }
  }

  // range of values of competetive parameter sets
  fRange = population.back().value - population.front().value;

  // This is the test to see if the function is optimized

  if(parameterDescriptions.numFitParameters() == 0) {
    optimal = true;
  }
  else if(populationEvaluated && fRange < fTol && maxUniformRange < tol &&
           (maxLogRange - 1.0) < tol) {
    optimal = true;
  }
  else if(generationNum > maxGenerationNum) {
    optimal = true;
  }
  else {
    optimal = false; // provisional, may change in a bit
    /*
    const size_t lookBack = 1000;
    if(generationNum > lookBack) {
      const double smallTol = fTol * 0.1;

      const double deltaValue =
        generationHistory[generationNum - lookBack].bestParameters.value -
        bestParameters.value;

      if(generationNum > lookBack && fRange < smallTol && deltaValue < smallTol){
          optimal = true;
      }
    }
    */
  }
}

void
ParameterPopulation::saveHistory(void)
{
  // save current generation's history
  // NOTE: this function may be called more than once per generation, so can't
  // simply call generationHistory.push_back(...)

  // resize generationHistory
  generationHistory.resize(generationNum,
    GenerationSummary(bestParameters, generationTime, totalTime,
                      fRange, maxLogRange, maxUniformRange) );
}

void
ParameterPopulation::summarizeGeneration(const size_t & genNum) const
{
  // print a summary of the requested generation
  assert(genNum > 0);

  // get a pointer to the requested generation summary
  GenerationSummary const* const histPtr = &generationHistory[genNum - 1];

  // print out a the details of the summary
  if(logToTerminal) {
    cout << "####### Generation " << genNum << " #######\n";
    cout << "Best value = " << histPtr->bestParameters.value << '\n';
    cout << "Evaluation time:  " << histPtr->generationTime << '\n';
    cout << "Total elapsed time:  " << histPtr->totalTime << '\n';
    if(optimal && genNum == generationNum)
      cout << "Finished optimizing.\n";
    cout.flush();
  }
}

inline void
ParameterPopulation::get3ParentInds(size_t & ind1, size_t & ind2,
                                    size_t & ind3, RandGen & randGen) const
{
  // Randomly draw indices to three members of the population

  const size_t popSize = population.size();
  ind1 = getParent(popSize, randGen);
  ind2 = getParent(popSize - 1, randGen);
  ind3 = getParent(popSize - 2, randGen);
  if(ind2 >= ind1) {
    ++ind2;
    if(ind3 >= ind1)
      ++ind3;
    if(ind3 >= ind2)
      ++ind3;
  }
  else {
    if(ind3 >= ind2)
      ++ind3;
    if(ind3 >= ind1)
      ++ind3;
  }
}

inline void
ParameterPopulation::getNParentInds(vector<size_t> & parentInds,
                                    const size_t & numParents,
                                    RandGen & randGen) const
{
  // Randomly draw indices to numParents members of the population.
  // Ensure that the first parentInd is the best one

  // create list of all possible parents
  static vector<size_t> allInds;  // change to not be vector?
  allInds.resize(population.size());
  size_t n = 0;
  for(size_t & ind : allInds) {
    ind = n;
    ++n;
  }

  // resize the vector of indices appropriately
  parentInds.resize(numParents);

  for(size_t & parentInd : parentInds) {
    // randomly select a valid member of the population
    const size_t randomInd = randGen.unsignedInt(allInds.size());
    auto allItr = allInds.begin() + randomInd;
    // set the current parent to the selected member
    parentInd = *allItr;
    // If it's better (lower index) than the first parentInd, swap them
    if(parentInd < parentInds[0]) {
      swap(parentInd, parentInds[0]);
    }
    // remove this population member from further consideration
    allInds.erase(allItr);
  }
}

inline size_t
ParameterPopulation::getParent(const size_t & cutoff, RandGen & randGen) const
{
  // return a parent index from the breeding population [0, cutoff - 1]

  return (size_t)randGen.unsignedInt(cutoff);
}


text:
#include "bank_worker.h"
#include "db/txs/dbrad.h"
#include "db/txs/dbtx.h"
#include "db/txs/dbsi.h"
#include "db/txs/db_farm.h"
#include "db/forkset.h"

#include "tx_config.h"

#include "util/util.h"

#include "rtx/rtx_occ_rdma.hpp"
#include "rtx/rtx_occ_variants.hpp"

#include <boost/bind.hpp>

#define unlikely(x) __builtin_expect(!!(x), 0)

extern nocc::db::TSManager *ts_manager;

extern __thread RemoteHelper *remote_helper;

extern size_t current_partition;
extern size_t scale_factor;

#define MULTI_SITE 1 // distributed TX ratio
#define TX_HOT     90

namespace nocc {

extern RdmaCtrl *cm;

namespace oltp {

extern __thread util::fast_random   *random_generator;

namespace bank {

BreakdownTimer compute_timer;
BreakdownTimer send_timer;

extern unsigned g_txn_workload_mix[6];

static inline ALWAYS_INLINE size_t
TotalAccts() {
  // "-1" because we dedicate one server as the timestamp oracle
  return DEFAULT_NUM_ACCOUNTS * scale_factor * (total_partition - 1);
}

static inline ALWAYS_INLINE uint64_t
GetStartAcctt() {
  return current_partition * NumAcctsLocal();
}

static inline ALWAYS_INLINE uint64_t
GetEndAcctt() {
  return (current_partition + 1) * NumAcctsLocal() - 1;
}

static inline ALWAYS_INLINE int
custid_to_pid(uint64_t id) {
  return (id / NumAcctsLocal());
}

/* input generation */
void GetAccount(util::fast_random &r, uint64_t *acct_id) {
  uint64_t nums_global;
  if(r.next() % 100 < TX_HOT) {
    nums_global = NumAccounts();
  } else {
    nums_global = NumHotAccounts();
  }
  *acct_id = r.next() % nums_global;
}

static inline ALWAYS_INLINE void
_HotSpotOneAcct(fast_random &r,uint64_t *acct) {

  static const int total_accts = DEFAULT_NUM_ACCOUNTS * scale_factor;
  static const int total_hot   = DEFAULT_NUM_HOT * scale_factor;

  if( _RandomNumber(r,0,100) < TX_HOT) {
    *acct = GetStartAcctt()  + _RandomNumber(r,0,total_hot-1);
  }else {
    *acct = GetStartAcctt()  + _RandomNumber(r,total_hot,total_accts - 1);
  }
}

static inline ALWAYS_INLINE void
_HotSpotTwoAcct(fast_random &r,uint64_t *acct0,uint64_t *acct1) {

  static const int total_accts = DEFAULT_NUM_ACCOUNTS * scale_factor;
  static const int total_hot   = DEFAULT_NUM_HOT * scale_factor;

  bool is_dtxn = ((total_partition > 1) && _RandomNumber(r,0,100) < MULTI_SITE);
  if( _RandomNumber(r,0,100) < TX_HOT) {
    *acct0 = GetStartAcctt()  + _RandomNumber(r,0,total_hot-1);
    int mac_id,acct_id;
    if(is_dtxn) {
      do {
        mac_id = _RandomNumber(r,0,total_partition - 1);
      }while(mac_id == current_partition);

      acct_id = _RandomNumber(r,0,total_hot-1);
      *acct1  = acct_id + mac_id * total_accts;
    }else {
      //local
      do {
        *acct1 = GetStartAcctt()  + _RandomNumber(r,0,total_hot-1);
      }while(*acct1 == *acct0);
    }
    //end hot
  }else {

    *acct0 = GetStartAcct()  + _RandomNumber(r,total_hot,total_accts-1);
    int mac_id,acct_id;
    if(is_dtxn) {
      do {
	mac_id = _RandomNumber(r,0,total_partition - 1);
      }while(mac_id == current_partition);

      acct_id = _RandomNumber(r,total_hot,total_accts-1);
      *acct1  = acct_id + mac_id * total_accts;
    }else {
      //local
      do {
	*acct1 = GetStartAcct()  + _RandomNumber(r,total_hot,total_accts-1);
      }while(*acct1 == *acct0);
    }
    //end no hot
  }
}

void GetTwoAccount(util::fast_random &r,
                   uint64_t *acct_id_0, uint64_t *acct_id_1)  {
  uint64_t nums_global;
  if(r.next() % 100 < TX_HOT) {
    nums_global = NumAccounts();
  } else {
    nums_global = NumHotAccounts();
  }
  *acct_id_0 = r.next() % nums_global;
  *acct_id_1 = r.next() % nums_global;
  while(*acct_id_1 == *acct_id_0) {
    *acct_id_1 = r.next() % nums_global;
  }
}

BankWorker::BankWorker(unsigned int id,unsigned long seed,MemDB *db,uint64_t total_ops,
                       spin_barrier *a, spin_barrier *b,BenchRunner *context):
    BenchWorker(id,true,seed,total_ops,a,b,context),
    store_(db)
{
  // clear timer states
  compute_timer.report();
  send_timer.report();
}

void BankWorker::register_callbacks() {
}

void BankWorker::check_consistency() {

}

void BankWorker::balance_piece(int id, int cid, char *input, yield_func_t &yield) {

  balance_req_header *header = (balance_req_header *)input;
  assert(false);
#ifdef OCC_TX
  RemoteHelper *h =  remote_helper;
  h->begin(_QP_ENCODE_ID(id,cid + 1));
#endif

#ifdef SI_TX
  uint64_t timestamp = (uint64_t)(&(header->ts_vec));
#else
  uint64_t timestamp = header->time;
#endif

  checking::value cv;
  savings::value sv;
  uint64_t seq = tx_->get_ro_versioned(CHECK,header->id,(char *)(&cv),timestamp,yield);
  seq = tx_->get_ro_versioned(SAV,header->id,(char *)(&sv),timestamp,yield);
  assert(seq != 1);

  double res = cv.c_balance + sv.s_balance;
  double *reply_msg  = (double *)(rpc_->get_reply_buf());
  *reply_msg = res;
  rpc_->send_reply((char *)reply_msg,sizeof(double), id, worker_id_,cid);
}

txn_result_t BankWorker::txn_balance2(yield_func_t &yield) {

  tx_->begin();
  uint64_t id;
retry:
  GetAccount(random_generator[cor_id_],&(id));
  int pid = AcctToPid(id);

  double res = 0.0;
  //if(pid != current_partition) {
  if(1){

    tx_->add_to_remote_set(CHECK,id,pid,yield);
    tx_->add_to_remote_set(SAV,id,pid,yield);

    tx_->do_remote_reads();
    indirect_yield(yield);
    tx_->get_remote_results(1);

    checking::value *cv;
    savings::value  *sv;
    tx_->get_cached(0,(char **)(&cv));
    tx_->get_cached(1,(char **)(&sv));

    res = cv->c_balance + sv->s_balance;

  } else {
    checking::value *cv;
    savings::value *sv;
    tx_->get(CHECK,id,(char **)(&cv),sizeof(checking::value));
    tx_->get(SAV,id,(char **)(&sv),sizeof(savings::value));
    res = cv->c_balance + sv->s_balance;
  }

  bool ret = tx_->end(yield);
  return txn_result_t(true,(uint64_t)res);
}

txn_result_t BankWorker::txn_deposit_checking(yield_func_t &yield) {

  tx_->begin(db_logger_);
  float amount = 1.3;
  // this is an always local TX

  uint64_t acct_id;
  _HotSpotOneAcct(random_generator[cor_id_],&acct_id);

  checking::value *cv = nullptr;
  tx_->get(CHECK,acct_id,(char **)(&cv),sizeof(checking::value));
  ASSERT(cv != nullptr);
  cv->c_balance += amount;
  tx_->write(CHECK,acct_id,(char *)cv,sizeof(checking::value));
  bool ret = tx_->end(yield);
  return txn_result_t(ret,73);
}

txn_result_t BankWorker::txn_send_payment(yield_func_t &yield) {

  tx_->begin(db_logger_);
  uint64_t id0,id1;
  _HotSpotTwoAcct(random_generator[cor_id_],&id0,&id1);
  float amount = 5.0;

  checking::value *c0, *c1; int idx0,idx1;

  int pid = AcctToPid(id0);
  ASSERT(pid == current_partition);

  tx_->get(CHECK,id0,(char **)(&c0),sizeof(checking::value));

  pid = AcctToPid(id1);
  if (pid != current_partition) {
    tx_->add_to_remote_set(CHECK,id1,pid,yield);
    auto replies = tx_->do_remote_reads();
    indirect_yield(yield);
    tx_->get_remote_results(replies);
    auto seq = tx_->get_cached(0,(char **)(&c1));
    tx_->remote_write(0,(char *)c1,sizeof(checking::value));
  } else {
    tx_->get(CHECK,id1,(char **)(&c1),sizeof(checking::value));
  }

  if(c0->c_balance < amount) {
  } else {
    c0->c_balance -= amount;
    c1->c_balance += amount;
  }

  auto ret = tx_->end(yield);
  return txn_result_t(ret,73);
}

txn_result_t BankWorker::txn_transact_savings(yield_func_t &yield) {

  tx_->begin(db_logger_);
  float amount   = 20.20; //from original code
  uint64_t id;
  GetAccount(random_generator[cor_id_],&id);
  int pid = AcctToPid(id);

#ifdef EM_FASST
  tx_->remoteset->add(REQ_READ_LOCK,pid,SAV,id);
  tx_->remoteset->do_reads(1);
#else
  tx_->add_to_remote_set(SAV,id,pid,yield);
  tx_->do_remote_reads();
#endif

  indirect_yield(yield);

#ifdef EM_FASST
  bool ret = tx_->remoteset->get_results_readlock(1);
#else
  tx_->get_remote_results(1);
#endif

  savings::value *sv;
  uint64_t seq = tx_->get_cached(0,(char **)(&sv));
  sv->s_balance += amount;
  tx_->remote_write(0,(char *)sv,sizeof(savings::value));
#ifdef EM_FASST
  if(unlikely(!ret)) {
    tx_->remoteset->release_remote(yield);
    //tx_->remoteset->clear_for_reads();
    tx_->abort();
    return txn_result_t(false,0);
  }

  ret = tx_->end_fasst(yield);
#else
  auto ret = tx_->end(yield);
#endif
  return txn_result_t(ret,73);
}

txn_result_t BankWorker::txn_write_check(yield_func_t &yield) {

  tx_->begin(db_logger_);
  float amount = 5.0; //from original code

  uint64_t id;
  GetAccount(random_generator[cor_id_],&id);
  int pid = AcctToPid(id);

#ifdef EM_FASST
  tx_->remoteset->add(REQ_READ,pid,SAV,id);
  tx_->remoteset->add(REQ_READ_LOCK,pid,CHECK,id);
#else
  tx_->add_to_remote_set(SAV,id,pid,yield);
  tx_->add_to_remote_set(CHECK,id,pid,yield);
#endif
  //auto replies = tx_->remoteset->do_reads(0);
  auto replies = tx_->do_remote_reads();

  indirect_yield(yield);

#ifdef EM_FASST
  bool res = tx_->remoteset->get_results_readlock(replies);
#else
  tx_->get_remote_results(replies);
#endif

  savings::value *sv;
  checking::value *cv;
  auto seq = tx_->get_cached(0,(char **)(&sv));
  seq = tx_->get_cached(1,(char **)(&cv));

  auto total = sv->s_balance + cv->c_balance;
  if(total < amount) {
    cv->c_balance -= (amount - 1);
  } else
    cv->c_balance -= amount;

  tx_->remote_write(1,(char *)cv,sizeof(checking::value));

#ifdef EM_FASST
  if(unlikely(!res)) {
    tx_->remoteset->release_remote(yield);
    //tx_->remoteset->clear_for_reads();
    tx_->abort();
    return txn_result_t(false,0);
  }
#endif

#ifdef EM_FASST
  bool ret = tx_->end_fasst(yield);
#else
  bool ret = tx_->end(yield);
#endif
  return txn_result_t(ret,73);
}

txn_result_t BankWorker::txn_amal(yield_func_t &yield) {

  tx_->begin(db_logger_);
  uint64_t id0,id1;
retry:
  GetTwoAccount(random_generator[cor_id_],&id0,&id1);

  checking::value *c0,*c1; savings::value *s0,s1;

  int pid0 = AcctToPid(id0);
  int pid1 = AcctToPid(id1),idx1;
#ifdef EM_FASST
  tx_->remoteset->add(REQ_READ_LOCK,pid0,SAV,id0);
  tx_->remoteset->add(REQ_READ_LOCK,pid0,CHECK,id0);
  tx_->remoteset->add(REQ_READ_LOCK,pid1,CHECK,id1);
#else
  tx_->add_to_remote_set(SAV,id0,pid0,yield);
  tx_->add_to_remote_set(CHECK,id0,pid0,yield);
  tx_->add_to_remote_set(CHECK,id1,pid1,yield);
#endif

  auto replies = tx_->do_remote_reads();

  indirect_yield(yield);
#ifdef EM_FASST
  bool res = tx_->remoteset->get_results_readlock(replies);
#else
  tx_->get_remote_results(replies);
#endif

  double total = 0;

  auto seq = tx_->get_cached(0,(char **)(&s0));
  //assert(seq != 0);
  seq = tx_->get_cached(1,(char **)(&c0));
  //        assert(seq != 0);

  total = s0->s_balance + c0->c_balance;

  s0->s_balance = 0;
  c0->c_balance = 0;

  tx_->remote_write(0,(char *)s0,sizeof(savings::value));
  tx_->remote_write(1,(char *)c0,sizeof(checking::value));

  seq = tx_->get_cached(2,(char **)(&c1));
  //assert(seq != 0);
  c1->c_balance += total;
  tx_->remote_write(2,(char *)c1,sizeof(checking::value));

#ifdef EM_FASST
  if(unlikely(!res)) {
    // no early aborts here
    tx_->remoteset->release_remote(yield);
    //tx_->remoteset->clear_for_reads();
    tx_->abort();
    return txn_result_t(false,0);
  }

  bool ret = tx_->end_fasst(yield);
#else
  bool ret = tx_->end(yield);
#endif
  return txn_result_t(ret,73); // since readlock success, so no need to abort
}

void BankWorker::thread_local_init() {

  assert(store_ != NULL);
  for(uint i = 0;i < server_routine + 1;++i) {
    // init TXs
#ifdef RAD_TX
    txs_[i] = new DBRad(store_,worker_id_,rpc_,i);
#elif defined(OCC_TX)
    txs_[i] = new DBTX(store_,worker_id_,rpc_,i);
    //((DBTX *)(txs_[i]))->new_logger_ = new_logger_;
    //remote_helper = new RemoteHelper(store_,total_partition,server_routine + 1);

    // -1 transformed every local operations to remote ones
#elif defined(FARM)
    txs_[i] = new DBFarm(cm,rdma_sched_,store_,worker_id_,rpc_,i);
#elif defined(SI_TX)
    txs_[i] = new DBSI(store_,worker_id_,rpc_,i);
#else
    fprintf(stderr,"No transaction layer used!\n");
    assert(false);
#endif
  }
  /* init local tx so that it is not a null value */
  tx_ = txs_[cor_id_];
  //rtx_ = new_txs_[cor_id_];
  //routine_1_tx_ = txs_[1]; // used for report
} // end func: thread_local_init

workload_desc_vec_t BankWorker::get_workload() const {
  return _get_workload();
}

workload_desc_vec_t BankWorker::_get_workload() {

  workload_desc_vec_t w;
  unsigned m = 0;
  for (size_t i = 0; i < ARRAY_NELEMS(g_txn_workload_mix); i++)
    m += g_txn_workload_mix[i];
  ALWAYS_ASSERT(m == 100);

  if(g_txn_workload_mix[0]) {
    w.push_back(workload_desc("SendPayment", double(g_txn_workload_mix[0])/100.0, TxnSendPayment));
  }
  if(g_txn_workload_mix[1]) {
    w.push_back(workload_desc("DepositChecking",double(g_txn_workload_mix[1])/100.0,TxnDepositChecking));
  }
  if(g_txn_workload_mix[2]) {
    w.push_back(workload_desc("Balance",double(g_txn_workload_mix[2])/100.0,TxnBalance));
  }
  if(g_txn_workload_mix[3]) {
    w.push_back(workload_desc("Transact saving",double(g_txn_workload_mix[3])/100.0,TxnTransactSavings));
  }
  if(g_txn_workload_mix[4]) {
    w.push_back(workload_desc("Write check",double(g_txn_workload_mix[4])/100.0,TxnWriteCheck));
  }
  if(g_txn_workload_mix[5]) {
    w.push_back(workload_desc("Txn amal",double(g_txn_workload_mix[5])/100.0,TxnAmal));
  }
  return w;
}

}; // namespace bank
};
};

ext: cc

max_stars_repo_name: SJTU-IPADS/dst

max_issues_repo_name: SJTU-IPADS/dst

max_forks_repo_name: SJTU-IPADS/dst


text:
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include <boost/filesystem.hpp>

#include <thrift/concurrency/ThreadManager.h>
#include <thrift/concurrency/PlatformThreadFactory.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include "thrift/server/TNonblockingServer.h"
#include "thrift/transport/TSSLSocket.h"
#include "thrift/transport/TNonblockingSSLServerSocket.h"
#include <iostream>
#include <event.h>

#include "../gen-cpp/Calculator.h"

using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::concurrency;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace apache::thrift::server;

using namespace tutorial;
using namespace shared;

class CalculatorHandler : public CalculatorIf {
public:
  CalculatorHandler() {}

  void ping() { cout << "ping()" << endl; }

  int32_t add(const int32_t n1, const int32_t n2) {
    cout << "add(" << n1 << ", " << n2 << ")" << endl;
    return n1 + n2;
  }

  int32_t calculate(const int32_t logid, const Work& work) {
    cout << "calculate(" << logid << ", " << work << ")" << endl;
    int32_t val;

    switch (work.op) {
    case Operation::ADD:
      val = work.num1 + work.num2;
      break;
    case Operation::SUBTRACT:
      val = work.num1 - work.num2;
      break;
    case Operation::MULTIPLY:
      val = work.num1 * work.num2;
      break;
    case Operation::DIVIDE:
      if (work.num2 == 0) {
        InvalidOperation io;
        io.whatOp = work.op;
        io.why = "Cannot divide by 0";
        throw io;
      }
      val = work.num1 / work.num2;
      break;
    default:
      InvalidOperation io;
      io.whatOp = work.op;
      io.why = "Invalid Operation";
      throw io;
    }

    SharedStruct ss;
    ss.key = logid;
    ss.value = to_string(val);

    log[logid] = ss;

    return val;
  }

  void getStruct(SharedStruct& ret, const int32_t logid) {
    cout << "getStruct(" << logid << ")" << endl;
    ret = log[logid];
  }

  void zip() { cout << "zip()" << endl; }

protected:
  map<int32_t, SharedStruct> log;
};

/*
  CalculatorIfFactory is code generated.
  CalculatorCloneFactory is useful for getting access to the server side of the
  transport.  It is also useful for making per-connection state.  Without this
  CloneFactory, all connections will end up sharing the same handler instance.
*/
class CalculatorCloneFactory : virtual public CalculatorIfFactory {
 public:
  virtual ~CalculatorCloneFactory() {}
  virtual CalculatorIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo)
  {
    stdcxx::shared_ptr<TSocket> sock = stdcxx::dynamic_pointer_cast<TSocket>(connInfo.transport);
    cout << "Incoming connection\n";
    cout << "\tSocketInfo: "  << sock->getSocketInfo() << "\n";
    cout << "\tPeerHost: "    << sock->getPeerHost() << "\n";
    cout << "\tPeerAddress: " << sock->getPeerAddress() << "\n";
    cout << "\tPeerPort: "    << sock->getPeerPort() << "\n";
    return new CalculatorHandler;
  }
  virtual void releaseHandler( ::shared::SharedServiceIf* handler) {
    delete handler;
  }
};

class ListenEventHandler : public TServerEventHandler {
  public:
    ListenEventHandler(Mutex* mutex) : listenMonitor_(mutex), ready_(false) {}

    void preServe() /* override */ {
      Guard g(listenMonitor_.mutex());
      ready_ = true;
      listenMonitor_.notify();
    }

    Monitor listenMonitor_;
    bool ready_;
};

boost::filesystem::path keyDir;
boost::filesystem::path certFile(const std::string& filename) {
  return keyDir / filename;
}

class Runner : public apache::thrift::concurrency::Runnable {
  public:
  int port;
  stdcxx::shared_ptr<event_base> userEventBase;
  stdcxx::shared_ptr<CalculatorProcessorFactory> processor;
  stdcxx::shared_ptr<server::TNonblockingServer> server;
  stdcxx::shared_ptr<ListenEventHandler> listenHandler;
  stdcxx::shared_ptr<TSSLSocketFactory> pServerSocketFactory;
  stdcxx::shared_ptr<transport::TNonblockingSSLServerSocket> socket;
  Mutex mutex_;

  Runner() {
    listenHandler.reset(new ListenEventHandler(&mutex_));
  }

  virtual void run() {
    // When binding to explicit port, allow retrying to workaround bind failures on ports in use
    int retryCount = port ? 10 : 0;
//    pServerSocketFactory = createServerSocketFactory();

    pServerSocketFactory.reset(new TSSLSocketFactory());
    pServerSocketFactory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
    pServerSocketFactory->loadCertificate(certFile("server.crt").string().c_str());
    pServerSocketFactory->loadPrivateKey(certFile("server.key").string().c_str());
    pServerSocketFactory->server(true);

    startServer(retryCount);
  }

  void readyBarrier() {
    // block until server is listening and ready to accept connections
    Guard g(mutex_);
    while (!listenHandler->ready_) {
      listenHandler->listenMonitor_.wait();
    }
  }

  private:
  void startServer(int retry_count) {
    try {
      socket.reset(new transport::TNonblockingSSLServerSocket(port, pServerSocketFactory));
      server.reset(new server::TNonblockingServer(processor, socket));
      server->setServerEventHandler(listenHandler);
      server->setNumIOThreads(1);
      if (userEventBase) {
        server->registerEvents(userEventBase.get());
      }
      server->serve();
    } catch (const transport::TTransportException&) {
      if (retry_count > 0) {
        ++port;
        startServer(retry_count - 1);
      } else {
        throw;
      }
    }
  }
};

struct EventDeleter {
  void operator()(event_base* p) { event_base_free(p); }
};

void canCommunicate(int serverPort) {
  stdcxx::shared_ptr<TSSLSocketFactory> pClientSocketFactory;

  pClientSocketFactory.reset(new TSSLSocketFactory());
  pClientSocketFactory->authenticate(true);
  pClientSocketFactory->loadCertificate(certFile("client.crt").string().c_str());
  pClientSocketFactory->loadPrivateKey(certFile("client.key").string().c_str());
  pClientSocketFactory->loadTrustedCertificates(certFile("CA.pem").string().c_str());

  stdcxx::shared_ptr<TSSLSocket> socket = pClientSocketFactory->createSocket("localhost", serverPort);
  stdcxx::shared_ptr<TTransport> transport(new TFramedTransport(socket));
  stdcxx::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
  CalculatorClient client(protocol);

  try {
    socket->open();

    client.ping();
    cout << "ping()" << endl;

    cout << "1 + 1 = " << client.add(1, 1) << endl;

    Work work;
    work.op = Operation::DIVIDE;
    work.num1 = 1;
    work.num2 = 0;

    try {
      client.calculate(1, work);
      cout << "Whoa? We can divide by zero!" << endl;
    } catch (InvalidOperation& io) {
      cout << "InvalidOperation: " << io.why << endl;
      // or using generated operator<<: cout << io << endl;
      // or by using std::exception native method what(): cout << io.what() << endl;
    }

    work.op = Operation::SUBTRACT;
    work.num1 = 15;
    work.num2 = 10;
    int32_t diff = client.calculate(1, work);
    cout << "15 - 10 = " << diff << endl;

    // Note that C++ uses return by reference for complex types to avoid
    // costly copy construction
    SharedStruct ss;
    client.getStruct(ss, 1);
    cout << "Received log: " << ss << endl;

    transport->close();
  } catch (TException& tx) {
    cout << "ERROR: " << tx.what() << endl;
  }
}

int main() {
  stdcxx::shared_ptr<event_base> userEventBase;
  stdcxx::shared_ptr<server::TNonblockingServer> server;
  stdcxx::shared_ptr<TSSLSocketFactory> pServerSocketFactory;
  stdcxx::shared_ptr<transport::TNonblockingSSLServerSocket> socket;
  stdcxx::shared_ptr<CalculatorProcessorFactory> processor = stdcxx::make_shared<CalculatorProcessorFactory>(stdcxx::make_shared<CalculatorCloneFactory>());
  stdcxx::shared_ptr<apache::thrift::concurrency::Thread> thread;

#ifdef __linux__
  // OpenSSL calls send() without MSG_NOSIGPIPE so writing to a socket that has
  // disconnected can cause a SIGPIPE signal...
  signal(SIGPIPE, SIG_IGN);
#endif

  TSSLSocketFactory::setManualOpenSSLInitialization(true);
  apache::thrift::transport::initializeOpenSSL();

  keyDir = boost::filesystem::current_path().parent_path().parent_path() / "keys";

  event_base* eb = event_base_new();
  userEventBase.reset(eb, EventDeleter());

  stdcxx::shared_ptr<Runner> runner(new Runner);
  runner->port = 0;
  runner->processor =  processor;
  runner->userEventBase = userEventBase;

  apache::thrift::stdcxx::scoped_ptr<apache::thrift::concurrency::ThreadFactory> threadFactory(
    new apache::thrift::concurrency::PlatformThreadFactory(
#if !USE_BOOST_THREAD && !USE_STD_THREAD
      concurrency::PlatformThreadFactory::OTHER, concurrency::PlatformThreadFactory::NORMAL,
      1,
#endif
      false));
  thread = threadFactory->newThread(runner);
  cout << "Starting the server..." << endl;
  thread->start();
  runner->readyBarrier();

  server = runner->server;

  cout << "Port : " << server->getListenPort() << endl;

  canCommunicate(server->getListenPort());
//  canCommunicate(server->getListenPort());
//  canCommunicate(server->getListenPort());

  if (server) {
    server->stop();
  }
  if (thread) {
    thread->join();
  }

  apache::thrift::transport::cleanupOpenSSL();
#ifdef __linux__
  signal(SIGPIPE, SIG_DFL);
#endif
  cout << "Done." << endl;

//int stop;
//cin >> stop;

  return runner->port;
}

ext: cpp

max_stars_repo_name: NorbertoBurciaga/apache-thrift-tsl

max_issues_repo_name: NorbertoBurciaga/apache-thrift-tsl

max_forks_repo_name: NorbertoBurciaga/apache-thrift-tsl


text:
#include "server.hpp"
#include <boost/asio.hpp>
#include "network/http/server.hpp"

Xse::HttpServer::HttpServer(
    const std::string& address,
    const std::string& port,
    const std::string& doc_root)
:maddress(address),
mport(port),
mdoc_root(doc_root){

}
Xse::HttpServer::~HttpServer(){

}
void Xse::HttpServer::Start(){
    http::server::server s(this->maddress, this->mport, this->mdoc_root);
    s.run();
}

max_stars_repo_name: czjone/node

max_issues_repo_name: czjone/node

max_forks_repo_name: czjone/node


text:
// Author: Jiesi Zhao (jiesizhao0423@gmail.com), Wei Dai (wdai@cs.cmu.edu)
// Date: 2014.11.6

#pragma once

#include "decision_tree.hpp"
#include "rand_forest.hpp"
#include <ml/include/ml.hpp>
#include <petuum_ps_common/include/petuum_ps.hpp>
#include <boost/thread.hpp>
#include <vector>
#include <cstdint>
#include <atomic>
#include <utility>

namespace tree {

class RandForestEngine {
public:
  RandForestEngine();

  void ReadData(std::string type);

  int GetNumLabels() const {
    return num_labels_;
  }

  int GetNumTestData() const {
    return num_test_data_;
  }

  // Can be called concurrently.
  void Start();

private:  // private methods

  // Set meta reader for ReadData()
  void SetReader();

  // Evalute error on each client
  static float EvaluateErrorLocal(const RandForest& rand_forest,
      const std::vector<petuum::ml::AbstractFeature<float>*>& features,
     const std::vector<int32_t>& labels);

  // Register label votes on test data on test_vote_table_.
  float VoteOnTestData(const RandForest& rand_forest);

  // Only head thread should call this to collect the votes and compute test
  // error.
  float ComputeTestError();

private:
  // ============== Data Variables ==================
  int32_t num_train_data_;
  int32_t num_test_data_;
  int32_t feature_dim_;
  int32_t num_labels_;  // # of classes
  int32_t num_train_eval_;  // # of train data in each eval
  int32_t num_test_eval_;  // # of test data in each eval
  bool perform_test_;
  std::string read_format_; // for both train and test.
  bool feature_one_based_;  // feature starts from 1 (train and test).
  bool label_one_based_;    // label starts from 1 (train and test).
  bool save_pred_; // whether to save prediction on test set to file
  std::string pred_file_; // path of prediction output file
  bool save_trees_;  // whether to save trees to file
  std::string output_file_;  // path of output file
  bool load_trees_; // whether load trees from file
                    // if set true, all variable above are ignored
  std::string input_file_;

  // Each feature is a float array of length num_units_each_layer_[0].
  // DNNEngine takes ownership of these pointers.
  std::vector<petuum::ml::AbstractFeature<float>*> train_features_;

  // train_labels_.size() == train_features_.size()
  std::vector<int32_t> train_labels_;

  std::vector<petuum::ml::AbstractFeature<float>*> test_features_;
  std::vector<int32_t> test_labels_;

  // ============= Concurrency Management ==============
  std::atomic<int32_t> thread_counter_;

  std::unique_ptr<boost::barrier> process_barrier_;

  // ============ PS Tables ============
  petuum::Table<int> test_vote_table_;
};

}  // namespace tree

ext: hpp


text:
/**************************************************************
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 *************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sdext.hxx"

#include "PresenterBitmapContainer.hxx"
#include "PresenterConfigurationAccess.hxx"

#include <com/sun/star/deployment/XPackageInformationProvider.hpp>
#include <com/sun/star/drawing/XPresenterHelper.hpp>
#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#include <com/sun/star/rendering/CompositeOperation.hpp>
#include <com/sun/star/rendering/XIntegerBitmap.hpp>
#include <boost/bind.hpp>
#include <map>

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::std;
using ::rtl::OUString;

#define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString)))

namespace sdext { namespace presenter {

namespace {
static OUString gsNameProperty (A2S("Name"));
static OUString gsNormalFileNameProperty (A2S("NormalFileName"));
static OUString gsMouseOverFileNameProperty (A2S("MouseOverFileName"));
static OUString gsButtonDownFileNameProperty (A2S("ButtonDownFileName"));
static OUString gsDisabledFileNameProperty (A2S("DisabledFileName"));
static OUString gsMaskFileNameProperty (A2S("MaskFileName"));
static OUString gsXOffsetProperty (A2S("XOffset"));
static OUString gsYOffsetProperty (A2S("YOffset"));
static OUString gsXHotSpotProperty (A2S("XHotSpot"));
static OUString gsYHotSpotProperty (A2S("YHotSpot"));
static OUString gsReplacementColorProperty (A2S("ReplacementColor"));
static OUString gsHorizontalTexturingModeProperty (A2S("HorizontalTexturingMode"));
static OUString gsVerticalTexturingModeProperty (A2S("VerticalTexturingMode"));
}

//===== PresenterBitmapContainer ==============================================

PresenterBitmapContainer::PresenterBitmapContainer (
    const ::rtl::OUString& rsConfigurationBase,
    const ::boost::shared_ptr<PresenterBitmapContainer>& rpParentContainer,
    const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext,
    const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
    const css::uno::Reference<css::drawing::XPresenterHelper>& rxPresenterHelper)
    : mpParentContainer(rpParentContainer),
      maIconContainer(),
      mxCanvas(rxCanvas),
      mxPresenterHelper(rxPresenterHelper)
{
    Initialize(rxComponentContext);

    // Get access to the configuration.
    PresenterConfigurationAccess aConfiguration (
        rxComponentContext,
        A2S("org.openoffice.Office.PresenterScreen"),
        PresenterConfigurationAccess::READ_ONLY);
    Reference<container::XNameAccess> xBitmapList (
        aConfiguration.GetConfigurationNode(rsConfigurationBase),
        UNO_QUERY_THROW);

    LoadBitmaps(xBitmapList);
}

PresenterBitmapContainer::PresenterBitmapContainer (
    const css::uno::Reference<css::container::XNameAccess>& rxRootNode,
    const ::boost::shared_ptr<PresenterBitmapContainer>& rpParentContainer,
    const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext,
    const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
    const css::uno::Reference<css::drawing::XPresenterHelper>& rxPresenterHelper)
    : mpParentContainer(rpParentContainer),
      maIconContainer(),
      mxCanvas(rxCanvas),
      mxPresenterHelper(rxPresenterHelper)
{
    Initialize(rxComponentContext);

    LoadBitmaps(rxRootNode);
}

void PresenterBitmapContainer::Initialize (
    const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext)
{
    if ( ! mxPresenterHelper.is())
    {
        // Create an object that is able to load the bitmaps in a format that is
        // supported by the canvas.
        Reference<lang::XMultiComponentFactory> xFactory (
            rxComponentContext->getServiceManager(), UNO_QUERY);
        if ( ! xFactory.is())
            return;
        mxPresenterHelper = Reference<drawing::XPresenterHelper>(
            xFactory->createInstanceWithContext(
                A2S("com.sun.star.drawing.PresenterHelper"),
                rxComponentContext),
            UNO_QUERY_THROW);
    }
}

PresenterBitmapContainer::~PresenterBitmapContainer (void)
{
    maIconContainer.clear();
}

SharedBitmapDescriptor PresenterBitmapContainer::GetBitmap (
    const OUString& rsName) const
{
    BitmapContainer::const_iterator iSet (maIconContainer.find(rsName));
    if (iSet != maIconContainer.end())
        return iSet->second;
    else if (mpParentContainer.get() != NULL)
        return mpParentContainer->GetBitmap(rsName);
    else
        return SharedBitmapDescriptor();
}

void PresenterBitmapContainer::LoadBitmaps (
    const css::uno::Reference<css::container::XNameAccess>& rxBitmapList)
{
    if ( ! mxCanvas.is())
        return;

    if ( ! rxBitmapList.is())
        return;

    try
    {
        // Load all button bitmaps.
        if (rxBitmapList.is())
        {
            PresenterConfigurationAccess::ForAll(
                rxBitmapList,
                ::boost::bind(&PresenterBitmapContainer::ProcessBitmap, this, _1, _2));
        }
    }
    catch (Exception&)
    {
        OSL_ASSERT(false);
    }
}

SharedBitmapDescriptor PresenterBitmapContainer::LoadBitmap (
    const css::uno::Reference<css::container::XHierarchicalNameAccess>& rxNode,
    const ::rtl::OUString& rsPath,
    const css::uno::Reference<css::drawing::XPresenterHelper>& rxPresenterHelper,
    const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
    const SharedBitmapDescriptor& rpDefault)
{
    SharedBitmapDescriptor pBitmap;

    if (rxNode.is())
    {
        try
        {
            Reference<beans::XPropertySet> xBitmapProperties (
                PresenterConfigurationAccess::GetConfigurationNode(rxNode, rsPath),
                UNO_QUERY);
            if (xBitmapProperties.is())
                pBitmap = LoadBitmap(
                    xBitmapProperties,
                    rxPresenterHelper,
                    rxCanvas,
                    rpDefault);
        }
        catch (Exception&)
        {
            OSL_ASSERT(false);
        }
    }

    return pBitmap;
}

void PresenterBitmapContainer::ProcessBitmap (
    const OUString& rsKey,
    const Reference<beans::XPropertySet>& rxProperties)
{
    OUString sName;
    if ( ! (PresenterConfigurationAccess::GetProperty(rxProperties, gsNameProperty) >>= sName))
        sName = rsKey;

    maIconContainer[sName] = LoadBitmap(
        rxProperties,
        mxPresenterHelper,
        mxCanvas,
        SharedBitmapDescriptor());
}

SharedBitmapDescriptor PresenterBitmapContainer::LoadBitmap (
    const Reference<beans::XPropertySet>& rxProperties,
    const css::uno::Reference<css::drawing::XPresenterHelper>& rxPresenterHelper,
    const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
    const SharedBitmapDescriptor& rpDefault)
{
    OSL_ASSERT(rxCanvas.is());
    OSL_ASSERT(rxPresenterHelper.is());

    SharedBitmapDescriptor pBitmap (new BitmapDescriptor(rpDefault));

    if ( ! rxProperties.is())
        return pBitmap;

    OUString sFileName;

    // Load bitmaps.
    if (PresenterConfigurationAccess::GetProperty(rxProperties, gsNormalFileNameProperty) >>= sFileName)
        try
        {
            pBitmap->SetBitmap(
                BitmapDescriptor::Normal,
                rxPresenterHelper->loadBitmap(sFileName, rxCanvas));
        }
        catch (Exception&)
        {}
    if (PresenterConfigurationAccess::GetProperty(rxProperties, gsMouseOverFileNameProperty) >>= sFileName)
        try
        {
            pBitmap->SetBitmap(
                BitmapDescriptor::MouseOver,
                rxPresenterHelper->loadBitmap(sFileName, rxCanvas));
        }
        catch (Exception&)
        {}
    if (PresenterConfigurationAccess::GetProperty(rxProperties, gsButtonDownFileNameProperty) >>= sFileName)
        try
        {
            pBitmap->SetBitmap(
                BitmapDescriptor::ButtonDown,
                rxPresenterHelper->loadBitmap(sFileName, rxCanvas));
        }
        catch (Exception&)
        {}
    if (PresenterConfigurationAccess::GetProperty(rxProperties, gsDisabledFileNameProperty) >>= sFileName)
        try
        {
            pBitmap->SetBitmap(
                BitmapDescriptor::Disabled,
                rxPresenterHelper->loadBitmap(sFileName, rxCanvas));
        }
        catch (Exception&)
        {}
    if (PresenterConfigurationAccess::GetProperty(rxProperties, gsMaskFileNameProperty) >>= sFileName)
        try
        {
            pBitmap->SetBitmap(
                BitmapDescriptor::Mask,
                rxPresenterHelper->loadBitmap(sFileName, rxCanvas));
        }
        catch (Exception&)
        {}

    PresenterConfigurationAccess::GetProperty(rxProperties, gsXOffsetProperty) >>= pBitmap->mnXOffset;
    PresenterConfigurationAccess::GetProperty(rxProperties, gsYOffsetProperty) >>= pBitmap->mnYOffset;

    PresenterConfigurationAccess::GetProperty(rxProperties, gsXHotSpotProperty) >>= pBitmap->mnXHotSpot;
    PresenterConfigurationAccess::GetProperty(rxProperties, gsYHotSpotProperty) >>= pBitmap->mnYHotSpot;

    PresenterConfigurationAccess::GetProperty(rxProperties, gsReplacementColorProperty) >>= pBitmap->maReplacementColor;

    OUString sTexturingMode;
    if (PresenterConfigurationAccess::GetProperty(rxProperties, gsHorizontalTexturingModeProperty) >>= sTexturingMode)
        pBitmap->meHorizontalTexturingMode = StringToTexturingMode(sTexturingMode);
    if (PresenterConfigurationAccess::GetProperty(rxProperties, gsVerticalTexturingModeProperty) >>= sTexturingMode)
        pBitmap->meVerticalTexturingMode = StringToTexturingMode(sTexturingMode);

    return pBitmap;
}

PresenterBitmapContainer::BitmapDescriptor::TexturingMode
    PresenterBitmapContainer::StringToTexturingMode (const OUString& rsTexturingMode)
{
    if (rsTexturingMode == A2S("Once"))
        return PresenterBitmapContainer::BitmapDescriptor::Once;
    else if (rsTexturingMode == A2S("Repeat"))
        return PresenterBitmapContainer::BitmapDescriptor::Repeat;
    else if (rsTexturingMode == A2S("Stretch"))
        return PresenterBitmapContainer::BitmapDescriptor::Stretch;
    else
        return PresenterBitmapContainer::BitmapDescriptor::Once;
}

//===== PresenterBitmapContainer::BitmapSet ===================================

PresenterBitmapContainer::BitmapDescriptor::BitmapDescriptor (void)
    : mnWidth(0),
      mnHeight(0),
      mnXOffset(0),
      mnYOffset(0),
      mnXHotSpot(0),
      mnYHotSpot(0),
      maReplacementColor(0x00000000),
      meHorizontalTexturingMode(Once),
      meVerticalTexturingMode(Once),
      mxNormalBitmap(),
      mxMouseOverBitmap(),
      mxButtonDownBitmap(),
      mxDisabledBitmap(),
      mxMaskBitmap()
{
}

PresenterBitmapContainer::BitmapDescriptor::BitmapDescriptor (
    const ::boost::shared_ptr<PresenterBitmapContainer::BitmapDescriptor>& rpDefault)
    : mnWidth(0),
      mnHeight(0),
      mnXOffset(0),
      mnYOffset(0),
      mnXHotSpot(0),
      mnYHotSpot(0),
      maReplacementColor(0x00000000),
      meHorizontalTexturingMode(Once),
      meVerticalTexturingMode(Once),
      mxNormalBitmap(),
      mxMouseOverBitmap(),
      mxButtonDownBitmap(),
      mxDisabledBitmap(),
      mxMaskBitmap()
{
    if (rpDefault.get() != NULL)
    {
        mnWidth = rpDefault->mnWidth;
        mnHeight = rpDefault->mnHeight;
        mnXOffset = rpDefault->mnXOffset;
        mnYOffset = rpDefault->mnYOffset;
        mnXHotSpot = rpDefault->mnXHotSpot;
        mnYHotSpot = rpDefault->mnYHotSpot;
        maReplacementColor = rpDefault->maReplacementColor;
        meHorizontalTexturingMode = rpDefault->meHorizontalTexturingMode;
        meVerticalTexturingMode = rpDefault->meVerticalTexturingMode;
        mxNormalBitmap = rpDefault->mxNormalBitmap;
        mxMouseOverBitmap = rpDefault->mxMouseOverBitmap;
        mxButtonDownBitmap = rpDefault->mxButtonDownBitmap;
        mxDisabledBitmap = rpDefault->mxDisabledBitmap;
        mxMaskBitmap = rpDefault->mxMaskBitmap;
    }
}

css::uno::Reference<css::rendering::XBitmap>
    PresenterBitmapContainer::BitmapDescriptor::GetNormalBitmap (void) const
{
    return mxNormalBitmap;
}

css::uno::Reference<css::rendering::XBitmap>
    PresenterBitmapContainer::BitmapDescriptor::GetBitmap (
        const Mode eMode,
        const bool bMissingDefaultsToNormal) const
{
    switch (eMode)
    {
        case Normal:
        default:
            return mxNormalBitmap;

        case MouseOver:
            if (mxMouseOverBitmap.is())
                return mxMouseOverBitmap;
            else if (bMissingDefaultsToNormal)
                return mxNormalBitmap;

        case ButtonDown:
            if (mxButtonDownBitmap.is())
                return mxButtonDownBitmap;
            else if (bMissingDefaultsToNormal)
                return mxNormalBitmap;

        case Disabled:
            if (mxDisabledBitmap.is())
                return mxDisabledBitmap;
            else if (bMissingDefaultsToNormal)
                return mxNormalBitmap;

        case Mask:
            return mxMaskBitmap;
    }
    return NULL;
}

void PresenterBitmapContainer::BitmapDescriptor::SetBitmap (
    const Mode eMode,
    const css::uno::Reference<css::rendering::XBitmap>& rxBitmap)
{
    switch (eMode)
    {
        case Normal:
        default:
            mxNormalBitmap = rxBitmap;
            if (mxNormalBitmap.is())
            {
                const geometry::IntegerSize2D aSize (mxNormalBitmap->getSize());
                mnWidth = aSize.Width;
                mnHeight = aSize.Height;
            }
            break;

        case MouseOver:
            mxMouseOverBitmap = rxBitmap;
            break;

        case ButtonDown:
            mxButtonDownBitmap = rxBitmap;
            break;

        case Disabled:
            mxDisabledBitmap = rxBitmap;
            break;

        case Mask:
            mxMaskBitmap = rxBitmap;
            break;
    }
}

} } // end of namespace ::sdext::presenter

ext: cxx

max_stars_repo_name: Grosskopf/openoffice

max_issues_repo_name: Grosskopf/openoffice

max_forks_repo_name: Grosskopf/openoffice


text:
//
// Copyright (c) 2021 Richard Hodges (hodges.r@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/madmongo1/router
//

#include "boost/connector/vendor/ftx/order_book_impl.hpp"

#include <boost/asio/co_spawn.hpp>
#include <boost/asio/compose.hpp>
#include <boost/asio/experimental/append.hpp>
#include <boost/asio/experimental/awaitable_operators.hpp>
#include <boost/connector/config/error.hpp>
#include <boost/connector/util/async_circular_buffer.hpp>
#include <boost/connector/util/async_void.hpp>
#include <boost/connector/vendor/ftx/order_book_impl.hpp>
#include <boost/json.hpp>

#include <iostream>

namespace boost::connector::vendor::ftx
{
order_book_impl::order_book_impl(websocket_connector connection,
                                     std::string         market)
: upstream_subscription_impl(
      std::move(connection),
      channel_market_pair { .channel = "orderbook",
                            .market  = std::move(market) })
{
}

namespace
{
void
enter(std::string_view f)
{
    std::cout << f << " - enter\n";
}
void
exit_success(std::string_view f)
{
    std::cout << f << " - exit success\n";
}
void
exit_exception(std::string_view f, std::exception &e)
{
    std::cout << f << " - exit exception: " << e.what() << "\n";
}

asio::awaitable< void >
wait_for_unsub_confirmation(
    websocket_connector                     &connector,
    async_circular_buffer< json::value, 1 > &frame_buffer)
try
{
    using namespace asio::experimental::awaitable_operators;
    enter("wait_for_unsub_confirmation");

    for (;;)
    {
        auto which = co_await(connector.wait_down() || frame_buffer.pop());
        switch (which.index())
        {
        case 0:
            co_return;

        case 1:
            auto const &frame = get< json::value >(which);
            auto const &type  = frame.at("type").as_string();
            if (type == "unsubscribed")
                co_return;
        }
    }
    exit_success("wait_for_unsub_confirmation");
}
catch (std::exception &e)
{
    exit_exception("wait_for_unsub_confirmation", e);
}

}   // namespace

}   // namespace boost::connector::vendor::ftx