<commit_before>/*
 * TI Voxel Lib component.
 *
 * Copyright (c) 2014 Texas Instruments Inc.
 */

#include "CalculusCDKCamera.h"
#include "VoxelUSBProgrammer.h"
#include <Logger.h>
#include <USBBulkStreamer.h>

#include <Parameter.h>
#define _USE_MATH_DEFINES
#include <math.h>

#include "USBSystem.h"

#define REQUEST_EEPROM_SIZE 0x31
#define REQUEST_EEPROM_DATA 0x33

namespace Voxel
{

namespace TI
{

CalculusCDKCamera::CalculusCDKCamera(Voxel::DevicePtr device): ToFCalculusCamera("CalculusCDKCamera", device)
{
  _init();
}

class CalculusCDKMixVoltageParameter: public UnsignedIntegerParameter
{
protected:
  virtual uint _fromRawValue(uint32_t value) const
  {
    if(value > 0x1AU)
      return 2000;
    else if (value == 0)
      return 800;
    else
      return (value)*50 + 750;
  }

  virtual uint32_t _toRawValue(uint value) const
  {
    if(value < 800)
      return 0x00U;
    else
      return (value - 750)/50;
  }

public:
  CalculusCDKMixVoltageParameter(RegisterProgrammer &programmer):
  UnsignedIntegerParameter(programmer, MIX_VOLTAGE, "mV", 0x6023, 8, 7, 0, 800, 2000, 1800, "Mixing voltage",
                           "Mixing voltage?", Parameter::IO_READ_WRITE, {})
  {}

  virtual ~CalculusCDKMixVoltageParameter() {}
};

class CalculusCDKIlluminationPowerParameter: public UnsignedIntegerParameter
{
protected:
  virtual bool get(uint &value, bool refresh = false)
  {
    value = uint(300);
    return true;
  }

  virtual bool set(const uint &value)
  {
    return true;
  }

#if 0
  virtual uint _fromRawValue(uint32_t value) const
  {
    return uint(299);
  }

  virtual uint32_t _toRawValue(uint value) const
  {
    return uint32_t(299);
  }
#endif

public:
  CalculusCDKIlluminationPowerParameter(RegisterProgrammer &programmer):
  UnsignedIntegerParameter(programmer, ILLUM_POWER, "mW", 0, 0, 0, 0, 0, 300, 300, "Illumination Power", "These power numbers are approximate.", Parameter::IO_READ_WRITE, {})
  {}

  virtual ~CalculusCDKIlluminationPowerParameter() {}
};

class CalculusCDKIlluminationPowerPercentParameter: public UnsignedIntegerParameter
{
protected:
  CalculusCDKCamera &_depthCamera;

public:
  CalculusCDKIlluminationPowerPercentParameter(CalculusCDKCamera &depthCamera, RegisterProgrammer &programmer):
  UnsignedIntegerParameter(programmer, ILLUM_POWER_PERCENTAGE, "%", 0, 0, 0, 0, 0, 100, 100, "Illumination Power",
                          "These power numbers are approximate", Parameter::IO_READ_WRITE, {}),
                          _depthCamera(depthCamera)
  {}

  virtual bool get(uint &value, bool refresh = false)
  {
    uint v;
    value = (uint)((100.0f));
    return true;
  }

  virtual bool set(const uint &value)
  {
    return true;
  }

  virtual ~CalculusCDKIlluminationPowerPercentParameter() {}
};

class CalculusCDKIllumCurrentParameter: public UnsignedIntegerParameter
{
protected:
  virtual uint _fromRawValue(uint32_t value) const
  {
    uint8_t lsbyte = value & 0xFF;
    uint8_t msbyte = (value >> 8) & 0xFF;
    uint current = (lsbyte << 8) + msbyte;
    // Calibration register is set to 6991 to get about 122.07 uA/bit
    return (current * 0.12207);
  }

//   virtual uint32_t _toRawValue(uint value) const
//   {
//     return (255U * value / 3300U);
//   }

public:
  CalculusCDKIllumCurrentParameter(RegisterProgrammer &programmer):
  UnsignedIntegerParameter(programmer, "illum_current", "mA", 0x4E04, 8, 7, 0, 0, 8000, 0000, "Illumination Current",
                           "This is the current on the illumination 5V rail.", Parameter::IO_READ_ONLY, {})
  {}

  virtual ~CalculusCDKIllumCurrentParameter() {}
};

class CalculusCDKMainCurrentParameter: public UnsignedIntegerParameter
{
protected:
  virtual uint _fromRawValue(uint32_t value) const
  {
    uint8_t lsbyte = value & 0xFF;
    uint8_t msbyte = (value >> 8) & 0xFF;
    uint current = (lsbyte << 8) + msbyte;

    // Calibration register is set to 1864 to get about 61.035 uA/bit
    return (current * 0.061035);
  }

//   virtual uint32_t _toRawValue(uint value) const
//   {
//     return (255U * value / 3300U);
//   }

public:
  CalculusCDKMainCurrentParameter(RegisterProgrammer &programmer):
  UnsignedIntegerParameter(programmer, "main_current", "mA", 0x4B04, 8, 7, 0, 0, 2000, 0000, "Main Board Current",
                           "This is the current drawn by the main board.", Parameter::IO_READ_ONLY, {})
  {}

  virtual ~CalculusCDKMainCurrentParameter() {}
};

bool CalculusCDKCamera::_init()
{
  USBDevice &d = (USBDevice &)*_device;

  DevicePtr controlDevice;

  controlDevice = _device;

  _usbIO = USBIOPtr(new USBIO(controlDevice));

  _programmer = Ptr<RegisterProgrammer>(new VoxelUSBProgrammer(
    { {0x58, 3}, {0x60, 1}, {0x4B, 2}, {0x4E, 2} },
    {
      {0x58, {0x08, 0x09, 0}},
      {0x4B, {0x0A, 0x0B, 0}},
      {0x4E, {0x0A, 0x0B, 0}},
      {0x60, {0x0C, 0x0D, 0}},
    }, _usbIO,
    controlDevice));

  _streamer = Ptr<Streamer>(new USBBulkStreamer(_usbIO, controlDevice, 0x82));

  if(!_programmer->isInitialized() || !_streamer->isInitialized())
    return false;

  if (!_addParameters({
    ParameterPtr(new CalculusCDKMixVoltageParameter(*_programmer)),
    ParameterPtr(new CalculusCDKMainCurrentParameter(*_programmer)),
    ParameterPtr(new CalculusCDKIllumCurrentParameter(*_programmer)),
    ParameterPtr(new CalculusCDKIlluminationPowerParameter(*_programmer)),
    ParameterPtr(new CalculusCDKIlluminationPowerPercentParameter(*this, *_programmer)),
    ParameterPtr(new CalculusModulationFrequencyParameter(*this, *_programmer, 12, 37, 18)),
    ParameterPtr(new CalculusUnambiguousRangeParameter(*this, *_programmer, 4, 50, 5)),
    }))
  {
    return false;
  }

  /* INA226 initializations: note byteswapped for now */
  if (!_programmer->writeRegister(0x4B00, 0x274F) ||
    !_programmer->writeRegister(0x4E00, 0x274F) ||
    !_programmer->writeRegister(0x4B05, 0x4807) ||
    !_programmer->writeRegister(0x4E05, 0x4F1B)
  )
    return false;

  if(!ToFCalculusCamera::_init())
    return false;

  // Initialize serializer block
  configFile.setHardwareConfigSerializer(new HardwareSerializer(_usbIO, REQUEST_EEPROM_DATA, REQUEST_EEPROM_SIZE));

  FrameSize s;

  if(!getFrameSize(s))
  {
    logger(LOG_ERROR) << "CalculusCDKCamera: Unable to get frame size" << std::endl;
    return false;
  }

  if(!_setStreamerFrameSize(s))
  {
    logger(LOG_ERROR) << "CalculusCDKCamera: Unable to set frame size for USBBulkStreamer" << std::endl;
    return false;
  }

  return true;
}

bool CalculusCDKCamera::_initStartParams()
{
  if (!ToFCalculusCamera::_initStartParams())
    return false;

  VoxelUSBProgrammer *programmer = dynamic_cast<VoxelUSBProgrammer *>(&*_programmer);

  if(!programmer)
  {
    logger(LOG_ERROR) << "CalculusCDKCamera: Streamer is not of type VoxelUSBProgrammer" << std::endl;
    return false;
  }

  uint16_t length = 0;

  if(
    // Enable Slave Fifo, reqCode 0x12
    !_usbIO->controlTransfer(USBIO::TO_DEVICE, USBIO::REQUEST_VENDOR, USBIO::RECIPIENT_DEVICE, 0x12, 0x00, 0x00, 0, length) ||
    // Set VD Counter to 1300 for now
    !_usbIO->controlTransfer(USBIO::TO_DEVICE, USBIO::REQUEST_VENDOR, USBIO::RECIPIENT_DEVICE, 0x13, 1300, 0x00, 0, length) ||
    // Enable FSC
    !_usbIO->controlTransfer(USBIO::TO_DEVICE, USBIO::REQUEST_VENDOR, USBIO::RECIPIENT_DEVICE, 0x10, 0x0001, 0x00, 0, length))
    return false;

  return true;
}

bool CalculusCDKCamera::_getFieldOfView(float &fovHalfAngle) const
{
  fovHalfAngle = (87/2.0f)*(M_PI/180.0f);
  return true;
}

bool CalculusCDKCamera::_setStreamerFrameSize(const FrameSize &s)
{
  USBBulkStreamer *streamer = dynamic_cast<USBBulkStreamer *>(&*_streamer);

  if(!streamer)
  {
    logger(LOG_ERROR) << "CalculusCDKCamera: Streamer is not of type USBBulkStreamer" << std::endl;
    return false;
  }

  uint bytesPerPixel;

  if(!_getBytesPerPixel(bytesPerPixel))
  {
    logger(LOG_ERROR) << "CalculusCDKCamera: Could not get current bytes per pixel" << std::endl;
    return false;
  }

  return streamer->setBufferSize(s.width*s.height*bytesPerPixel);
}

bool CalculusCDKCamera::_getSupportedVideoModes(Vector<SupportedVideoMode> &supportedVideoModes) const
{
  supportedVideoModes.clear();
  return true;
}

bool CalculusCDKCamera::_getMaximumVideoMode(VideoMode &videoMode) const
{
  videoMode.frameSize.width = 80;
  videoMode.frameSize.height = 60;
  videoMode.frameRate.denominator = 1;
  videoMode.frameRate.numerator = 100;
  return true;
}

bool CalculusCDKCamera::_getMaximumFrameRate(FrameRate &frameRate, const FrameSize &forFrameSize) const
{
  frameRate.numerator = 500; // To be later updated to use OP_CLK_FREQ
  frameRate.denominator = 1;
  return true;
}

}
}<commit_msg>CalculusCDKCamera: bugfix: set HardwareSerializer before calling parent init<commit_after>/*
 * TI Voxel Lib component.
 *
 * Copyright (c) 2014 Texas Instruments Inc.
 */

#include "CalculusCDKCamera.h"
#include "VoxelUSBProgrammer.h"
#include <Logger.h>
#include <USBBulkStreamer.h>

#include <Parameter.h>
#define _USE_MATH_DEFINES
#include <math.h>

#include "USBSystem.h"

#define REQUEST_EEPROM_SIZE 0x31
#define REQUEST_EEPROM_DATA 0x33

namespace Voxel
{

namespace TI
{

CalculusCDKCamera::CalculusCDKCamera(Voxel::DevicePtr device): ToFCalculusCamera("CalculusCDKCamera", device)
{
  _init();
}

class CalculusCDKMixVoltageParameter: public UnsignedIntegerParameter
{
protected:
  virtual uint _fromRawValue(uint32_t value) const
  {
    if(value > 0x1AU)
      return 2000;
    else if (value == 0)
      return 800;
    else
      return (value)*50 + 750;
  }

  virtual uint32_t _toRawValue(uint value) const
  {
    if(value < 800)
      return 0x00U;
    else
      return (value - 750)/50;
  }

public:
  CalculusCDKMixVoltageParameter(RegisterProgrammer &programmer):
  UnsignedIntegerParameter(programmer, MIX_VOLTAGE, "mV", 0x6023, 8, 7, 0, 800, 2000, 1800, "Mixing voltage",
                           "Mixing voltage?", Parameter::IO_READ_WRITE, {})
  {}

  virtual ~CalculusCDKMixVoltageParameter() {}
};

class CalculusCDKIlluminationPowerParameter: public UnsignedIntegerParameter
{
protected:
  virtual bool get(uint &value, bool refresh = false)
  {
    value = uint(300);
    return true;
  }

  virtual bool set(const uint &value)
  {
    return true;
  }

#if 0
  virtual uint _fromRawValue(uint32_t value) const
  {
    return uint(299);
  }

  virtual uint32_t _toRawValue(uint value) const
  {
    return uint32_t(299);
  }
#endif

public:
  CalculusCDKIlluminationPowerParameter(RegisterProgrammer &programmer):
  UnsignedIntegerParameter(programmer, ILLUM_POWER, "mW", 0, 0, 0, 0, 0, 300, 300, "Illumination Power", "These power numbers are approximate.", Parameter::IO_READ_WRITE, {})
  {}

  virtual ~CalculusCDKIlluminationPowerParameter() {}
};

class CalculusCDKIlluminationPowerPercentParameter: public UnsignedIntegerParameter
{
protected:
  CalculusCDKCamera &_depthCamera;

public:
  CalculusCDKIlluminationPowerPercentParameter(CalculusCDKCamera &depthCamera, RegisterProgrammer &programmer):
  UnsignedIntegerParameter(programmer, ILLUM_POWER_PERCENTAGE, "%", 0, 0, 0, 0, 0, 100, 100, "Illumination Power",
                          "These power numbers are approximate", Parameter::IO_READ_WRITE, {}),
                          _depthCamera(depthCamera)
  {}

  virtual bool get(uint &value, bool refresh = false)
  {
    uint v;
    value = (uint)((100.0f));
    return true;
  }

  virtual bool set(const uint &value)
  {
    return true;
  }

  virtual ~CalculusCDKIlluminationPowerPercentParameter() {}
};

class CalculusCDKIllumCurrentParameter: public UnsignedIntegerParameter
{
protected:
  virtual uint _fromRawValue(uint32_t value) const
  {
    uint8_t lsbyte = value & 0xFF;
    uint8_t msbyte = (value >> 8) & 0xFF;
    uint current = (lsbyte << 8) + msbyte;
    // Calibration register is set to 6991 to get about 122.07 uA/bit
    return (current * 0.12207);
  }

//   virtual uint32_t _toRawValue(uint value) const
//   {
//     return (255U * value / 3300U);
//   }

public:
  CalculusCDKIllumCurrentParameter(RegisterProgrammer &programmer):
  UnsignedIntegerParameter(programmer, "illum_current", "mA", 0x4E04, 8, 7, 0, 0, 8000, 0000, "Illumination Current",
                           "This is the current on the illumination 5V rail.", Parameter::IO_READ_ONLY, {})
  {}

  virtual ~CalculusCDKIllumCurrentParameter() {}
};

class CalculusCDKMainCurrentParameter: public UnsignedIntegerParameter
{
protected:
  virtual uint _fromRawValue(uint32_t value) const
  {
    uint8_t lsbyte = value & 0xFF;
    uint8_t msbyte = (value >> 8) & 0xFF;
    uint current = (lsbyte << 8) + msbyte;

    // Calibration register is set to 1864 to get about 61.035 uA/bit
    return (current * 0.061035);
  }

//   virtual uint32_t _toRawValue(uint value) const
//   {
//     return (255U * value / 3300U);
//   }

public:
  CalculusCDKMainCurrentParameter(RegisterProgrammer &programmer):
  UnsignedIntegerParameter(programmer, "main_current", "mA", 0x4B04, 8, 7, 0, 0, 2000, 0000, "Main Board Current",
                           "This is the current drawn by the main board.", Parameter::IO_READ_ONLY, {})
  {}

  virtual ~CalculusCDKMainCurrentParameter() {}
};

bool CalculusCDKCamera::_init()
{
  USBDevice &d = (USBDevice &)*_device;

  DevicePtr controlDevice;

  controlDevice = _device;

  _usbIO = USBIOPtr(new USBIO(controlDevice));

  _programmer = Ptr<RegisterProgrammer>(new VoxelUSBProgrammer(
    { {0x58, 3}, {0x60, 1}, {0x4B, 2}, {0x4E, 2} },
    {
      {0x58, {0x08, 0x09, 0}},
      {0x4B, {0x0A, 0x0B, 0}},
      {0x4E, {0x0A, 0x0B, 0}},
      {0x60, {0x0C, 0x0D, 0}},
    }, _usbIO,
    controlDevice));

  _streamer = Ptr<Streamer>(new USBBulkStreamer(_usbIO, controlDevice, 0x82));

  if(!_programmer->isInitialized() || !_streamer->isInitialized())
    return false;

  if (!_addParameters({
    ParameterPtr(new CalculusCDKMixVoltageParameter(*_programmer)),
    ParameterPtr(new CalculusCDKMainCurrentParameter(*_programmer)),
    ParameterPtr(new CalculusCDKIllumCurrentParameter(*_programmer)),
    ParameterPtr(new CalculusCDKIlluminationPowerParameter(*_programmer)),
    ParameterPtr(new CalculusCDKIlluminationPowerPercentParameter(*this, *_programmer)),
    ParameterPtr(new CalculusModulationFrequencyParameter(*this, *_programmer, 12, 37, 18)),
    ParameterPtr(new CalculusUnambiguousRangeParameter(*this, *_programmer, 4, 50, 5)),
    }))
  {
    return false;
  }

  /* INA226 initializations: note byteswapped for now */
  if (!_programmer->writeRegister(0x4B00, 0x274F) ||
    !_programmer->writeRegister(0x4E00, 0x274F) ||
    !_programmer->writeRegister(0x4B05, 0x4807) ||
    !_programmer->writeRegister(0x4E05, 0x4F1B)
  )
    return false;

  // Initialize serializer block
  configFile.setHardwareConfigSerializer(new HardwareSerializer(_usbIO, REQUEST_EEPROM_DATA, REQUEST_EEPROM_SIZE));

  if(!ToFCalculusCamera::_init())
    return false;

  FrameSize s;

  if(!getFrameSize(s))
  {
    logger(LOG_ERROR) << "CalculusCDKCamera: Unable to get frame size" << std::endl;
    return false;
  }

  if(!_setStreamerFrameSize(s))
  {
    logger(LOG_ERROR) << "CalculusCDKCamera: Unable to set frame size for USBBulkStreamer" << std::endl;
    return false;
  }

  return true;
}

bool CalculusCDKCamera::_initStartParams()
{
  if (!ToFCalculusCamera::_initStartParams())
    return false;

  VoxelUSBProgrammer *programmer = dynamic_cast<VoxelUSBProgrammer *>(&*_programmer);

  if(!programmer)
  {
    logger(LOG_ERROR) << "CalculusCDKCamera: Streamer is not of type VoxelUSBProgrammer" << std::endl;
    return false;
  }

  uint16_t length = 0;

  if(
    // Enable Slave Fifo, reqCode 0x12
    !_usbIO->controlTransfer(USBIO::TO_DEVICE, USBIO::REQUEST_VENDOR, USBIO::RECIPIENT_DEVICE, 0x12, 0x00, 0x00, 0, length) ||
    // Set VD Counter to 1300 for now
    !_usbIO->controlTransfer(USBIO::TO_DEVICE, USBIO::REQUEST_VENDOR, USBIO::RECIPIENT_DEVICE, 0x13, 1300, 0x00, 0, length) ||
    // Enable FSC
    !_usbIO->controlTransfer(USBIO::TO_DEVICE, USBIO::REQUEST_VENDOR, USBIO::RECIPIENT_DEVICE, 0x10, 0x0001, 0x00, 0, length))
    return false;

  return true;
}

bool CalculusCDKCamera::_getFieldOfView(float &fovHalfAngle) const
{
  fovHalfAngle = (87/2.0f)*(M_PI/180.0f);
  return true;
}

bool CalculusCDKCamera::_setStreamerFrameSize(const FrameSize &s)
{
  USBBulkStreamer *streamer = dynamic_cast<USBBulkStreamer *>(&*_streamer);

  if(!streamer)
  {
    logger(LOG_ERROR) << "CalculusCDKCamera: Streamer is not of type USBBulkStreamer" << std::endl;
    return false;
  }

  uint bytesPerPixel;

  if(!_getBytesPerPixel(bytesPerPixel))
  {
    logger(LOG_ERROR) << "CalculusCDKCamera: Could not get current bytes per pixel" << std::endl;
    return false;
  }

  return streamer->setBufferSize(s.width*s.height*bytesPerPixel);
}

bool CalculusCDKCamera::_getSupportedVideoModes(Vector<SupportedVideoMode> &supportedVideoModes) const
{
  supportedVideoModes.clear();
  return true;
}

bool CalculusCDKCamera::_getMaximumVideoMode(VideoMode &videoMode) const
{
  videoMode.frameSize.width = 80;
  videoMode.frameSize.height = 60;
  videoMode.frameRate.denominator = 1;
  videoMode.frameRate.numerator = 100;
  return true;
}

bool CalculusCDKCamera::_getMaximumFrameRate(FrameRate &frameRate, const FrameSize &forFrameSize) const
{
  frameRate.numerator = 500; // To be later updated to use OP_CLK_FREQ
  frameRate.denominator = 1;
  return true;
}

}
}<|endoftext|>


<commit_before>//
//  pfilter.cpp
//  EpiGenMCMC
//
//  Created by Lucy Li on 05/05/2016.
//  Copyright (c) 2016 Lucy Li, Imperial College London. All rights reserved.
//

#include "pfilter.h"
#include <iostream>

namespace EpiGenPfilter {
    double pfilter(Model & sim_model, Parameter & model_params, MCMCoptions & options, Particle &particles, Trajectory & output_traj, TimeSeriesData &epi_data, TreeData &tree_data, MultiTreeData &multitree_data) {
        int thread_max = std::min(options.num_threads, omp_get_max_threads());
        gsl_rng** rngs = new gsl_rng*[thread_max];
        for (int thread = 0; thread < thread_max; thread++) {
            rngs[thread] = gsl_rng_alloc(gsl_rng_mt19937);
            gsl_rng_set(rngs[thread], omp_get_thread_num() + thread);
        }

        double loglik = 0.0;
        int num_groups = options.num_groups;
        int num_particles = options.particles;
        int init_seed = options.seed;
        int total_dt = options.total_dt;
        double sim_dt = options.sim_dt;
        int total_steps = ceil((double)total_dt/(double)options.pfilter_every);
        int add_dt = 0;
        double ESS_threshold = options.pfilter_threshold*(double)num_particles;
        Likelihood likelihood_calc;
        //        std::vector <Parameter> values;// (options.num_threads, model_params);
        //        for (int i=0; i!=options.num_threads; ++i) values.push_back(model_params);
        //        for (int i=0; i!=model_params.get_total_params(); ++i) values.push_back(model_params.get(i));
        std::vector <std::vector<double> > values(options.num_threads, std::vector<double>(model_params.get_total_params(), 0.0));
        for (int i=0; i!=options.num_threads; ++i) {
            for (int j=0; j!=model_params.get_total_params(); ++j) {
                values[i][j] = model_params.get(j);
            }
        }
        // printf("Size of values = %d\n",values.size());
        double reporting_rate = 1.0;
        if (model_params.param_exists("reporting")) {
            reporting_rate = model_params.get("reporting");
        }
        else if (model_params.param_exists("reporting0")) {
            reporting_rate = model_params.get("reporting0");
        }
        std::vector <std::string> param_names = model_params.get_names_vector();
        std::vector <std::vector<std::string> > param_names_threads (options.num_threads);
        if (model_params.param_exists("time_before_data")) {
            add_dt = model_params.get("time_before_data");
        }
        if (options.save_traj) {
            if (add_dt > 0) {
                particles.start_particle_tracing(add_dt+total_dt, num_groups);
            }
            else if (add_dt < 0) {
                particles.start_particle_tracing(add_dt+total_dt, num_groups);
                total_steps = ceil((double)(total_dt+add_dt)/(double)options.pfilter_every);
            }
            else {
                particles.start_particle_tracing(total_dt, num_groups);
            }
        }
	std::vector <Model> models;
        for (int i=0; i<options.num_threads; ++i) {
            models.push_back(sim_model);
        }
        std::vector <int> add_dt_threads (options.num_threads, add_dt);
        std::vector <int> start_dt_threads (options.num_threads, 0);
        std::vector <int> end_dt_threads (options.num_threads, add_dt);
        std::vector <double> dt_threads (options.num_threads, sim_dt);
        std::vector <int> total_dt_threads(options.num_threads, total_dt);
        std::vector <double> reporting_rate_threads(options.num_threads, reporting_rate);
        std::vector <int> num_groups_threads(options.num_threads, num_groups);
        // Simulate model and calculate likelihood assuming no observed data
        if (model_params.param_exists("time_before_data")) {
            if (add_dt > 0) {
                omp_set_num_threads(options.num_threads);
                //                std::vector <Trajectory *> curr_trajs;
                //                for (int i=0; i!=num_particles; ++i) {
                //                    curr_trajs.push_back(particles.get_traj(i));
                //                }
#pragma omp parallel for shared(particles, values) schedule(static,1)
                for (int tn = 0; tn < thread_max; tn++) {
                    for (int i = tn; i < num_particles; i += thread_max) {
                        // Adjust length of trajectory
                        particles.get_traj(i)->resize(add_dt, num_groups);
                        models[tn].simulate(values[tn], param_names_threads[tn], particles.get_traj(i), 0, add_dt_threads[tn], dt_threads[tn], total_dt_threads[tn], rngs[tn]);
                        if (options.which_likelihood < 2) {
                            double w = likelihood_calc.binomial_lik(reporting_rate_threads[tn], particles.get_traj(i)->get_total_traj(), add_dt_threads[tn] + total_dt_threads[tn], 0, add_dt_threads[tn], num_groups_threads[tn], false);
                            particles.set_weight(w, i, false);
                        }
                        if (options.save_traj) {
                            particles.save_traj_to_matrix(i, 0, add_dt);
                            particles.save_ancestry(i, 0, add_dt);
                        }
                    }
                }
            }
        }
        init_seed += num_particles;
        int t=0;
        int start_dt;
        int end_dt;
        for (t = 0; t != total_steps; ++t) {
            // std::vector<double> we(options.particles, 0.0), wg(options.particles, 0.0);
            start_dt = t*options.pfilter_every;
            end_dt = std::min(total_dt, (t + 1)*options.pfilter_every);
            if (model_params.param_exists("reportingT0")) {
                int time_change_i = 0;
                bool reporting_rate_found = false;
                reporting_rate = model_param.get("reporting0");
                while (model_params.param_exists("reportingT"+std::to_string(time_change_i))) {
                    if (end_dt >= model_params.get("reportingT"+std::to_string(time_change_i))) {
                        reporting_rate *= model_params.get("reporting"+std::to_string(time_change_i+1));
                    }
                }
            }
            std::fill(start_dt_threads.begin(), start_dt_threads.end(), start_dt);
            std::fill(end_dt_threads.begin(), end_dt_threads.end(), end_dt);
            omp_set_num_threads(options.num_threads);
#pragma omp parallel for shared (particles, values) schedule(static,1)
            for (int tn = 0; tn < thread_max; tn++) {
                for (int i = tn; i < num_particles; i+=thread_max) {
                    // Adjust length of trajectory
                    //                    if (tn==0) std::cout << i << ' ' << std::endl;
                    particles.get_traj(i)->resize(end_dt - start_dt, options.num_groups);
                    models[tn].simulate(values[tn], param_names_threads[tn], particles.get_traj(i), start_dt_threads[tn], end_dt_threads[tn], dt_threads[tn], total_dt_threads[tn], rngs[tn]);
                    double w = 1.0;
                    double temp = 0.0;
                    if (options.which_likelihood < 2) {
                        double A = particles.get_traj(i)->get_total_traj();
                        temp = likelihood_calc.binomial_lik(reporting_rate_threads[tn], A, epi_data.get_data_ptr(0), add_dt_threads[tn] + total_dt_threads[tn], start_dt_threads[tn], end_dt_threads[tn], add_dt_threads[tn], num_groups_threads[tn], false);
                        w *= temp;
                        // we[i] = log(temp);
                    }
                    if (options.which_likelihood != 1) {
                        temp = likelihood_calc.coalescent_lik(particles.get_traj(i)->get_traj_ptr(0, 0), particles.get_traj(i)->get_traj_ptr(1, 0),
                                                              tree_data.get_binomial_ptr(0), tree_data.get_interval_ptr(0), tree_data.get_ends_ptr(0),
                                                              start_dt_threads[tn], end_dt_threads[tn], add_dt_threads[tn], false);
                        w *= temp;
                        // wg[i] = log(temp);
                    }
                    particles.set_weight(w, i, true);
                    if (options.save_traj) {
                        particles.save_traj_to_matrix(i, start_dt_threads[tn] + add_dt_threads[tn], end_dt_threads[tn] + add_dt_threads[tn]);
                        particles.save_ancestry(i, start_dt_threads[tn] + add_dt_threads[tn], end_dt_threads[tn] + add_dt_threads[tn]);
                    }
                }
            }
            // std::cout << "Epi Weight: " << std::accumulate(we.begin(), we.end(), 0.0) << " Gen Weight: " << std::accumulate(wg.begin(), wg.end(), 0.0) << " Total: " << particles.get_total_weight() << std::endl;
	    double curr_ESS = particles.get_ESS();
            if (curr_ESS < ESS_threshold) {
                double total_weight = particles.get_total_weight();
                if (total_weight == 0.0) {
                    loglik += -0.1*std::numeric_limits<double>::max();
                    //                    std::cout << std::accumulate(epi_data.get_data_ptr(0)+start_dt, epi_data.get_data_ptr(0)+end_dt, 0.0) << " : " << particles.get_traj(0)->get_traj(0) << std::endl;
                    std::cout << "stop time: " << end_dt << std::endl;
                    break;
                } else {
                    loglik += log(total_weight) - log(num_particles);
                }
                particles.resample(options.rng[0]);
            }
            else {
                particles.reset_parents();
            }
        }
        if (options.save_traj) {
            output_traj.resize((total_dt+add_dt), num_groups);
            //if (loglik > -0.1*std::numeric_limits<double>::max()) {
            particles.retrace_traj(output_traj, options.rng[0]);
            //}
        }
        for (int i=0; i!=num_particles; ++i) {
            particles.get_traj(i)->reset();
        }
        std::vector < std::vector<double> >().swap(values);

        for (int thread = 0; thread < thread_max; thread++) {
            gsl_rng_free(rngs[thread]);
        }
        delete[] rngs;

        return (loglik);
    }
}

<commit_msg>corrected spelling error<commit_after>//
//  pfilter.cpp
//  EpiGenMCMC
//
//  Created by Lucy Li on 05/05/2016.
//  Copyright (c) 2016 Lucy Li, Imperial College London. All rights reserved.
//

#include "pfilter.h"
#include <iostream>

namespace EpiGenPfilter {
    double pfilter(Model & sim_model, Parameter & model_params, MCMCoptions & options, Particle &particles, Trajectory & output_traj, TimeSeriesData &epi_data, TreeData &tree_data, MultiTreeData &multitree_data) {
        int thread_max = std::min(options.num_threads, omp_get_max_threads());
        gsl_rng** rngs = new gsl_rng*[thread_max];
        for (int thread = 0; thread < thread_max; thread++) {
            rngs[thread] = gsl_rng_alloc(gsl_rng_mt19937);
            gsl_rng_set(rngs[thread], omp_get_thread_num() + thread);
        }

        double loglik = 0.0;
        int num_groups = options.num_groups;
        int num_particles = options.particles;
        int init_seed = options.seed;
        int total_dt = options.total_dt;
        double sim_dt = options.sim_dt;
        int total_steps = ceil((double)total_dt/(double)options.pfilter_every);
        int add_dt = 0;
        double ESS_threshold = options.pfilter_threshold*(double)num_particles;
        Likelihood likelihood_calc;
        //        std::vector <Parameter> values;// (options.num_threads, model_params);
        //        for (int i=0; i!=options.num_threads; ++i) values.push_back(model_params);
        //        for (int i=0; i!=model_params.get_total_params(); ++i) values.push_back(model_params.get(i));
        std::vector <std::vector<double> > values(options.num_threads, std::vector<double>(model_params.get_total_params(), 0.0));
        for (int i=0; i!=options.num_threads; ++i) {
            for (int j=0; j!=model_params.get_total_params(); ++j) {
                values[i][j] = model_params.get(j);
            }
        }
        // printf("Size of values = %d\n",values.size());
        double reporting_rate = 1.0;
        if (model_params.param_exists("reporting")) {
            reporting_rate = model_params.get("reporting");
        }
        else if (model_params.param_exists("reporting0")) {
            reporting_rate = model_params.get("reporting0");
        }
        std::vector <std::string> param_names = model_params.get_names_vector();
        std::vector <std::vector<std::string> > param_names_threads (options.num_threads);
        if (model_params.param_exists("time_before_data")) {
            add_dt = model_params.get("time_before_data");
        }
        if (options.save_traj) {
            if (add_dt > 0) {
                particles.start_particle_tracing(add_dt+total_dt, num_groups);
            }
            else if (add_dt < 0) {
                particles.start_particle_tracing(add_dt+total_dt, num_groups);
                total_steps = ceil((double)(total_dt+add_dt)/(double)options.pfilter_every);
            }
            else {
                particles.start_particle_tracing(total_dt, num_groups);
            }
        }
	std::vector <Model> models;
        for (int i=0; i<options.num_threads; ++i) {
            models.push_back(sim_model);
        }
        std::vector <int> add_dt_threads (options.num_threads, add_dt);
        std::vector <int> start_dt_threads (options.num_threads, 0);
        std::vector <int> end_dt_threads (options.num_threads, add_dt);
        std::vector <double> dt_threads (options.num_threads, sim_dt);
        std::vector <int> total_dt_threads(options.num_threads, total_dt);
        std::vector <double> reporting_rate_threads(options.num_threads, reporting_rate);
        std::vector <int> num_groups_threads(options.num_threads, num_groups);
        // Simulate model and calculate likelihood assuming no observed data
        if (model_params.param_exists("time_before_data")) {
            if (add_dt > 0) {
                omp_set_num_threads(options.num_threads);
                //                std::vector <Trajectory *> curr_trajs;
                //                for (int i=0; i!=num_particles; ++i) {
                //                    curr_trajs.push_back(particles.get_traj(i));
                //                }
#pragma omp parallel for shared(particles, values) schedule(static,1)
                for (int tn = 0; tn < thread_max; tn++) {
                    for (int i = tn; i < num_particles; i += thread_max) {
                        // Adjust length of trajectory
                        particles.get_traj(i)->resize(add_dt, num_groups);
                        models[tn].simulate(values[tn], param_names_threads[tn], particles.get_traj(i), 0, add_dt_threads[tn], dt_threads[tn], total_dt_threads[tn], rngs[tn]);
                        if (options.which_likelihood < 2) {
                            double w = likelihood_calc.binomial_lik(reporting_rate_threads[tn], particles.get_traj(i)->get_total_traj(), add_dt_threads[tn] + total_dt_threads[tn], 0, add_dt_threads[tn], num_groups_threads[tn], false);
                            particles.set_weight(w, i, false);
                        }
                        if (options.save_traj) {
                            particles.save_traj_to_matrix(i, 0, add_dt);
                            particles.save_ancestry(i, 0, add_dt);
                        }
                    }
                }
            }
        }
        init_seed += num_particles;
        int t=0;
        int start_dt;
        int end_dt;
        for (t = 0; t != total_steps; ++t) {
            // std::vector<double> we(options.particles, 0.0), wg(options.particles, 0.0);
            start_dt = t*options.pfilter_every;
            end_dt = std::min(total_dt, (t + 1)*options.pfilter_every);
            if (model_params.param_exists("reportingT0")) {
                int time_change_i = 0;
                bool reporting_rate_found = false;
                reporting_rate = model_params.get("reporting0");
                while (model_params.param_exists("reportingT"+std::to_string(time_change_i))) {
                    if (end_dt >= model_params.get("reportingT"+std::to_string(time_change_i))) {
                        reporting_rate *= model_params.get("reporting"+std::to_string(time_change_i+1));
                    }
                }
            }
            std::fill(start_dt_threads.begin(), start_dt_threads.end(), start_dt);
            std::fill(end_dt_threads.begin(), end_dt_threads.end(), end_dt);
            omp_set_num_threads(options.num_threads);
#pragma omp parallel for shared (particles, values) schedule(static,1)
            for (int tn = 0; tn < thread_max; tn++) {
                for (int i = tn; i < num_particles; i+=thread_max) {
                    // Adjust length of trajectory
                    //                    if (tn==0) std::cout << i << ' ' << std::endl;
                    particles.get_traj(i)->resize(end_dt - start_dt, options.num_groups);
                    models[tn].simulate(values[tn], param_names_threads[tn], particles.get_traj(i), start_dt_threads[tn], end_dt_threads[tn], dt_threads[tn], total_dt_threads[tn], rngs[tn]);
                    double w = 1.0;
                    double temp = 0.0;
                    if (options.which_likelihood < 2) {
                        double A = particles.get_traj(i)->get_total_traj();
                        temp = likelihood_calc.binomial_lik(reporting_rate_threads[tn], A, epi_data.get_data_ptr(0), add_dt_threads[tn] + total_dt_threads[tn], start_dt_threads[tn], end_dt_threads[tn], add_dt_threads[tn], num_groups_threads[tn], false);
                        w *= temp;
                        // we[i] = log(temp);
                    }
                    if (options.which_likelihood != 1) {
                        temp = likelihood_calc.coalescent_lik(particles.get_traj(i)->get_traj_ptr(0, 0), particles.get_traj(i)->get_traj_ptr(1, 0),
                                                              tree_data.get_binomial_ptr(0), tree_data.get_interval_ptr(0), tree_data.get_ends_ptr(0),
                                                              start_dt_threads[tn], end_dt_threads[tn], add_dt_threads[tn], false);
                        w *= temp;
                        // wg[i] = log(temp);
                    }
                    particles.set_weight(w, i, true);
                    if (options.save_traj) {
                        particles.save_traj_to_matrix(i, start_dt_threads[tn] + add_dt_threads[tn], end_dt_threads[tn] + add_dt_threads[tn]);
                        particles.save_ancestry(i, start_dt_threads[tn] + add_dt_threads[tn], end_dt_threads[tn] + add_dt_threads[tn]);
                    }
                }
            }
            // std::cout << "Epi Weight: " << std::accumulate(we.begin(), we.end(), 0.0) << " Gen Weight: " << std::accumulate(wg.begin(), wg.end(), 0.0) << " Total: " << particles.get_total_weight() << std::endl;
	    double curr_ESS = particles.get_ESS();
            if (curr_ESS < ESS_threshold) {
                double total_weight = particles.get_total_weight();
                if (total_weight == 0.0) {
                    loglik += -0.1*std::numeric_limits<double>::max();
                    //                    std::cout << std::accumulate(epi_data.get_data_ptr(0)+start_dt, epi_data.get_data_ptr(0)+end_dt, 0.0) << " : " << particles.get_traj(0)->get_traj(0) << std::endl;
                    std::cout << "stop time: " << end_dt << std::endl;
                    break;
                } else {
                    loglik += log(total_weight) - log(num_particles);
                }
                particles.resample(options.rng[0]);
            }
            else {
                particles.reset_parents();
            }
        }
        if (options.save_traj) {
            output_traj.resize((total_dt+add_dt), num_groups);
            //if (loglik > -0.1*std::numeric_limits<double>::max()) {
            particles.retrace_traj(output_traj, options.rng[0]);
            //}
        }
        for (int i=0; i!=num_particles; ++i) {
            particles.get_traj(i)->reset();
        }
        std::vector < std::vector<double> >().swap(values);

        for (int thread = 0; thread < thread_max; thread++) {
            gsl_rng_free(rngs[thread]);
        }
        delete[] rngs;

        return (loglik);
    }
}

<|endoftext|>


<commit_before>///
/// @file  pi_lmo3.cpp
/// @brief Simple implementation of the Lagarias-Miller-Odlyzko prime
///        counting algorithm. This implementation uses the segmented
///        sieve of Eratosthenes to calculate S2(x).
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include "PhiTiny.hpp"
#include "pmath.hpp"
#include "Pk.hpp"

#include <primecount.hpp>
#include <primesieve.hpp>
#include <stdint.h>
#include <vector>

using std::log;

namespace {

/// Calculate the contribution of the ordinary leaves.
///
int64_t S1(int64_t x,
           int64_t x13_alpha,
           int64_t c,
           std::vector<int32_t>& primes,
           std::vector<int32_t>& lpf,
           std::vector<int32_t>& mu)
{
  int64_t S1_result = 0;

  for (int64_t n = 1; n <= x13_alpha; n++)
    if (lpf[n] > primes[c])
      S1_result += mu[n] * primecount::phi(x / n, c);

  return S1_result;
}

/// Calculate the contribution of the special leaves.
/// This implementation uses segmentation which reduces the
/// algorithm's space complexity to O(n^(1/3)).
/// @pre c >= 2
///
int64_t S2(int64_t x,
           int64_t x13_alpha,
           int64_t x23_alpha,
           int64_t a,
           int64_t c,
           std::vector<int32_t>& primes,
           std::vector<int32_t>& lpf,
           std::vector<int32_t>& mu)
{
  int64_t limit = x23_alpha + 1;
  int64_t segment_size = primecount::isqrt(limit);
  int64_t S2_result = 0;

  // vector used for sieving
  std::vector<char> sieve(segment_size);
  std::vector<int64_t> next(primes.begin(), primes.end());
  std::vector<int64_t> phi(primes.size(), 0);

  // segmented sieve of Eratosthenes
  for (int64_t low = 1; low < limit; low += segment_size)
  {
    std::fill(sieve.begin(), sieve.end(), 1);

    // current segment = interval [low, high[
    int64_t high = std::min(low + segment_size, limit);

    // phi(y, b) nodes with b <= c do not contribute to S2, so we
    // simply sieve out the multiples of the first c primes
    //
    for (int64_t b = 1; b <= c; b++)
    {
      int64_t k = next[b];
      for (int64_t prime = primes[b]; k < high; k += prime)
        sieve[k - low] = 0;
      next[b] = k;
    }

    for (int64_t b = c; b + 1 < a; b++)
    {
      int64_t prime = primes[b + 1];
      int64_t max_m = std::min(x / (low * prime), x13_alpha);
      int64_t min_m = std::max(x / (high * prime), x13_alpha / prime);
      int64_t i = low;

      // Obviously if (prime >= max_m) then (prime >= lpf[max_m])
      // if so then (prime < lpf[m]) will always evaluate to
      // false and no special leaves are possible
      //
      if (prime >= max_m)
        break;

      for (int64_t m = max_m; m > min_m; m--)
      {
        if (mu[m] != 0 && prime < lpf[m])
        {
          // We have found a special leaf, compute it's contribution
          // phi(x / (m * primes[b + 1]), b) by counting the
          // number of unsieved elements <= x / (m * primes[b + 1])
          // after having removed the multiples of the first b primes
          //
          for (int64_t y = x / (m * prime); i <= y; i++)
            phi[b + 1] += sieve[i - low];

          S2_result -= mu[m] * phi[b + 1];
        }
      }

      // Count the remaining unsieved elements in this segment,
      // we need their values in the next segment
      for (; i < high; i++)
        phi[b + 1] += sieve[i - low];

      // Remove the multiples of (b + 1)th prime
      int64_t k = next[b + 1];
      for (; k < high; k += prime * 2)
        sieve[k - low] = 0;
      next[b + 1] = k;
    }
  }

  return S2_result;
}

} // namespace

namespace primecount {

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm.
/// Run time: O(x^(2/3)) operations, O(x^0.5) space.
/// @note O(x^0.5) space is due to parallel P2(x, a).
///
int64_t pi_lmo3(int64_t x, int threads)
{
  if (x < 2)
    return 0;

  // Optimization factor, see:
  // Tomás Oliveira e Silva, Computing pi(x): the combinatorial method,
  // Revista do DETUA, vol. 4, no. 6, pp. 763-764, March 2006.
  double beta = 1.1;
  double alpha = std::max(1.0, log(log((double) x)) * beta);

  int64_t x13 = iroot<3>(x);
  int64_t x13_alpha = (int64_t)(x13 * alpha);
  int64_t x23_alpha = (int64_t) std::pow((double) x / alpha, 2.0 / 3.0);
  int64_t a = pi_lehmer(x13_alpha);
  int64_t c = (a < 6) ? a : 6;

  std::vector<int32_t> lpf = make_least_prime_factor(x13_alpha);
  std::vector<int32_t> mu = make_moebius(x13_alpha);
  std::vector<int32_t> primes;
  primes.push_back(0);
  primesieve::generate_n_primes(a, &primes);

  int64_t phi = S1(x, x13_alpha, c, primes, lpf , mu) + S2(x, x13_alpha, x23_alpha, a, c, primes, lpf , mu);
  int64_t sum = phi + a - 1 - P2(x, a, threads);

  return sum;
}

} // namespace primecount
<commit_msg>Refactoring<commit_after>///
/// @file  pi_lmo3.cpp
/// @brief Simple implementation of the Lagarias-Miller-Odlyzko prime
///        counting algorithm. This implementation uses the segmented
///        sieve of Eratosthenes to calculate S2(x).
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include "PhiTiny.hpp"
#include "pmath.hpp"
#include "Pk.hpp"

#include <primecount.hpp>
#include <primesieve.hpp>
#include <stdint.h>
#include <vector>

using std::log;

namespace {

/// Calculate the contribution of the ordinary leaves.
///
int64_t S1(int64_t x,
           int64_t x13_alpha,
           int64_t c,
           std::vector<int32_t>& primes,
           std::vector<int32_t>& lpf,
           std::vector<int32_t>& mu)
{
  int64_t S1_result = 0;

  for (int64_t n = 1; n <= x13_alpha; n++)
    if (lpf[n] > primes[c])
      S1_result += mu[n] * primecount::phi(x / n, c);

  return S1_result;
}

/// Calculate the contribution of the special leaves.
/// This implementation uses segmentation which reduces the
/// algorithm's space complexity to O(n^(1/3)).
/// @pre c >= 2
///
int64_t S2(int64_t x,
           int64_t x13_alpha,
           int64_t x23_alpha,
           int64_t a,
           int64_t c,
           std::vector<int32_t>& primes,
           std::vector<int32_t>& lpf,
           std::vector<int32_t>& mu)
{
  int64_t limit = x23_alpha + 1;
  int64_t segment_size = primecount::isqrt(limit);
  int64_t S2_result = 0;

  // vector used for sieving
  std::vector<char> sieve(segment_size);
  std::vector<int64_t> next(primes.begin(), primes.end());
  std::vector<int64_t> phi(primes.size(), 0);

  // segmented sieve of Eratosthenes
  for (int64_t low = 1; low < limit; low += segment_size)
  {
    std::fill(sieve.begin(), sieve.end(), 1);

    // current segment = interval [low, high[
    int64_t high = std::min(low + segment_size, limit);

    // phi(y, b) nodes with b <= c do not contribute to S2, so we
    // simply sieve out the multiples of the first c primes
    for (int64_t b = 1; b <= c; b++)
    {
      int64_t k = next[b];
      for (int64_t prime = primes[b]; k < high; k += prime)
        sieve[k - low] = 0;
      next[b] = k;
    }

    for (int64_t b = c; b + 1 < a; b++)
    {
      int64_t prime = primes[b + 1];
      int64_t max_m = std::min(x / (low * prime), x13_alpha);
      int64_t min_m = std::max(x / (high * prime), x13_alpha / prime);
      int64_t i = low;

      // Obviously if (prime >= max_m) then (prime >= lpf[max_m])
      // if so then (prime < lpf[m]) will always evaluate to
      // false and no special leaves are possible
      if (prime >= max_m)
        break;

      for (int64_t m = max_m; m > min_m; m--)
      {
        if (mu[m] != 0 && prime < lpf[m])
        {
          // We have found a special leaf, compute it's contribution
          // phi(x / (m * primes[b + 1]), b) by counting the
          // number of unsieved elements <= x / (m * primes[b + 1])
          // after having removed the multiples of the first b primes
          //
          for (int64_t y = x / (m * prime); i <= y; i++)
            phi[b + 1] += sieve[i - low];

          S2_result -= mu[m] * phi[b + 1];
        }
      }

      // Count the remaining unsieved elements in this segment,
      // we need their values in the next segment
      for (; i < high; i++)
        phi[b + 1] += sieve[i - low];

      // Remove the multiples of (b + 1)th prime
      int64_t k = next[b + 1];
      for (; k < high; k += prime * 2)
        sieve[k - low] = 0;
      next[b + 1] = k;
    }
  }

  return S2_result;
}

} // namespace

namespace primecount {

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm.
/// Run time: O(x^(2/3)) operations, O(x^0.5) space.
/// @note O(x^0.5) space is due to parallel P2(x, a).
///
int64_t pi_lmo3(int64_t x, int threads)
{
  if (x < 2)
    return 0;

  // Optimization factor, see:
  // Tomás Oliveira e Silva, Computing pi(x): the combinatorial method,
  // Revista do DETUA, vol. 4, no. 6, pp. 763-764, March 2006.
  double beta = 1.1;
  double alpha = std::max(1.0, log(log((double) x)) * beta);

  int64_t x13 = iroot<3>(x);
  int64_t x13_alpha = (int64_t)(x13 * alpha);
  int64_t x23_alpha = (int64_t) std::pow((double) x / alpha, 2.0 / 3.0);
  int64_t a = pi_lehmer(x13_alpha);
  int64_t c = (a < 6) ? a : 6;

  std::vector<int32_t> lpf = make_least_prime_factor(x13_alpha);
  std::vector<int32_t> mu = make_moebius(x13_alpha);
  std::vector<int32_t> primes;
  primes.push_back(0);
  primesieve::generate_n_primes(a, &primes);

  int64_t phi = S1(x, x13_alpha, c, primes, lpf , mu) + S2(x, x13_alpha, x23_alpha, a, c, primes, lpf , mu);
  int64_t sum = phi + a - 1 - P2(x, a, threads);

  return sum;
}

} // namespace primecount
<|endoftext|>


<commit_before>/*
* Copyright (C) 2008-2010 J-P Nurmi jpnurmi@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* $Id$
*/

#include "editframe.h"
#include "completer.h"
#include <QShortcut>

EditFrame::EditFrame(QWidget* parent) : QFrame(parent)
{
    ui.setupUi(this);

    ui.completer = new Completer(this);
    ui.completer->setWidget(this);
    ui.completer->setLineEdit(ui.lineEdit);

    QShortcut* shortcut = new QShortcut(Qt::Key_Tab, this);
    connect(shortcut, SIGNAL(activated()), ui.completer, SLOT(onTabPressed()));

    ui.tabButton->setFocusProxy(ui.lineEdit);
    ui.sendButton->setFocusProxy(ui.lineEdit);

    connect(ui.tabButton, SIGNAL(clicked()), ui.completer, SLOT(onTabPressed()));
    connect(ui.sendButton, SIGNAL(clicked()), this, SLOT(onSend()));
    connect(ui.lineEdit, SIGNAL(returnPressed()), this, SLOT(onSend()));
    connect(ui.lineEdit, SIGNAL(textChanged(QString)), this, SLOT(updateUi()));
    connect(ui.lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(typed(QString)));

    updateUi();
}

Completer* EditFrame::completer() const
{
    return ui.completer;
}

HistoryLineEdit* EditFrame::lineEdit() const
{
    return ui.lineEdit;
}

void EditFrame::onSend()
{
    QString input = ui.lineEdit->text();
    if (!input.isEmpty())
    {
        ui.lineEdit->clear();
        emit send(input);
    }
}

void EditFrame::updateUi()
{
    QString input = ui.lineEdit->text();
    ui.tabButton->setEnabled(!input.isEmpty());
    ui.sendButton->setEnabled(!input.isEmpty());
}
<commit_msg>A workaround for a bug in the Oxygen style<commit_after>/*
* Copyright (C) 2008-2010 J-P Nurmi jpnurmi@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* $Id$
*/

#include "editframe.h"
#include "completer.h"
#include <QShortcut>
#include <QPlastiqueStyle>

EditFrame::EditFrame(QWidget* parent) : QFrame(parent)
{
    ui.setupUi(this);

    ui.completer = new Completer(this);
    ui.completer->setWidget(this);
    ui.completer->setLineEdit(ui.lineEdit);

    // a workaround for a bug in the Oxygen style
    if (qApp->style()->objectName() == "oxygen")
        ui.lineEdit->setStyle(new QPlastiqueStyle);

    QShortcut* shortcut = new QShortcut(Qt::Key_Tab, this);
    connect(shortcut, SIGNAL(activated()), ui.completer, SLOT(onTabPressed()));

    ui.tabButton->setFocusProxy(ui.lineEdit);
    ui.sendButton->setFocusProxy(ui.lineEdit);

    connect(ui.tabButton, SIGNAL(clicked()), ui.completer, SLOT(onTabPressed()));
    connect(ui.sendButton, SIGNAL(clicked()), this, SLOT(onSend()));
    connect(ui.lineEdit, SIGNAL(returnPressed()), this, SLOT(onSend()));
    connect(ui.lineEdit, SIGNAL(textChanged(QString)), this, SLOT(updateUi()));
    connect(ui.lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(typed(QString)));

    updateUi();
}

Completer* EditFrame::completer() const
{
    return ui.completer;
}

HistoryLineEdit* EditFrame::lineEdit() const
{
    return ui.lineEdit;
}

void EditFrame::onSend()
{
    QString input = ui.lineEdit->text();
    if (!input.isEmpty())
    {
        ui.lineEdit->clear();
        emit send(input);
    }
}

void EditFrame::updateUi()
{
    QString input = ui.lineEdit->text();
    ui.tabButton->setEnabled(!input.isEmpty());
    ui.sendButton->setEnabled(!input.isEmpty());
}
<|endoftext|>


<commit_before>#include "AliMFTCluster.h"
#include "TFile.h"
#include "AliMFTCluster.h"
#include "TObjArray.h"
#include "TClonesArray.h"
#include "TTree.h"
#include "AliMFTConstants.h"
#include "TBranch.h"
#include "TRandom.h"

TFile *fileIn=0, *fileOut=0;

const Int_t labelMCOffset = 1000000;
Double_t misalignmentX[AliMFTConstants::fNMaxPlanes] = {0};
Double_t misalignmentY[AliMFTConstants::fNMaxPlanes] = {0};

//====================================================================================================================================================

void AddMisalignmentToClusters(Char_t *nameDir=".",
			       Int_t seed = 12345,
			       Double_t misalignment = 0.0015) {

  gRandom -> SetSeed(seed);

  TClonesArray *fRecPointsPerPlaneIn[AliMFTConstants::fNMaxPlanes] = {0};
  TClonesArray *fRecPointsPerPlaneOut[AliMFTConstants::fNMaxPlanes] = {0};

  fileIn = new TFile(Form("%s/MFT.RecPoints.root",nameDir));
  fileOut = new TFile(Form("%s/MFT.RecPoints.Misaligned.root",nameDir), "recreate");

  Int_t iEv=0;
  while (fileIn->cd(Form("Event%d",iEv))) {

    for (Int_t iPlane=0; iPlane<AliMFTConstants::fNMaxPlanes; iPlane++) {
      fRecPointsPerPlaneIn[iPlane] = new TClonesArray("AliMFTCluster");
      fRecPointsPerPlaneOut[iPlane] = new TClonesArray("AliMFTCluster");
    }

    printf("Event %d\n",iEv);
    TTree *treeIn = (TTree*) gDirectory->Get("TreeR");
    treeIn -> SetName("TreeR_In");
    fileOut-> cd();
    TTree *treeOut = new TTree("TreeR", "Reconstructed Points Container");

    Int_t iPlane=0;
    while (treeIn->GetBranch(Form("Plane_%02d",iPlane))) {
      //      printf("Plane %02d\n",iPlane);
      Double_t misalignmentPhi = 2.*TMath::Pi()*gRandom->Rndm();
      misalignmentX[iPlane] = misalignment*TMath::Cos(misalignmentPhi);
      misalignmentY[iPlane] = misalignment*TMath::Sin(misalignmentPhi);
      treeIn ->SetBranchAddress(Form("Plane_%02d",iPlane), &(fRecPointsPerPlaneIn[iPlane]));
      treeOut->Branch(Form("Plane_%02d",iPlane), &(fRecPointsPerPlaneOut[iPlane]));
      //      treeOut->SetBranchAddress(Form("Plane_%02d",iPlane), &(fRecPointsPerPlaneOut[iPlane]));
      iPlane++;
    }

    iPlane=0;
    treeIn -> GetEntry(0);
    while (treeIn->GetBranch(Form("Plane_%02d",iPlane))) {
      Int_t nClusters = fRecPointsPerPlaneIn[iPlane]->GetEntries();
      for (Int_t iCluster=0; iCluster<nClusters; iCluster++) {
	//	printf("Cluster %4d\n",iCluster);
	AliMFTCluster *newCluster = (AliMFTCluster*) fRecPointsPerPlaneIn[iPlane]->At(iCluster);
	newCluster->SetClusterEditable(kTRUE);
	newCluster->SetX(newCluster->GetX()+misalignmentX[iPlane]);
	newCluster->SetY(newCluster->GetY()+misalignmentY[iPlane]);
	new ((*fRecPointsPerPlaneOut[iPlane])[fRecPointsPerPlaneOut[iPlane]->GetEntries()]) AliMFTCluster(*newCluster);
      }
      iPlane++;
    }

    treeOut -> Fill();
    fileOut -> mkdir(Form("Event%d",iEv));
    fileOut -> cd(Form("Event%d",iEv));
    treeOut -> Write();
    for (Int_t jPlane=0; jPlane<AliMFTConstants::fNMaxPlanes; jPlane++) {
      delete fRecPointsPerPlaneIn[jPlane];
      delete fRecPointsPerPlaneOut[jPlane];
    }

    iEv++;

  }

  fileOut -> Close();

}

//====================================================================================================================================================
<commit_msg>Modified support macro AddMisalignmentToClusters.C<commit_after>#include "AliMFTCluster.h"
#include "TFile.h"
#include "AliMFTCluster.h"
#include "TObjArray.h"
#include "TClonesArray.h"
#include "TTree.h"
#include "AliMFTConstants.h"
#include "TBranch.h"
#include "TRandom.h"

TFile *fileIn=0, *fileOut=0;

const Int_t labelMCOffset = 1000000;
Double_t misalignmentX[AliMFTConstants::fNMaxPlanes] = {0};
Double_t misalignmentY[AliMFTConstants::fNMaxPlanes] = {0};

//====================================================================================================================================================

void AddMisalignmentToClusters(Char_t *nameDir=".",
			       Int_t seed = 12345,
			       Double_t misalignment = 0.0030) {

  gRandom -> SetSeed(seed);

  TClonesArray *fRecPointsPerPlaneIn[AliMFTConstants::fNMaxPlanes] = {0};
  TClonesArray *fRecPointsPerPlaneOut[AliMFTConstants::fNMaxPlanes] = {0};

  fileIn = new TFile(Form("%s/MFT.RecPoints.root",nameDir));
  fileOut = new TFile(Form("%s/MFT.RecPoints.Misaligned.root",nameDir), "recreate");

  Int_t iEv=0;
  while (fileIn->cd(Form("Event%d",iEv))) {

    for (Int_t iPlane=0; iPlane<AliMFTConstants::fNMaxPlanes; iPlane++) {
      fRecPointsPerPlaneIn[iPlane] = new TClonesArray("AliMFTCluster");
      fRecPointsPerPlaneOut[iPlane] = new TClonesArray("AliMFTCluster");
    }

    printf("Event %d\n",iEv);
    TTree *treeIn = (TTree*) gDirectory->Get("TreeR");
    treeIn -> SetName("TreeR_In");
    fileOut-> cd();
    TTree *treeOut = new TTree("TreeR", "Reconstructed Points Container");

    Int_t iPlane=0;
    while (treeIn->GetBranch(Form("Plane_%02d",iPlane))) {
      //      printf("Plane %02d\n",iPlane);
      Double_t misalignmentPhi = 2.*TMath::Pi()*gRandom->Rndm();
      misalignmentX[iPlane] = misalignment*TMath::Cos(misalignmentPhi);
      misalignmentY[iPlane] = misalignment*TMath::Sin(misalignmentPhi);
      treeIn ->SetBranchAddress(Form("Plane_%02d",iPlane), &(fRecPointsPerPlaneIn[iPlane]));
      treeOut->Branch(Form("Plane_%02d",iPlane), &(fRecPointsPerPlaneOut[iPlane]));
      //      treeOut->SetBranchAddress(Form("Plane_%02d",iPlane), &(fRecPointsPerPlaneOut[iPlane]));
      iPlane++;
    }

    iPlane=0;
    treeIn -> GetEntry(0);
    while (treeIn->GetBranch(Form("Plane_%02d",iPlane))) {
      Int_t nClusters = fRecPointsPerPlaneIn[iPlane]->GetEntries();
      for (Int_t iCluster=0; iCluster<nClusters; iCluster++) {
	//	printf("Cluster %4d\n",iCluster);
	AliMFTCluster *newCluster = (AliMFTCluster*) fRecPointsPerPlaneIn[iPlane]->At(iCluster);
	newCluster->SetClusterEditable(kTRUE);
	newCluster->SetX(newCluster->GetX()+misalignmentX[iPlane]);
	newCluster->SetY(newCluster->GetY()+misalignmentY[iPlane]);
	new ((*fRecPointsPerPlaneOut[iPlane])[fRecPointsPerPlaneOut[iPlane]->GetEntries()]) AliMFTCluster(*newCluster);
      }
      iPlane++;
    }

    treeOut -> Fill();
    fileOut -> mkdir(Form("Event%d",iEv));
    fileOut -> cd(Form("Event%d",iEv));
    treeOut -> Write();
    for (Int_t jPlane=0; jPlane<AliMFTConstants::fNMaxPlanes; jPlane++) {
      delete fRecPointsPerPlaneIn[jPlane];
      delete fRecPointsPerPlaneOut[jPlane];
    }

    iEv++;

  }

  fileOut -> Close();

}

//====================================================================================================================================================
<|endoftext|>


<commit_before>#ifndef SERVER_HTTP_HPP
#define	SERVER_HTTP_HPP

#include <boost/asio.hpp>
#include <boost/regex.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/functional/hash.hpp>

#include <unordered_map>
#include <thread>
#include <functional>
#include <iostream>
#include <sstream>

namespace SimpleWeb {
    template <class socket_type>
    class ServerBase {
    public:
        virtual ~ServerBase() {}

        class Response : public std::ostream {
            friend class ServerBase<socket_type>;

            boost::asio::streambuf streambuf;

            std::shared_ptr<socket_type> socket;

            Response(std::shared_ptr<socket_type> socket): std::ostream(&streambuf), socket(socket) {}

        public:
            size_t size() {
                return streambuf.size();
            }
        };

        class Content : public std::istream {
            friend class ServerBase<socket_type>;
        public:
            size_t size() {
                return streambuf.size();
            }
            std::string string() {
                std::stringstream ss;
                ss << rdbuf();
                return ss.str();
            }
        private:
            boost::asio::streambuf &streambuf;
            Content(boost::asio::streambuf &streambuf): std::istream(&streambuf), streambuf(streambuf) {}
        };

        class Request {
            friend class ServerBase<socket_type>;

            //Based on http://www.boost.org/doc/libs/1_60_0/doc/html/unordered/hash_equality.html
            class iequal_to {
            public:
              bool operator()(const std::string &key1, const std::string &key2) const {
                return boost::algorithm::iequals(key1, key2);
              }
            };
            class ihash {
            public:
              size_t operator()(const std::string &key) const {
                std::size_t seed=0;
                for(auto &c: key)
                  boost::hash_combine(seed, std::tolower(c));
                return seed;
              }
            };
        public:
            std::string method, path, http_version;

            Content content;

            std::unordered_multimap<std::string, std::string, ihash, iequal_to> header;

            boost::smatch path_match;

            std::string remote_endpoint_address;
            unsigned short remote_endpoint_port;

        private:
            Request(): content(streambuf) {}

            boost::asio::streambuf streambuf;

            void read_remote_endpoint_data(socket_type& socket) {
                remote_endpoint_address=socket.lowest_layer().remote_endpoint().address().to_string();
                remote_endpoint_port=socket.lowest_layer().remote_endpoint().port();
            }
        };

        class Config {
            friend class ServerBase<socket_type>;

            Config(unsigned short port, size_t num_threads): num_threads(num_threads), port(port), reuse_address(true) {}
            size_t num_threads;
        public:
            unsigned short port;
            ///IPv4 address in dotted decimal form or IPv6 address in hexadecimal notation.
            ///If empty, the address will be any address.
            std::string address;
            ///Set to false to avoid binding the socket to an address that is already in use.
            bool reuse_address;
        };
        ///Set before calling start().
        Config config;

        std::unordered_map<std::string, std::unordered_map<std::string,
            std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > >  resource;

        std::unordered_map<std::string,
            std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > default_resource;

    private:
        std::vector<std::pair<std::string, std::vector<std::pair<boost::regex,
            std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > > > > opt_resource;

    public:
        void start() {
            //Copy the resources to opt_resource for more efficient request processing
            opt_resource.clear();
            for(auto& res: resource) {
                for(auto& res_method: res.second) {
                    auto it=opt_resource.end();
                    for(auto opt_it=opt_resource.begin();opt_it!=opt_resource.end();opt_it++) {
                        if(res_method.first==opt_it->first) {
                            it=opt_it;
                            break;
                        }
                    }
                    if(it==opt_resource.end()) {
                        opt_resource.emplace_back();
                        it=opt_resource.begin()+(opt_resource.size()-1);
                        it->first=res_method.first;
                    }
                    it->second.emplace_back(boost::regex(res.first), res_method.second);
                }
            }

            if(io_service.stopped())
                io_service.reset();

            boost::asio::ip::tcp::endpoint endpoint;
            if(config.address.size()>0)
                endpoint=boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(config.address), config.port);
            else
                endpoint=boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), config.port);
            acceptor.open(endpoint.protocol());
            acceptor.set_option(boost::asio::socket_base::reuse_address(config.reuse_address));
            acceptor.bind(endpoint);
            acceptor.listen();

            accept();

            //If num_threads>1, start m_io_service.run() in (num_threads-1) threads for thread-pooling
            threads.clear();
            for(size_t c=1;c<config.num_threads;c++) {
                threads.emplace_back([this](){
                    io_service.run();
                });
            }

            //Main thread
            io_service.run();

            //Wait for the rest of the threads, if any, to finish as well
            for(auto& t: threads) {
                t.join();
            }
        }

        void stop() {
            acceptor.close();
            io_service.stop();
        }

        ///Use this function if you need to recursively send parts of a longer message
        void send(std::shared_ptr<Response> response, const std::function<void(const boost::system::error_code&)>& callback=nullptr) const {
            boost::asio::async_write(*response->socket, response->streambuf, [this, response, callback](const boost::system::error_code& ec, size_t /*bytes_transferred*/) {
                if(callback)
                    callback(ec);
            });
        }
        std::function<void(const std::exception&)> exception_handler;

    protected:
        boost::asio::io_service io_service;
        boost::asio::ip::tcp::acceptor acceptor;
        std::vector<std::thread> threads;

        long timeout_request;
        long timeout_content;

        ServerBase(unsigned short port, size_t num_threads, long timeout_request, long timeout_send_or_receive) :
                config(port, num_threads), acceptor(io_service),
                timeout_request(timeout_request), timeout_content(timeout_send_or_receive) {}

        virtual void accept()=0;

        std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket(std::shared_ptr<socket_type> socket, long seconds) {
            std::shared_ptr<boost::asio::deadline_timer> timer(new boost::asio::deadline_timer(io_service));
            timer->expires_from_now(boost::posix_time::seconds(seconds));
            timer->async_wait([socket](const boost::system::error_code& ec){
                if(!ec) {
                    boost::system::error_code ec;
                    socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
                    socket->lowest_layer().close();
                }
            });
            return timer;
        }

        void read_request_and_content(std::shared_ptr<socket_type> socket) {
            //Create new streambuf (Request::streambuf) for async_read_until()
            //shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<Request> request(new Request());
            try {
               request->read_remote_endpoint_data(*socket);
            }
            catch(const std::exception &e) {
                if(exception_handler)
                   exception_handler(e);
            }

            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_request>0)
                timer=set_timeout_on_socket(socket, timeout_request);

            boost::asio::async_read_until(*socket, request->streambuf, "\r\n\r\n",
                    [this, socket, request, timer](const boost::system::error_code& ec, size_t bytes_transferred) {
                if(timeout_request>0)
                    timer->cancel();
                if(!ec) {
                    //request->streambuf.size() is not necessarily the same as bytes_transferred, from Boost-docs:
                    //"After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
                    //The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
                    //streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
                    size_t num_additional_bytes=request->streambuf.size()-bytes_transferred;

                    if(!parse_request(request, request->content))
                        return;

                    //If content, read that as well
                    auto it=request->header.find("Content-Length");
                    if(it!=request->header.end()) {
                        //Set timeout on the following boost::asio::async-read or write function
                        std::shared_ptr<boost::asio::deadline_timer> timer;
                        if(timeout_content>0)
                            timer=set_timeout_on_socket(socket, timeout_content);
                        unsigned long long content_length;
                        try {
                            content_length=stoull(it->second);
                        }
                        catch(const std::exception &e) {
                            if(exception_handler)
                                exception_handler(e);
                            return;
                        }
                        if(content_length>num_additional_bytes) {
                            boost::asio::async_read(*socket, request->streambuf,
                                    boost::asio::transfer_exactly(content_length-num_additional_bytes),
                                    [this, socket, request, timer]
                                    (const boost::system::error_code& ec, size_t /*bytes_transferred*/) {
                                if(timeout_content>0)
                                    timer->cancel();
                                if(!ec)
                                    find_resource(socket, request);
                            });
                        }
                        else {
                            if(timeout_content>0)
                                timer->cancel();
                            find_resource(socket, request);
                        }
                    }
                    else {
                        find_resource(socket, request);
                    }
                }
            });
        }

        bool parse_request(std::shared_ptr<Request> request, std::istream& stream) const {
            std::string line;
            getline(stream, line);
            size_t method_end;
            if((method_end=line.find(' '))!=std::string::npos) {
                size_t path_end;
                if((path_end=line.find(' ', method_end+1))!=std::string::npos) {
                    request->method=line.substr(0, method_end);
                    request->path=line.substr(method_end+1, path_end-method_end-1);

                    size_t protocol_end;
                    if((protocol_end=line.find('/', path_end+1))!=std::string::npos) {
                        if(line.substr(path_end+1, protocol_end-path_end-1)!="HTTP")
                            return false;
                        request->http_version=line.substr(protocol_end+1, line.size()-protocol_end-2);
                    }
                    else
                        return false;

                    getline(stream, line);
                    size_t param_end;
                    while((param_end=line.find(':'))!=std::string::npos) {
                        size_t value_start=param_end+1;
                        if((value_start)<line.size()) {
                            if(line[value_start]==' ')
                                value_start++;
                            if(value_start<line.size())
                                request->header.insert(std::make_pair(line.substr(0, param_end), line.substr(value_start, line.size()-value_start-1)));
                        }

                        getline(stream, line);
                    }
                }
                else
                    return false;
            }
            else
                return false;
            return true;
        }

        void find_resource(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request) {
            //Find path- and method-match, and call write_response
            for(auto& res: opt_resource) {
                if(request->method==res.first) {
                    for(auto& res_path: res.second) {
                        boost::smatch sm_res;
                        if(boost::regex_match(request->path, sm_res, res_path.first)) {
                            request->path_match=std::move(sm_res);
                            write_response(socket, request, res_path.second);
                            return;
                        }
                    }
                }
            }
            auto it_method=default_resource.find(request->method);
            if(it_method!=default_resource.end()) {
                write_response(socket, request, it_method->second);
            }
        }

        void write_response(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request,
                std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>,
                                   std::shared_ptr<typename ServerBase<socket_type>::Request>)>& resource_function) {
            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_content>0)
                timer=set_timeout_on_socket(socket, timeout_content);

            auto response=std::shared_ptr<Response>(new Response(socket), [this, request, timer](Response *response_ptr) {
                auto response=std::shared_ptr<Response>(response_ptr);
                send(response, [this, response, request, timer](const boost::system::error_code& ec) {
                    if(!ec) {
                        if(timeout_content>0)
                            timer->cancel();
                        float http_version;
                        try {
                            http_version=stof(request->http_version);
                        }
                        catch(const std::exception &e){
                            if(exception_handler)
                                exception_handler(e);
                            return;
                        }

                        auto range=request->header.equal_range("Connection");
                        for(auto it=range.first;it!=range.second;it++) {
                            if(boost::iequals(it->second, "close"))
                                return;
                        }
                        if(http_version>1.05)
                            read_request_and_content(response->socket);
                    }
                });
            });

            try {
                resource_function(response, request);
            }
            catch(const std::exception &e) {
                if(exception_handler)
                    exception_handler(e);
                return;
            }
        }
    };

    template<class socket_type>
    class Server : public ServerBase<socket_type> {};

    typedef boost::asio::ip::tcp::socket HTTP;

    template<>
    class Server<HTTP> : public ServerBase<HTTP> {
    public:
        Server(unsigned short port, size_t num_threads=1, long timeout_request=5, long timeout_content=300) :
                ServerBase<HTTP>::ServerBase(port, num_threads, timeout_request, timeout_content) {}

    protected:
        void accept() {
            //Create new socket for this connection
            //Shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<HTTP> socket(new HTTP(io_service));

            acceptor.async_accept(*socket, [this, socket](const boost::system::error_code& ec){
                //Immediately start accepting a new connection
                accept();

                if(!ec) {
                    boost::asio::ip::tcp::no_delay option(true);
                    socket->set_option(option);

                    read_request_and_content(socket);
                }
            });
        }
    };
}
#endif	/* SERVER_HTTP_HPP */
<commit_msg>Minor cleanup of exception_handler code<commit_after>#ifndef SERVER_HTTP_HPP
#define	SERVER_HTTP_HPP

#include <boost/asio.hpp>
#include <boost/regex.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/functional/hash.hpp>

#include <unordered_map>
#include <thread>
#include <functional>
#include <iostream>
#include <sstream>

namespace SimpleWeb {
    template <class socket_type>
    class ServerBase {
    public:
        virtual ~ServerBase() {}

        class Response : public std::ostream {
            friend class ServerBase<socket_type>;

            boost::asio::streambuf streambuf;

            std::shared_ptr<socket_type> socket;

            Response(std::shared_ptr<socket_type> socket): std::ostream(&streambuf), socket(socket) {}

        public:
            size_t size() {
                return streambuf.size();
            }
        };

        class Content : public std::istream {
            friend class ServerBase<socket_type>;
        public:
            size_t size() {
                return streambuf.size();
            }
            std::string string() {
                std::stringstream ss;
                ss << rdbuf();
                return ss.str();
            }
        private:
            boost::asio::streambuf &streambuf;
            Content(boost::asio::streambuf &streambuf): std::istream(&streambuf), streambuf(streambuf) {}
        };

        class Request {
            friend class ServerBase<socket_type>;

            //Based on http://www.boost.org/doc/libs/1_60_0/doc/html/unordered/hash_equality.html
            class iequal_to {
            public:
              bool operator()(const std::string &key1, const std::string &key2) const {
                return boost::algorithm::iequals(key1, key2);
              }
            };
            class ihash {
            public:
              size_t operator()(const std::string &key) const {
                std::size_t seed=0;
                for(auto &c: key)
                  boost::hash_combine(seed, std::tolower(c));
                return seed;
              }
            };
        public:
            std::string method, path, http_version;

            Content content;

            std::unordered_multimap<std::string, std::string, ihash, iequal_to> header;

            boost::smatch path_match;

            std::string remote_endpoint_address;
            unsigned short remote_endpoint_port;

        private:
            Request(): content(streambuf) {}

            boost::asio::streambuf streambuf;
        };

        class Config {
            friend class ServerBase<socket_type>;

            Config(unsigned short port, size_t num_threads): num_threads(num_threads), port(port), reuse_address(true) {}
            size_t num_threads;
        public:
            unsigned short port;
            ///IPv4 address in dotted decimal form or IPv6 address in hexadecimal notation.
            ///If empty, the address will be any address.
            std::string address;
            ///Set to false to avoid binding the socket to an address that is already in use.
            bool reuse_address;
        };
        ///Set before calling start().
        Config config;

        std::unordered_map<std::string, std::unordered_map<std::string,
            std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > >  resource;

        std::unordered_map<std::string,
            std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > default_resource;

        std::function<void(const std::exception&)> exception_handler;

    private:
        std::vector<std::pair<std::string, std::vector<std::pair<boost::regex,
            std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > > > > opt_resource;

    public:
        void start() {
            //Copy the resources to opt_resource for more efficient request processing
            opt_resource.clear();
            for(auto& res: resource) {
                for(auto& res_method: res.second) {
                    auto it=opt_resource.end();
                    for(auto opt_it=opt_resource.begin();opt_it!=opt_resource.end();opt_it++) {
                        if(res_method.first==opt_it->first) {
                            it=opt_it;
                            break;
                        }
                    }
                    if(it==opt_resource.end()) {
                        opt_resource.emplace_back();
                        it=opt_resource.begin()+(opt_resource.size()-1);
                        it->first=res_method.first;
                    }
                    it->second.emplace_back(boost::regex(res.first), res_method.second);
                }
            }

            if(io_service.stopped())
                io_service.reset();

            boost::asio::ip::tcp::endpoint endpoint;
            if(config.address.size()>0)
                endpoint=boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(config.address), config.port);
            else
                endpoint=boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), config.port);
            acceptor.open(endpoint.protocol());
            acceptor.set_option(boost::asio::socket_base::reuse_address(config.reuse_address));
            acceptor.bind(endpoint);
            acceptor.listen();

            accept();

            //If num_threads>1, start m_io_service.run() in (num_threads-1) threads for thread-pooling
            threads.clear();
            for(size_t c=1;c<config.num_threads;c++) {
                threads.emplace_back([this](){
                    io_service.run();
                });
            }

            //Main thread
            io_service.run();

            //Wait for the rest of the threads, if any, to finish as well
            for(auto& t: threads) {
                t.join();
            }
        }

        void stop() {
            acceptor.close();
            io_service.stop();
        }

        ///Use this function if you need to recursively send parts of a longer message
        void send(std::shared_ptr<Response> response, const std::function<void(const boost::system::error_code&)>& callback=nullptr) const {
            boost::asio::async_write(*response->socket, response->streambuf, [this, response, callback](const boost::system::error_code& ec, size_t /*bytes_transferred*/) {
                if(callback)
                    callback(ec);
            });
        }

    protected:
        boost::asio::io_service io_service;
        boost::asio::ip::tcp::acceptor acceptor;
        std::vector<std::thread> threads;

        long timeout_request;
        long timeout_content;

        ServerBase(unsigned short port, size_t num_threads, long timeout_request, long timeout_send_or_receive) :
                config(port, num_threads), acceptor(io_service),
                timeout_request(timeout_request), timeout_content(timeout_send_or_receive) {}

        virtual void accept()=0;

        std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket(std::shared_ptr<socket_type> socket, long seconds) {
            std::shared_ptr<boost::asio::deadline_timer> timer(new boost::asio::deadline_timer(io_service));
            timer->expires_from_now(boost::posix_time::seconds(seconds));
            timer->async_wait([socket](const boost::system::error_code& ec){
                if(!ec) {
                    boost::system::error_code ec;
                    socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
                    socket->lowest_layer().close();
                }
            });
            return timer;
        }

        void read_request_and_content(std::shared_ptr<socket_type> socket) {
            //Create new streambuf (Request::streambuf) for async_read_until()
            //shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<Request> request(new Request());
            try {
                request->remote_endpoint_address=socket->lowest_layer().remote_endpoint().address().to_string();
                request->remote_endpoint_port=socket->lowest_layer().remote_endpoint().port();
            }
            catch(const std::exception &e) {
                if(exception_handler)
                   exception_handler(e);
            }

            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_request>0)
                timer=set_timeout_on_socket(socket, timeout_request);

            boost::asio::async_read_until(*socket, request->streambuf, "\r\n\r\n",
                    [this, socket, request, timer](const boost::system::error_code& ec, size_t bytes_transferred) {
                if(timeout_request>0)
                    timer->cancel();
                if(!ec) {
                    //request->streambuf.size() is not necessarily the same as bytes_transferred, from Boost-docs:
                    //"After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
                    //The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
                    //streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
                    size_t num_additional_bytes=request->streambuf.size()-bytes_transferred;

                    if(!parse_request(request, request->content))
                        return;

                    //If content, read that as well
                    auto it=request->header.find("Content-Length");
                    if(it!=request->header.end()) {
                        //Set timeout on the following boost::asio::async-read or write function
                        std::shared_ptr<boost::asio::deadline_timer> timer;
                        if(timeout_content>0)
                            timer=set_timeout_on_socket(socket, timeout_content);
                        unsigned long long content_length;
                        try {
                            content_length=stoull(it->second);
                        }
                        catch(const std::exception &e) {
                            if(exception_handler)
                                exception_handler(e);
                            return;
                        }
                        if(content_length>num_additional_bytes) {
                            boost::asio::async_read(*socket, request->streambuf,
                                    boost::asio::transfer_exactly(content_length-num_additional_bytes),
                                    [this, socket, request, timer]
                                    (const boost::system::error_code& ec, size_t /*bytes_transferred*/) {
                                if(timeout_content>0)
                                    timer->cancel();
                                if(!ec)
                                    find_resource(socket, request);
                            });
                        }
                        else {
                            if(timeout_content>0)
                                timer->cancel();
                            find_resource(socket, request);
                        }
                    }
                    else {
                        find_resource(socket, request);
                    }
                }
            });
        }

        bool parse_request(std::shared_ptr<Request> request, std::istream& stream) const {
            std::string line;
            getline(stream, line);
            size_t method_end;
            if((method_end=line.find(' '))!=std::string::npos) {
                size_t path_end;
                if((path_end=line.find(' ', method_end+1))!=std::string::npos) {
                    request->method=line.substr(0, method_end);
                    request->path=line.substr(method_end+1, path_end-method_end-1);

                    size_t protocol_end;
                    if((protocol_end=line.find('/', path_end+1))!=std::string::npos) {
                        if(line.substr(path_end+1, protocol_end-path_end-1)!="HTTP")
                            return false;
                        request->http_version=line.substr(protocol_end+1, line.size()-protocol_end-2);
                    }
                    else
                        return false;

                    getline(stream, line);
                    size_t param_end;
                    while((param_end=line.find(':'))!=std::string::npos) {
                        size_t value_start=param_end+1;
                        if((value_start)<line.size()) {
                            if(line[value_start]==' ')
                                value_start++;
                            if(value_start<line.size())
                                request->header.insert(std::make_pair(line.substr(0, param_end), line.substr(value_start, line.size()-value_start-1)));
                        }

                        getline(stream, line);
                    }
                }
                else
                    return false;
            }
            else
                return false;
            return true;
        }

        void find_resource(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request) {
            //Find path- and method-match, and call write_response
            for(auto& res: opt_resource) {
                if(request->method==res.first) {
                    for(auto& res_path: res.second) {
                        boost::smatch sm_res;
                        if(boost::regex_match(request->path, sm_res, res_path.first)) {
                            request->path_match=std::move(sm_res);
                            write_response(socket, request, res_path.second);
                            return;
                        }
                    }
                }
            }
            auto it_method=default_resource.find(request->method);
            if(it_method!=default_resource.end()) {
                write_response(socket, request, it_method->second);
            }
        }

        void write_response(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request,
                std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>,
                                   std::shared_ptr<typename ServerBase<socket_type>::Request>)>& resource_function) {
            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_content>0)
                timer=set_timeout_on_socket(socket, timeout_content);

            auto response=std::shared_ptr<Response>(new Response(socket), [this, request, timer](Response *response_ptr) {
                auto response=std::shared_ptr<Response>(response_ptr);
                send(response, [this, response, request, timer](const boost::system::error_code& ec) {
                    if(!ec) {
                        if(timeout_content>0)
                            timer->cancel();
                        float http_version;
                        try {
                            http_version=stof(request->http_version);
                        }
                        catch(const std::exception &e){
                            if(exception_handler)
                                exception_handler(e);
                            return;
                        }

                        auto range=request->header.equal_range("Connection");
                        for(auto it=range.first;it!=range.second;it++) {
                            if(boost::iequals(it->second, "close"))
                                return;
                        }
                        if(http_version>1.05)
                            read_request_and_content(response->socket);
                    }
                });
            });

            try {
                resource_function(response, request);
            }
            catch(const std::exception &e) {
                if(exception_handler)
                    exception_handler(e);
                return;
            }
        }
    };

    template<class socket_type>
    class Server : public ServerBase<socket_type> {};

    typedef boost::asio::ip::tcp::socket HTTP;

    template<>
    class Server<HTTP> : public ServerBase<HTTP> {
    public:
        Server(unsigned short port, size_t num_threads=1, long timeout_request=5, long timeout_content=300) :
                ServerBase<HTTP>::ServerBase(port, num_threads, timeout_request, timeout_content) {}

    protected:
        void accept() {
            //Create new socket for this connection
            //Shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<HTTP> socket(new HTTP(io_service));

            acceptor.async_accept(*socket, [this, socket](const boost::system::error_code& ec){
                //Immediately start accepting a new connection
                accept();

                if(!ec) {
                    boost::asio::ip::tcp::no_delay option(true);
                    socket->set_option(option);

                    read_request_and_content(socket);
                }
            });
        }
    };
}
#endif	/* SERVER_HTTP_HPP */
<|endoftext|>