text:
/*
 * lstmlayer.cpp
 *
 * Feed-forward:
 *    x(t) -- inputs
 *    h(t-1) -- hidden state, aka outputs on prev timestep
 *    c(t) -- cell state
 *
 *    Phase 1: I/O gates
 *      zz_a(t) = ww_xa*x(t) + ww_ha * h(t-1) + bb_a  -- input
 *      zz_i(t) = ww_xi*x(t) + ww_hi * h(t-1) + bb_i  -- input gate
 *      zz_f(t) = ww_xf*x(t) + ww_hf * h(t-1) + bb_g  -- forget gate
 *      zz_o(t) = ww_xo*x(t) + ww_ho * h(t-1) + bb_o  -- output gate
 *
 *      a(t) = activ1 (zz_a(t))
 *      i(t) = activ2 (zz_i(t))
 *      f(t) = activ2 (zz_f(t))
 *      o(t) = activ2 (zz_o(t))
 *
 *    Phase 2: State
 *      c(t) = elem_prod(i(t), a(t)) + elem_prod(f(t), c(t-1))
 *
 *    Phase 3: Output
 *      h(t) = elem_prod(o(t), activ1(c(t))
 *
 * Back propagation:
 *
 */
#include <boost/assert.hpp>

#include "core/utils.h"
#include "core/random.h"
#include "core/functions.h"
#include "lstmlayer.h"

using namespace std;
using namespace boost;
using namespace yann;

namespace yann {

// prefixes for read/write
static const char g_ltsm_names_suffix[LstmLayer::Gate_Max + 1] = "aifo";

////////////////////////////////////////////////////////////////////////////////////////////////
//
// LstmLayer_Context implementation
//
class LstmLayer_Context :
    public Layer::Context
{
  typedef Layer::Context Base;

  friend class LstmLayer;

public:
  LstmLayer_Context(
      const MatrixSize & output_size,
      const MatrixSize & max_batch_size) :
    Base(output_size, max_batch_size),
    _pos(0)
  {
    init();
  }

  LstmLayer_Context(
      const RefVectorBatch & output) :
    Base(output),
    _pos(0)
  {
    init();
  }

  // Layer::Context overwrites
  virtual void reset_state()
  {
    Base::reset_state();

    _pos = 0;
  }

private:
  void init()
  {
    for(auto & zz_gate: _zz_gate) {
      zz_gate.resize(get_batch_size(), get_output_size());
    }
    for(auto & gate: _gate) {
      gate.resize(get_batch_size(), get_output_size());
    }

    _cc.resize(get_batch_size(), get_output_size());
    _activ_cc.resize(get_batch_size(), get_output_size());

    _hh.resize(get_batch_size(), get_output_size());
  }

protected:
  MatrixSize  _pos;
  VectorBatch _zz_gate[LstmLayer::Gate_Max]; // pre-activation function results for each gate
  VectorBatch _gate[LstmLayer::Gate_Max];    // post-activation function results for each gate
  VectorBatch _cc;                      // cell state (save it for each step)
  VectorBatch _activ_cc;                // activ1(c(t))
  VectorBatch _hh;                      // hidden state aka output (save it for each step)
}; // class LstmLayer_Context

////////////////////////////////////////////////////////////////////////////////////////////////
//
// LstmLayer_TrainingContext implementation
//
class LstmLayer_TrainingContext :
    public LstmLayer_Context
{
  typedef LstmLayer_Context Base;
  friend class LstmLayer;

public:
  LstmLayer_TrainingContext(
      const MatrixSize & input_size,
      const MatrixSize & output_size,
      const MatrixSize & batch_size,
      const unique_ptr<Layer::Updater> & updater) :
    Base(output_size, batch_size)
  {
    init(updater, input_size);
  }

  LstmLayer_TrainingContext(
      const MatrixSize & input_size,
      const RefVectorBatch & output,
      const unique_ptr<Layer::Updater> & updater) :
    Base(output)
  {
    init(updater, input_size);
  }

  // Layer::Context overwrites
  virtual void start_epoch()
  {
    Base::start_epoch();

    for(auto & ww_x_updater: _ww_x_updater) {
      YANN_SLOW_CHECK(ww_x_updater);
      ww_x_updater->start_epoch();
    }
    for(auto & ww_h_updater: _ww_h_updater) {
      YANN_SLOW_CHECK(ww_h_updater);
      ww_h_updater->start_epoch();
    }
    for(auto & bb_updater: _bb_updater) {
      YANN_SLOW_CHECK(bb_updater);
      bb_updater->start_epoch();
    }
  }

  virtual void reset_state()
  {
    Base::reset_state();

    for(auto & delta_ww_x: _delta_ww_x) {
      delta_ww_x.setZero();
    }
    for(auto & delta_ww_h: _delta_ww_h) {
      delta_ww_h.setZero();
    }
    for(auto & delta_bb: _delta_bb) {
      delta_bb.setZero();
    }

    for(auto & ww_x_updater: _ww_x_updater) {
      YANN_SLOW_CHECK(ww_x_updater);
      ww_x_updater->reset();
    }
    for(auto & ww_h_updater: _ww_h_updater) {
      YANN_SLOW_CHECK(ww_h_updater);
      ww_h_updater->reset();
    }
    for(auto & bb_updater: _bb_updater) {
      YANN_SLOW_CHECK(bb_updater);
      bb_updater->reset();
    }

    _gradient_hh.setZero();
    _gradient_cc.setZero();
  }

private:
  void init(
      const unique_ptr<Layer::Updater> & updater,
      const MatrixSize & input_size)
  {
    YANN_CHECK_GT(updater, 0);
    YANN_CHECK_GT(input_size, 0);

    // deltas
    for(auto & delta_ww_x: _delta_ww_x) {
      delta_ww_x.resize(input_size, get_output_size());
    }
    for(auto & delta_ww_h: _delta_ww_h) {
      delta_ww_h.resize(get_output_size(), get_output_size());
    }
    for(auto & delta_bb: _delta_bb) {
      delta_bb.resize(get_output_size());
    }

    // updaters
    for(auto & ww_x_updater: _ww_x_updater) {
      ww_x_updater = updater->copy();
      YANN_SLOW_CHECK(ww_x_updater);
      ww_x_updater->init(input_size, get_output_size());
    }
    for(auto & ww_h_updater: _ww_h_updater) {
      ww_h_updater = updater->copy();
      YANN_SLOW_CHECK(ww_h_updater);
      ww_h_updater->init(get_output_size(), get_output_size());
    }
    for(auto & bb_updater: _bb_updater) {
      bb_updater = updater->copy();
      YANN_SLOW_CHECK(bb_updater);
      bb_updater->init(1, get_output_size()); // RowMajor
    }

    // gate radients
    _gradient_hh.resize(get_output_size());
    _gradient_cc.resize(get_output_size());
    _gradient_gate.resize(get_output_size());
    _gradient_zz_gate.resize(get_output_size());
    _tmp_derivative.resize(get_output_size());
  }

private:
  Matrix _delta_ww_x[LstmLayer::Gate_Max];
  Matrix _delta_ww_h[LstmLayer::Gate_Max];
  Vector _delta_bb[LstmLayer::Gate_Max];

  unique_ptr<Layer::Updater> _ww_x_updater[LstmLayer::Gate_Max];
  unique_ptr<Layer::Updater> _ww_h_updater[LstmLayer::Gate_Max];
  unique_ptr<Layer::Updater> _bb_updater[LstmLayer::Gate_Max];

  Vector _gradient_hh;
  Vector _gradient_cc;
  Vector _gradient_gate;
  Vector _gradient_zz_gate;
  Vector _tmp_derivative;
}; // class LstmLayer_TrainingContext

}; // namespace yann

////////////////////////////////////////////////////////////////////////////////////////////////
//
// yann::LstmLayer implementation
//
yann::LstmLayer::LstmLayer(
    const MatrixSize & input_size,
    const MatrixSize & output_size) :
    _gate_activation_function(new SigmoidFunction()),
    _io_activation_function(new TanhFunction())
{
  YANN_CHECK_GT(input_size, 0);

  for(auto & ww_x: _ww_x) {
    ww_x.resize(input_size, output_size);
  }
  for(auto & ww_h: _ww_h) {
    ww_h.resize(output_size, output_size);
  }
  for(auto & bb: _bb) {
    bb.resize(output_size);
  }
}

yann::LstmLayer::~LstmLayer()
{
}

void yann::LstmLayer::set_values(
    const Matrix (& ww_x)[Gate_Max],
    const Matrix (& ww_h)[Gate_Max],
    const Vector (& bb)[Gate_Max])
{
  for(auto ii = 0; ii < Gate_Max; ++ii) {
    YANN_CHECK(is_same_size(ww_x[ii], _ww_x[ii]));
    YANN_CHECK(is_same_size(ww_h[ii], _ww_h[ii]));
    YANN_CHECK(is_same_size(bb[ii], _bb[ii]));

    _ww_x[ii] = ww_x[ii];
    _ww_h[ii] = ww_h[ii];
    _bb[ii] = bb[ii];
  }
}

void yann::LstmLayer::set_activation_functions(
    const std::unique_ptr<ActivationFunction> & gate_activation_function,
    const std::unique_ptr<ActivationFunction> & io_activation_function)
{
  YANN_CHECK(gate_activation_function);
  YANN_CHECK(io_activation_function);
  _gate_activation_function = gate_activation_function->copy();
  _io_activation_function = io_activation_function->copy();
}

// Layer overwrites
bool yann::LstmLayer::is_valid() const
{
  if(!Base::is_valid()) {
    return false;
  }
  if(!_io_activation_function || !_gate_activation_function) {
    return false;
  }
  for(auto ii = 0; ii < Gate_Max; ++ii) {
    if(!is_same_size(_ww_x[0], _ww_x[ii])) {
      return false;
    }
    if(!is_same_size(_ww_h[0], _ww_h[ii])) {
      return false;
    }
    if(!is_same_size(_bb[0], _bb[ii])) {
      return false;
    }
  }

  return true;
}

std::string yann::LstmLayer::get_name() const
{
  return "LstmLayer";
}

string yann::LstmLayer::get_info() const
{
  YANN_CHECK(is_valid());

  ostringstream oss;
  oss << Base::get_info()
      << ", state activation: " << _io_activation_function->get_info()
      << ", output activation: " << _gate_activation_function->get_info()
      ;
  return oss.str();
}

bool yann::LstmLayer::is_equal(const Layer & other, double tolerance) const
{
  if(!Base::is_equal(other, tolerance)) {
    return false;
  }
  auto the_other = dynamic_cast<const LstmLayer*>(&other);
  if(the_other == nullptr) {
    return false;
  }
  // TOOD: add deep compare
  if(_io_activation_function->get_info() != the_other->_io_activation_function->get_info()) {
    return false;
  }
  if(_gate_activation_function->get_info() != the_other->_gate_activation_function->get_info()) {
    return false;
  }
  for(auto ii = 0; ii < Gate_Max; ++ii) {
    if(!_ww_x[ii].isApprox(the_other->_ww_x[ii], tolerance)) {
      return false;
    }
    if(!_ww_h[ii].isApprox(the_other->_ww_h[ii], tolerance)) {
      return false;
    }
    if(!_bb[ii].isApprox(the_other->_bb[ii], tolerance)) {
      return false;
    }
  }
  return true;
}

MatrixSize yann::LstmLayer::get_input_size() const
{
  YANN_SLOW_CHECK(is_valid());
  return _ww_x[Gate_A].rows();
}

MatrixSize yann::LstmLayer::get_output_size() const
{
  YANN_SLOW_CHECK(is_valid());
  return _ww_x[Gate_A].cols();
}

unique_ptr<Layer::Context> yann::LstmLayer::create_context(const MatrixSize & batch_size) const
{
  YANN_CHECK(is_valid());
  return make_unique<LstmLayer_Context>(get_output_size(), batch_size);
}
unique_ptr<Layer::Context> yann::LstmLayer::create_context(const RefVectorBatch & output) const
{
  YANN_CHECK(is_valid());
  return make_unique<LstmLayer_Context>(output);
}
unique_ptr<Layer::Context> yann::LstmLayer::create_training_context(
    const MatrixSize & batch_size, const std::unique_ptr<Layer::Updater> & updater) const
{
  YANN_CHECK(is_valid());
  YANN_CHECK(updater);
  return make_unique<LstmLayer_TrainingContext>(
      get_input_size(), get_output_size(), batch_size, updater);
}
unique_ptr<Layer::Context> yann::LstmLayer::create_training_context(
    const RefVectorBatch & output, const std::unique_ptr<Layer::Updater> & updater) const
{
  YANN_CHECK(is_valid());
  YANN_CHECK(updater);
  return make_unique<LstmLayer_TrainingContext>(
      get_input_size(), output, updater);
}

template<typename InputType>
void yann::LstmLayer::feedforward_internal(
    const InputType & input,
    Context * context,
    enum OperationMode mode) const
{
  auto ctx = dynamic_cast<LstmLayer_Context *>(context);
  YANN_CHECK(ctx);
  YANN_CHECK(is_valid());
  YANN_CHECK_LE(get_batch_size(input) + ctx->_pos, ctx->get_batch_size());
  YANN_CHECK_LE(get_batch_size(input), get_batch_size(ctx->get_output()));
  YANN_CHECK_EQ(get_batch_item_size(input), get_input_size());

  for(MatrixSize ii = 0; ii < get_batch_size(input); ++ii, ++ctx->_pos) {
    // Phase 1: I/O gates
    //  zz_a(t) = ww_xa*x(t) + ww_ha * h(t-1) + bb_a  -- input
    //  zz_i(t) = ww_xi*x(t) + ww_hi * h(t-1) + bb_i  -- input gate
    //  zz_f(t) = ww_xf*x(t) + ww_hf * h(t-1) + bb_g  -- forget gate
    //  zz_o(t) = ww_xo*x(t) + ww_ho * h(t-1) + bb_o  -- output gate
    auto in  = get_batch(input, ii);
    auto out = get_batch(ctx->get_output(), ctx->_pos);
    auto hh  = get_batch(ctx->_hh, ctx->_pos);
    if(ctx->_pos > 0) {
      const auto & hh_prev = get_batch(ctx->_hh, ctx->_pos - 1);
      for(auto jj = 0; jj < Gate_Max; ++jj) {
        auto zz_gate = get_batch(ctx->_zz_gate[jj], ctx->_pos);
        zz_gate.noalias() = MatrixFunctions<InputType>::product(in, _ww_x[jj]);
        zz_gate.noalias() += MatrixFunctions<RefConstMatrix>::product(hh_prev, _ww_h[jj]) + _bb[jj];
      }
    } else {
      for(auto jj = 0; jj < Gate_Max; ++jj) {
        auto zz_gate = get_batch(ctx->_zz_gate[jj], ctx->_pos);
        zz_gate.noalias() = MatrixFunctions<InputType>::product(in, _ww_x[jj]);
        zz_gate.noalias() += _bb[jj];
      }
    }

    //  a(t) = activ1 (zz_a(t))
    //  i(t) = activ2 (zz_i(t))
    //  f(t) = activ2 (zz_f(t))
    //  o(t) = activ2 (zz_o(t))
    for(auto jj = 0; jj < Gate_Max; ++jj) {
      const auto zz_gate = get_batch(ctx->_zz_gate[jj], ctx->_pos);
      auto gate = get_batch(ctx->_gate[jj], ctx->_pos);
      if(jj > 0) {
        _gate_activation_function->f(zz_gate, gate, Operation_Assign);
      } else {
        _io_activation_function->f(zz_gate, gate, Operation_Assign);
      }
    }

    // Phase 2: State
    //  c(t) = elem_prod(i(t), a(t)) + elem_prod(f(t), c(t-1))
    const auto gate_aa = get_batch(ctx->_gate[Gate_A], ctx->_pos);
    const auto gate_ii = get_batch(ctx->_gate[Gate_I], ctx->_pos);
    const auto gate_ff = get_batch(ctx->_gate[Gate_F], ctx->_pos);
    auto cc = get_batch(ctx->_cc, ctx->_pos);
    if(ctx->_pos > 0) {
      const auto & cc_prev = get_batch(ctx->_cc, ctx->_pos - 1);
      cc.array() = gate_ii.array() * gate_aa.array() + gate_ff.array() * cc_prev.array();
    } else {
      cc.array() = gate_ii.array() * gate_aa.array();
    }

    // Phase 3: Output
    //  h(t) = elem_prod(o(t), activ1(c(t))
    const auto gate_oo = get_batch(ctx->_gate[Gate_O], ctx->_pos);
    auto activ_cc = get_batch(ctx->_activ_cc, ctx->_pos);
    _io_activation_function->f(cc, activ_cc, Operation_Assign);
    hh.array() = gate_oo.array() * activ_cc.array();

    // done!
    switch(mode) {
    case Operation_Assign:
      out.noalias() = hh;
      break;
    case Operation_PlusEqual:
      out.noalias() += hh;
      break;
    }
  }
}

void yann::LstmLayer::feedforward(
    const RefConstVectorBatch & input,
    Context * context,
    enum OperationMode mode) const
{
  feedforward_internal(input, context, mode);
}

void yann::LstmLayer::feedforward(
    const RefConstSparseVectorBatch & input,
    Context * context,
    enum OperationMode mode) const
{
  feedforward_internal<RefConstSparseMatrix>(input, context, mode);
}

template<
  typename MainInputType,
  typename InputType,
  typename GradientInputType,
  typename ContextType
>
void yann::LstmLayer::backprop_gate(
    enum IOGates gate,
    const std::unique_ptr<ActivationFunction> & activation_function,
    const RefConstVector & gradient_gate,
    const InputType & input,
    boost::optional<GradientInputType> gradient_in,
    ContextType * ctx) const
{
  YANN_SLOW_CHECK(activation_function);
  YANN_SLOW_CHECK(ctx);

  const auto zz_gate = get_batch(ctx->_zz_gate[gate], ctx->_pos);
  const auto & ww_x = _ww_x[gate];
  const auto & ww_h = _ww_h[gate];
  auto & gradient_zz_gate = ctx->_gradient_zz_gate;
  auto & tmp_derivative = ctx->_tmp_derivative;

  // gate(t) = activ(zz_gate(t))
  //
  // grad(zz_gate) = grad(gate) * activ'(zz_gate)
  activation_function->derivative(zz_gate, tmp_derivative);
  gradient_zz_gate.array() = gradient_gate.array() * tmp_derivative.array();

  // zz_gate(t) = ww_x_gate*x(t) + ww_h_gate * h(t-1) + bb_gate
  //
  // grad(ww_x_gate) = grad(zz_gate) * d zz_gate/dww_x_gate = grad(zz_gate) * x(t)
  // grad(ww_h_gate) = grad(zz_gate) * d zz_gate/dww_h_gate = grad(zz_gate) * h(t-1)
  // grad(b) = grad(zz_gate) * d zz_gate/db = grad(zz_gate)
  YANN_SLOW_CHECK(is_same_size(ctx->_delta_ww_x[gate], _ww_x[gate]));
  YANN_SLOW_CHECK(is_same_size(ctx->_delta_ww_h[gate], _ww_h[gate]));
  YANN_SLOW_CHECK(is_same_size(ctx->_delta_bb[gate], _bb[gate]));
  ctx->_delta_ww_x[gate] += MatrixFunctions<MainInputType>::product(input.transpose(), gradient_zz_gate);
  if(ctx->_pos > 0) {
    auto prev_hh = get_batch(ctx->_hh, ctx->_pos - 1);
    ctx->_delta_ww_h[gate] += MatrixFunctions<RefConstMatrix>::product(prev_hh.transpose(), gradient_zz_gate);
  }
  ctx->_delta_bb[gate].noalias() += gradient_zz_gate;

  // zz_gate(t) = ww_x_gate*x(t) + ww_h_gate * h(t-1) + bb_gate
  //
  // grad(h) = grad(zz_gate) * d zz_gate/dh = grad(zz_gate) * transp(ww_h_gate)
  if(ctx->_pos > 0) {
    auto & gradient_hh = ctx->_gradient_hh;
    gradient_hh.noalias() += MatrixFunctions<RefConstMatrix>::product(gradient_zz_gate, ww_h.transpose());
  }

  // zz_gate(t) = ww_x_gate*x(t) + ww_h_gate * h(t-1) + bb_gate
  //
  //  grad(x) = grad(zz_gate) * d zz_gate/dx = grad(zz_gate) * transp(ww_x_gate)
  if(gradient_in) {
    (*gradient_in).noalias() += MatrixFunctions<RefConstMatrix>::product(gradient_zz_gate, ww_x.transpose());
  }
}

template<typename InputType>
void yann::LstmLayer::backprop_internal(
    const RefConstVectorBatch & gradient_output,
    const InputType & input,
    optional<RefVectorBatch> gradient_input,
    Context * context) const
{
  auto ctx = dynamic_cast<LstmLayer_TrainingContext *>(context);
  YANN_CHECK(ctx);
  YANN_CHECK(is_valid());
  YANN_CHECK_GT(get_batch_size(gradient_output), 0);
  YANN_CHECK_LE(get_batch_size(gradient_output), ctx->_pos);
  YANN_CHECK_EQ(get_batch_item_size(gradient_output), get_output_size());
  YANN_CHECK_EQ(get_batch_size(input), get_batch_size(gradient_output));
  YANN_CHECK_EQ(get_batch_item_size(input), get_input_size());
  YANN_CHECK_EQ(get_batch_item_size(input), get_input_size());
  YANN_CHECK(!gradient_input || is_same_size(input, *gradient_input));

  // Zero out since we will be adding to it
  if(gradient_input) {
    gradient_input->setZero();
  }

  for(MatrixSize ii = get_batch_size(gradient_output) - 1; ii >= 0 && (--ctx->_pos) >= 0; --ii) {
    const auto in = get_batch(input, ii);
    auto gradient_in = gradient_input ? make_optional(get_batch(*gradient_input, ii)) : boost::none;
    const auto gate_aa  = get_batch(ctx->_gate[Gate_A], ctx->_pos);
    const auto gate_ii  = get_batch(ctx->_gate[Gate_I], ctx->_pos);
    const auto gate_ff  = get_batch(ctx->_gate[Gate_F], ctx->_pos);
    const auto gate_oo  = get_batch(ctx->_gate[Gate_O], ctx->_pos);
    auto & gradient_gate = ctx->_gradient_gate;

    // note that output gradient also has the internal feedback loop
    auto & gradient_hh = ctx->_gradient_hh;
    gradient_hh += get_batch(gradient_output, ii);

    // State cell
    //
    //  h(t) = elem_prod(o(t), activ1(c(t))
    //  grad(c) = grad(h) * d h/dactiv1(c) * activ1'(c) = elem_prod(grad(h), o, activ1(c)
    const auto cc = get_batch(ctx->_cc, ctx->_pos);
    auto & gradient_cc = ctx->_gradient_cc;
    auto & tmp_derivative = ctx->_tmp_derivative;
    _io_activation_function->derivative(cc, tmp_derivative);
    // add to the gradient from previous step
    gradient_cc.array() += gradient_hh.array() * gate_oo.array() * tmp_derivative.array();

    // Gate O: Output gate:
    //
    //  h(t) = elem_prod(o(t), activ1(c(t))
    //  grad(o) = grad(h) * dh/do = elem_prod(grad(h), activ1(c))
    const auto activ_cc = get_batch(ctx->_activ_cc, ctx->_pos);
    gradient_gate.array() = gradient_hh.array() * activ_cc.array();
    gradient_hh.setZero(); // we will update it in backprop_gate for next step
    backprop_gate<InputType>(Gate_O, _gate_activation_function, gradient_gate, in, gradient_in, ctx);

    // Gate A
    //
    //  c(t) = elem_prod(i(t), a(t)) + elem_prod(f(t), c(t-1))
    //  grad(a) = grad(c) * dc/da = elem_prod(grad(c), i(t))
    gradient_gate.array() = gradient_cc.array() * gate_ii.array();
    backprop_gate<InputType>(Gate_A, _io_activation_function, gradient_gate, in, gradient_in, ctx);

    // Gate I: Input gate
    //
    //  c(t) = elem_prod(i(t), a(t)) + elem_prod(f(t), c(t-1))
    //  grad(i) = grad(c) * dc/di = elem_prod(grad(c), a(t))
    gradient_gate.array() = gradient_cc.array() * gate_aa.array();
    backprop_gate<InputType>(Gate_I, _gate_activation_function, gradient_gate, in, gradient_in, ctx);

    // Gate F: Forget gate
    //
    //  c(t) = elem_prod(i(t), a(t)) + elem_prod(f(t), c(t-1))
    //  grad(f) = grad(c) * dc/df = elem_prod(grad(c), c(t-1))
    if(ctx->_pos > 0) {
      const auto prev_cc = get_batch(ctx->_activ_cc, ctx->_pos - 1);
      gradient_gate.array() = gradient_cc.array() * prev_cc.array();
    } else {
      gradient_gate.setZero();
    }
    backprop_gate<InputType>(Gate_F, _gate_activation_function, gradient_gate, in, gradient_in, ctx);

    // State gradient for prev step
    //
    //  c(t) = elem_prod(i(t), a(t)) + elem_prod(f(t), c(t-1))
    //  grad(c(t-1)) = grad(c) * dc(t)/dc(t-1) = elem_prod(grad(c(t)), f(t))
    if(ctx->_pos > 0) {
      gradient_cc.array() = gradient_cc.array() * gate_ff.array();
    }
  }
}

void yann::LstmLayer::backprop(
    const RefConstVectorBatch & gradient_output,
    const RefConstVectorBatch & input,
    optional<RefVectorBatch> gradient_input,
    Context * context) const
{
  backprop_internal(gradient_output, input, gradient_input, context);
}

void yann::LstmLayer::backprop(
    const RefConstVectorBatch & gradient_output,
    const RefConstSparseVectorBatch & input,
    optional<RefVectorBatch> gradient_input,
    Context * context) const
{
  // <RefConstSparseMatrix> is required for MatrixFunctions<>::product
  backprop_internal<RefConstSparseMatrix>(gradient_output, input, gradient_input, context);
}

void yann::LstmLayer::init(enum InitMode mode, boost::optional<InitContext> init_context)
{
  switch (mode) {
  case InitMode_Zeros:
    for(auto & ww_x: _ww_x) {
      ww_x.setZero();
    }
    for(auto & ww_h: _ww_h) {
      ww_h.setZero();
    }
    for(auto & bb: _bb) {
      bb.setZero();
    }
    break;
  case InitMode_Random:
    {
      unique_ptr<RandomGenerator> gen01 = RandomGenerator::normal_distribution(0, 1,
          init_context ? optional<Value>(init_context->seed()) : boost::none);
      for(auto & ww_x: _ww_x) {
        gen01->generate(ww_x);
      }
      for(auto & ww_h: _ww_h) {
        gen01->generate(ww_h);
      }
      for(auto & bb: _bb) {
        gen01->generate(bb);
      }
    }
    break;
  }
}

void yann::LstmLayer::update(Context * context, const size_t & tests_num)
{
  auto ctx = dynamic_cast<LstmLayer_TrainingContext *>(context);
  YANN_CHECK(ctx);

  for(auto ii = 0; ii < Gate_Max; ++ii) {
    YANN_SLOW_CHECK(ctx->_ww_x_updater[ii]);
    YANN_SLOW_CHECK(ctx->_ww_h_updater[ii]);
    YANN_SLOW_CHECK(ctx->_bb_updater[ii]);

    ctx->_ww_x_updater[ii]->update(ctx->_delta_ww_x[ii], tests_num, _ww_x[ii]);
    ctx->_ww_h_updater[ii]->update(ctx->_delta_ww_h[ii], tests_num, _ww_h[ii]);
    ctx->_bb_updater[ii]->update(ctx->_delta_bb[ii], tests_num, _bb[ii]);
  }
}

// the format is (no new lines):
// (wxa:<_ww_x[Gate_A]>,wxh:<_ww_h[Gate_A]>,ba:<_bb[Gate_A]>,
//  wxi:<_ww_x[Gate_I]>,wxi:<_ww_h[Gate_I]>,bi:<_bb[Gate_I]>,
//  wxf:<_ww_x[Gate_F]>,wxf:<_ww_h[Gate_F]>,bf:<_bb[Gate_F]>,
//  wxo:<_ww_x[Gate_O]>,wxo:<_ww_h[Gate_O]>,bo:<_bb[Gate_O]>)
void yann::LstmLayer::read(std::istream & is)
{
  Base::read(is);

  read_char(is, '(');

  for(auto ii = 0; ii < Gate_Max; ++ii) {
    const char & suffix =  g_ltsm_names_suffix[ii];
    if(ii > 0) {
      read_char(is, ',');
    }
    read_object(is, string("wx") + suffix, _ww_x[ii]);
    read_char(is, ',');
    read_object(is, string("wh") + suffix, _ww_h[ii]);
    read_char(is, ',');
    read_object(is, string("b") + suffix, _bb[ii]);
  }
  read_char(is, ')');
}

// the format is (no new lines):
// (wxa:<_ww_x[Gate_A]>,wxh:<_ww_h[Gate_A]>,ba:<_bb[Gate_A]>,
//  wxi:<_ww_x[Gate_I]>,wxi:<_ww_h[Gate_I]>,bi:<_bb[Gate_I]>,
//  wxf:<_ww_x[Gate_F]>,wxf:<_ww_h[Gate_F]>,bf:<_bb[Gate_F]>,
//  wxo:<_ww_x[Gate_O]>,wxo:<_ww_h[Gate_O]>,bo:<_bb[Gate_O]>)
void yann::LstmLayer::write(std::ostream & os) const
{
  Base::write(os);

  os << "(";
  for(auto ii = 0; ii < Gate_Max; ++ii) {
    const char & suffix =  g_ltsm_names_suffix[ii];
    if(ii > 0) {
      os << ",";
    }
    write_object(os, string("wx") + suffix, _ww_x[ii]);
    os << ",";
    write_object(os, string("wh") + suffix, _ww_h[ii]);
    os << ",";
    write_object(os, string("b") + suffix, _bb[ii]);
  }
  os << ")";
}

ext: cpp


text:
/*
 *
 * Copyright (c) 1998-2002
 * Dr John Maddock
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.  Dr John Maddock makes no representations
 * about the suitability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 *
 */

 /*
  *   LOCATION:    see http://www.boost.org for most recent version.
  *   FILE         pattern_except.hpp
  *   VERSION      see <boost/version.hpp>
  *   DESCRIPTION: Declares pattern-matching exception classes.
  */

#ifndef BOOST_RE_PAT_EXCEPT_HPP
#define BOOST_RE_PAT_EXCEPT_HPP

#include <boost/regex/config.hpp>

namespace boost{

#ifdef __BORLANDC__
   #pragma option push -a4 -b -Ve -pc
#endif

class BOOST_REGEX_DECL bad_pattern : public std::runtime_error
{
public:
   explicit bad_pattern(const std::string& s) : std::runtime_error(s){};
   ~bad_pattern() throw();
};

class BOOST_REGEX_DECL bad_expression : public bad_pattern
{
public:
   explicit bad_expression(const std::string& s) : bad_pattern(s) {}
   ~bad_expression() throw();
};

#ifdef __BORLANDC__
  #pragma option pop
#endif

} // namespace boost

#endif

ext: hpp


text: #include <boost/numeric/interval/compare/explicit.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
#pragma once

#include <boost/compute.hpp>

#include "../../common.hpp"

namespace aya
{
namespace backend
{

namespace compute = boost::compute;
void ping()
{
    std::cout << "pong from boost backend\n";
}

template <typename T>
struct Backend
{
    Backend()
    {
        gpu = compute::system::default_device();
        context = compute::context(gpu);
        queue = compute::command_queue(context, gpu);
    }

    ~Backend()
    {
        std::cout << "boost backend destructor called\n";
    }

    std::vector<T> topK(const std::vector<T> &src, unsigned int k)
    {
        auto d_vec = compute::vector<T>(src.size(), context);
        compute::copy(src.begin(), src.end(), d_vec.begin(), queue);
        compute::sort(d_vec.begin(), d_vec.end(), compute::greater<T>(), queue);
        queue.finish();
        if (k > src.size())
        {
            std::cout << "warn: k " << k << " is larger than size " << src.size();
            k = src.size();
        }
        std::vector<T> result(k);
        compute::copy(d_vec.begin(), d_vec.begin() + k, result.begin(), queue);
        queue.finish();
        return result;
    }

    // FIXME: can we keep the cout when using counting iterator?
    // std::vector<unsigned int> topKIndex(const std::vector<T> &src, unsigned int k)
    // {
    //     auto d_vec = compute::vector<T>(src.size(), context);
    //     compute::copy(src.begin(), src.end(), d_vec.begin(), queue);
    //     compute::counting_iterator<T> index(0);
    //     compute::sort_by_key(d_vec.begin(), d_vec.end(), index.begin(), queue);
    // }

  private:
    compute::device gpu;
    compute::context context;
    compute::command_queue queue;
};

template <typename T>
Backend<T> *init()
{
    return new Backend<T>;
}
} // backend
} // aya::backend


text:
#include "mainwindow.h"

#include <iostream>
#include <boost/optional.hpp>
#include <QApplication>
#include <QThread>
#include <QTimer>

using namespace std;
static boost::optional<race> currentRace = none;
static boost::optional<isAlive> currentAlive = none;
static boost::optional<character> currentCharacter = none;
static boost::optional<posNeg> currentPosNeg = none;
static boost::optional<status> curStatus = none;
static boost::optional<realm> curRealm = none;
static boost::optional<activity> curActivity = none;
static bool algoStop = false;
static bool waitForUser = false;
static bool triggerRestart = false;
template <typename T>
bool analyzeRule(Rule<T>* rule, QStack<Goal*> * goalStack)    {

    switch (rule->checkRule(currentRace, currentAlive, currentPosNeg, curStatus, curRealm, curActivity)) {

        case 1:

            if (typeid (T) == typeid(race))
                currentRace = static_cast<race>(rule->getConclusion());
            else if (typeid (T) == typeid(isAlive))
                currentAlive = static_cast<isAlive>(rule->getConclusion());
            else if (typeid(T) == typeid(character))
                currentCharacter = static_cast<character>(rule->getConclusion());
            else if (typeid(T) == typeid(realm))
                curRealm = static_cast<realm>(rule->getConclusion());
            else if (typeid(T) == typeid(posNeg))
                currentPosNeg = static_cast<posNeg>(rule->getConclusion());
            else if (typeid(T) == typeid(status))
                curStatus = static_cast<status>(rule->getConclusion());
            else if (typeid(T) == typeid(activity))
                curActivity = static_cast<activity>(rule->getConclusion());

            goalStack->pop();

            rule->tossAway();       // we don't need this rule anymore ???

            if (goalStack->empty())
                algoStop = true;
            else return true;
        break;

        case 0:         // rule is  false
            rule->tossAway();
        break;

        case -1:
            goalStack->push(new Attribute<race>(rule->getNumber()));     // push into stack with this rule's number

        break;

        case -2:
            goalStack->push(new Attribute<isAlive>(rule->getNumber()));
        break;

        case -3:
            goalStack->push(new Attribute<posNeg>(rule->getNumber()));
        break;

        case -4:
            goalStack->push(new Attribute<status>(rule->getNumber()));
        break;

        case -5:
            goalStack->push(new Attribute<realm>(rule->getNumber()));
        break;

        case -6:
            goalStack->push(new Attribute<activity>(rule->getNumber()));
        break;

    }

    return false;

}

bool preProcAnalyzeRule(int i, QList<Goal*> * ruleList, QStack<Goal*> * goalStack)   {

    bool anRetType;
    if (ruleList->at(i)->returnType() == "r race")
        anRetType = analyzeRule(static_cast<Rule<race>*>(ruleList->at(i)), goalStack);
    else if (ruleList->at(i)->returnType() == "r isAlive")
        anRetType = analyzeRule(static_cast<Rule<isAlive>*>(ruleList->at(i)), goalStack);
    else if (ruleList->at(i)->returnType() == "r character")
        anRetType = analyzeRule(static_cast<Rule<character>*>(ruleList->at(i)), goalStack);
    else if (ruleList->at(i)->returnType() == "r status")
        anRetType = analyzeRule(static_cast<Rule<status>*>(ruleList->at(i)), goalStack);
    else if (ruleList->at(i)->returnType() == "r posNeg")
        anRetType = analyzeRule(static_cast<Rule<posNeg>*>(ruleList->at(i)), goalStack);
    else if (ruleList->at(i)->returnType() == "r realm")
        anRetType = analyzeRule(static_cast<Rule<realm>*>(ruleList->at(i)), goalStack);
    else if (ruleList->at(i)->returnType() == "r activity")
        anRetType = analyzeRule(static_cast<Rule<activity>*>(ruleList->at(i)), goalStack);
    return anRetType;

}

int searchRule(Goal* goal, QList<Goal*> * ruleList)  {

    // there are only rules on the ruleList

    string goalName = goal ->returnType();

    for (int i = 0; i<ruleList->size(); ++i)    {

        if (ruleList->at(i)->isActual())    {
            string ruleReturnType = ruleList->at(i)->returnType();

            int compareStrings = goalName.compare(2, string::npos, ruleReturnType, 2, string::npos);

            if (compareStrings == 0)
                return i;
        }
    }

    return -1;

}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{

    setupUi(this);

    this->setWindowIcon(QIcon("images/LotrIcon.png"));

    uint quant = ruleList.size();
    ruleList.append(new Rule<isAlive>(isAlive::alive, quant++, race::Valar));
    ruleList.append(new Rule<character>(character::Gimli, quant++, race::Dwarf, isAlive::alive));
    ruleList.append(new Rule<character>(character::Thorin, quant++, race::Dwarf, isAlive::dead, posNeg::positive,
                                        status::king, realm::LonelyM));
    ruleList.append(new Rule<character>(character::Balin, quant++, race::Dwarf, isAlive::dead, posNeg::positive,
                                        status::king, realm::Moria));
    ruleList.append(new Rule<character>(character::Frodo, quant++, race::Hobbit, isAlive::alive, posNeg::positive,
                                        status::undefinedStatus, realm::Shire, activity::woreTheRing));
    ruleList.append(new Rule<character>(character::Bilbo, quant++, race::Hobbit, isAlive::alive, posNeg::positive,
                                        status::undefinedStatus, realm::Shire, activity::helpedTheDwarves));
    ruleList.append(new Rule<character>(character::Gollum, quant++, race::Hobbit, isAlive::dead, posNeg::negative,
                                        status::undefinedStatus, realm::Shire, activity::woreTheRing));
    ruleList.append(new Rule<status>(status::regular, quant++, race::Hobbit, isAlive::undefinedIsAlive, posNeg::undefinedPosNeg,
                                        status::undefinedStatus, realm::undefinedRealm));

    ruleList.append(new Rule<character>(character::Sam, quant++, race::Hobbit, isAlive::alive, posNeg::positive,
                                        status::undefinedStatus, realm::Shire, activity::helpedHisMaster));
    ruleList.append(new Rule<character>(character::Merry, quant++, race::Hobbit, isAlive::alive, posNeg::positive,
                                        status::undefinedStatus, realm::Rohan, activity::undefinedActivity));
    ruleList.append(new Rule<character>(character::Pippin, quant++, race::Hobbit, isAlive::alive, posNeg::positive,
                                        status::undefinedStatus, realm::Gondor, activity::undefinedActivity));
    ruleList.append(new Rule<character>(character::Elrond, quant++, race::Elf, isAlive::alive, posNeg::positive,
                                        status::king, realm::Rivendell, activity::undefinedActivity));

    ruleList.append(new Rule<character>(character::Galadriel, quant++, race::Elf, isAlive::alive, posNeg::positive,
                                        status::king, realm::Lorien, activity::undefinedActivity));
    ruleList.append(new Rule<character>(character::Thranduil, quant++, race::Elf, isAlive::alive, posNeg::positive,
                                        status::king, realm::Mirkwood, activity::undefinedActivity));
    ruleList.append(new Rule<character>(character::Legolas, quant++, race::Elf, isAlive::alive, posNeg::positive,
                                        status::greatWarrior, realm::Mirkwood, activity::undefinedActivity));
    ruleList.append(new Rule<character>(character::Glorfindel, quant++, race::Elf, isAlive::alive, posNeg::positive,
                                        status::greatWarrior, realm::Gondolin));
    ruleList.append(new Rule<character>(character::Fingolfin, quant++, race::Elf, isAlive::dead, posNeg::positive,
                                        status::king, realm::undefinedRealm, activity::fougthMorgoth));
    ruleList.append(new Rule<character>(character::GilGalad, quant++, race::Elf, isAlive::dead, posNeg::positive,
                                        status::king, realm::undefinedRealm, activity::diedFightingSauron));
    ruleList.append(new Rule<character>(character::Turgon, quant++, race::Elf, isAlive::dead, posNeg::positive,
                                        status::king, realm::Gondolin));
    ruleList.append(new Rule<character>(character::Echtelion, quant++, race::Elf, isAlive::dead, posNeg::positive,
                                        status::greatWarrior, realm::Gondolin));
    ruleList.append(new Rule<character>(character::Feanor, quant++, race::Elf, isAlive::dead, posNeg::negative,
                                        status::undefinedStatus, realm::undefinedRealm, activity::madeSilmarils));
    ruleList.append(new Rule<character>(character::Ingwe, quant++, race::Elf, isAlive::alive, posNeg::positive,
                                        status::king, realm::Valinor));
    ruleList.append(new Rule<character>(character::Aragorn, quant++, race::Man, isAlive::alive, posNeg::positive,
                                        status::king, realm::Gondor));
    ruleList.append(new Rule<character>(character::Eomer, quant++, race::Man, isAlive::alive, posNeg::positive,
                                        status::king, realm::Rohan));
    ruleList.append(new Rule<character>(character::Theoden, quant++, race::Man, isAlive::dead, posNeg::positive,
                                        status::king, realm::Rohan));
    ruleList.append(new Rule<character>(character::Tuor, quant++, race::Man, isAlive::dead, posNeg::positive,
                                        status::greatWarrior, realm::Gondolin));
    ruleList.append(new Rule<character>(character::Thurin, quant++, race::Man, isAlive::dead, posNeg::positive,
                                        status::greatWarrior, realm::DorLomin));
    ruleList.append(new Rule<character>(character::Boromir, quant++, race::Man, isAlive::dead, posNeg::positive,
                                        status::greatWarrior, realm::Gondor));
    ruleList.append(new Rule<character>(character::Sauron, quant++, race::Maiar, isAlive::dead, posNeg::negative,
                                        status::undefinedStatus, realm::Mordor));
    ruleList.append(new Rule<character>(character::Saruman, quant++, race::Maiar, isAlive::dead, posNeg::negative,
                                        status::undefinedStatus, realm::Orthanc));
    ruleList.append(new Rule<character>(character::Gandalf, quant++, race::Maiar, isAlive::alive, posNeg::positive,
                                        status::undefinedStatus, realm::undefinedRealm, activity::helpedPeoplesOfMiddleEarth));
    ruleList.append(new Rule<character>(character::Radagast, quant++, race::Maiar, isAlive::alive, posNeg::positive,
                                        status::undefinedStatus, realm::undefinedRealm, activity::TakesCareAboutAnimals));
    ruleList.append(new Rule<character>(character::Manwe, quant++, race::Valar, isAlive::undefinedIsAlive, posNeg::positive,
                                        status::undefinedStatus, realm::air));
    ruleList.append(new Rule<character>(character::Aule, quant++, race::Valar, isAlive::undefinedIsAlive, posNeg::positive,
                                        status::undefinedStatus, realm::earth));
    ruleList.append(new Rule<character>(character::Varda, quant++, race::Valar, isAlive::undefinedIsAlive, posNeg::positive,
                                        status::undefinedStatus, realm::stars));
    ruleList.append(new Rule<character>(character::Ulmo, quant++, race::Valar, isAlive::undefinedIsAlive, posNeg::positive,
                                        status::undefinedStatus, realm::water));
    ruleList.append(new Rule<character>(character::Melkor, quant++, race::Valar, isAlive::undefinedIsAlive, posNeg::negative));
    ruleList.append(new Rule<status>(status::king, quant++, race::Man, isAlive::alive));
    ruleList.append(new Rule<posNeg>(posNeg::positive, quant++, race::Man));
    ruleList.append(new Rule<character>(character::DurinsBane, quant++, race::Maiar, isAlive::dead, posNeg::negative,
                                        status::undefinedStatus, realm::Moria));
    ruleList.append(new Rule<character>(character::Glorfindel, quant++, race::Elf, isAlive::alive, posNeg::positive,
                                        status::greatWarrior, realm::Rivendell));

/*
    int quant = ruleList.size();
    int prepquant = 0;
    for (int al = isAlive::undefinedIsAlive; al<= isAlive::alive; al++)
    {
        for (int st = status::undefinedStatus; st<= status::regular; st++)
        {
            for (int pN = posNeg::undefinedPosNeg; pN<= posNeg::negative; pN++)
            {
                for (int act = activity::undefinedActivity; act<= activity::inTheQuestForLonelyMountaint; act++)
                {
                    int q = 0;
                    int ind = -1;
                    for (int i = prepquant; i<quant + prepquant; ++i)
                    {
                        if (ruleList.at(i)->returnType() == "r enum character")
                            if (((Rule<character>*)ruleList.at(i))->
                                    checkRuleUndefined(Elf, (isAlive)al, (posNeg)pN, (status)st, none,(activity)act))
                            {
                                q++;
                                ind = i;
                            }
                    }
                    if (q == 1)
                    {
                        ruleList.prepend(new Rule<character>(((Rule<character>*)ruleList.at(ind))->getConclusion(), 0,
                                                            Elf, (isAlive)al, (posNeg)pN, (status)st, realm::undefinedRealm, (activity)act));
                        for (int j = 1; j < ruleList.size(); ++j)
                            ruleList.at(j)->setNumber(ruleList.at(j)->getNumber()+1);
                        prepquant++;

                    }
                }
            }
        }
    }*/

    QAction *restart = new QAction("Restart");
    QAction *exit  = new QAction("Exit");
    this->menubar->addAction(restart);
    this->menubar->addAction(exit);
    this->stackedWidget->setCurrentWidget(startWidget);
    connect(restart, SIGNAL(triggered()), this, SLOT(on_tryAgainButton_clicked()));
    connect(exit, SIGNAL(triggered()), this, SLOT(on_actionexit_triggered()));
    connect(this, SIGNAL(destroyed()), this, SLOT(on_actionexit_triggered()));
    connect(startButton, SIGNAL(clicked()), this, SLOT(on_tryAgainButton_clicked()));

}

void MainWindow::exec()  {

    goalStack.push(new Attribute<character>());
    algoStop = false;
    while (!algoStop)   {

        int i = searchRule(goalStack.top(), &ruleList);

        if (i >= 0)
        {

            if (preProcAnalyzeRule(i, &ruleList, &goalStack))
                continue;              // go to the next goal

        }

        else    {
            // if there is a question, ask a question
            if (questionIndices.find(goalStack.top()->returnType()) != questionIndices.end())
            {
                if (goalStack.size() <= 1){
                    algoStop = true;
                    continue;
                }
                stackedWidget->setCurrentIndex(questionIndices.value(goalStack.top()->returnType()));
                waitForUser = true;
                QTimer *timer = new QTimer(this);
                while (waitForUser)  {
                    QEventLoop loop;
                    timer->start(5);
                    connect(timer, SIGNAL(timeout()), &loop, SLOT(quit()));
                    loop.exec();
                }
                // assign required value to global var
                if (algoStop)
                    return;
                // delete attribute from stack
                int ruleNumber = goalStack.pop()->getNumber();
                if (ruleNumber >= 0)
                {
                    if (preProcAnalyzeRule(ruleNumber, &ruleList, &goalStack))
                        continue;              // go to the next goal

                }

            }   else    algoStop = true;
        }
    }
    stackedWidget->setCurrentIndex(questionIndices.value("success"));
    if (currentCharacter)  {

        QPixmap pic(QString::fromStdString(pathsAndNames.value(currentCharacter.value()).second));
        finalImage->setPixmap(pic.scaled(finalImage->width() < pic.width() ? finalImage->width() : pic.width(), finalImage->height(), Qt::KeepAspectRatio));
        string name = pathsAndNames.value(currentCharacter.value()).first;
        finalMessage->setText(QString::fromStdString("Congratulations! It's " + name + "!\nWanna try again?"));

    }
    else
    {
        finalImage->setPixmap(QPixmap("images/gollum_sad").scaled(finalImage->width(), finalImage->height(), Qt::KeepAspectRatio));
        finalMessage->setText(QString::fromStdString("Oh no... I cannot guess. Try again!"));
    }

}

MainWindow::~MainWindow()
{

}

void MainWindow::on_buttonNextRace_clicked()
{

    QString rac = comboBoxRace->currentText();
    if (rac == "Elf")   {
        currentRace = race::Elf;
        generateRaceActivities(race::Elf);
        generateRaceRealms(race::Elf);
    }
    else if (rac == "Valar")    {
        currentRace = race::Valar;
        generateRaceActivities(race::Valar);
        generateRaceRealms(race::Valar);
    }
    else if (rac == "Maiar")    {
        currentRace = race::Maiar;
        generateRaceActivities(race::Maiar);
        generateRaceRealms(race::Maiar);
    }
    else if (rac == "Man")  {
        currentRace = race::Man;
        generateRaceActivities(race::Man);
        generateRaceRealms(race::Man);
    }
    else if (rac == "Dwarf")    {
        currentRace = race::Dwarf;
        generateRaceActivities(race::Dwarf);
        generateRaceRealms(race::Dwarf);
    }
    else if (rac == "Hobbit")   {
        currentRace = race::Hobbit;
        generateRaceActivities(race::Hobbit);
        generateRaceRealms(race::Hobbit);
    }
    waitForUser = false;
}

void MainWindow::on_tryAgainButton_clicked()
{
    algoStop = false;
    currentRace = none;
    currentAlive = none;
    currentCharacter = none;
    currentPosNeg = none;
    curStatus = none;
    curRealm = none;
    curActivity = none;
    activityComboBox->clear();
    realmComboBox->clear();
    waitForUser = false;
    for (int i =0; i<ruleList.size(); ++i)
        ruleList[i]->setActual();
    goalStack.clear();

   // while(true)
        this->exec();
}

void MainWindow::on_nextAlive_clicked()
{
    if (this->yesNoButtonGroupAlive->checkedId()==-1)
        return;
//    else if (yesNoButtonGroupAlive->checkedButton() == undefinedAlive)
  //      currentAlive = isAlive::undefinedIsAlive;
    else if (yesNoButtonGroupAlive->checkedButton() == yesAlive)
        currentAlive = isAlive::alive;
    else if (yesNoButtonGroupAlive->checkedButton() == this->noNotAlive)
        currentAlive = isAlive::dead;
    else return;
    waitForUser = false;
}

void MainWindow::on_nextPosNeg_clicked()
{
    if (this->posNegButtonGroup->checkedId()==-1)
        return;
    else if (posNegButtonGroup->checkedButton() == posRadButton)
        currentPosNeg = posNeg::positive;
    else    if (posNegButtonGroup->checkedButton() == negRadButton)
         currentPosNeg = posNeg::negative;
    else return;
    waitForUser = false;
}

void MainWindow::on_activityNext_clicked()
{
    QString acti = activityComboBox->currentText();
    curActivity = activity::undefinedActivity;
    if (activities.find(acti) != activities.end())
        curActivity = activities.value(acti);
    waitForUser = false;

}

void MainWindow::on_nextStatus_clicked()
{
    if (this->statusButtonGroup->checkedId()==-1)
        return;
    if (this->statusButtonGroup->checkedButton() == this->kingButton)
        curStatus = status::king;
    else  if (this->statusButtonGroup->checkedButton() == this->regularButton)
        curStatus = status::regular;
    else  if (this->statusButtonGroup->checkedButton() == this->gwarriorButton)
        curStatus = status::greatWarrior;
    waitForUser = false;
}

void MainWindow::on_nextRealm_clicked()
{
    QString realmm = realmComboBox->currentText();
    curRealm = realm::undefinedRealm;
    if (realms.find(realmm) != realms.end())
        curRealm = realms.value(realmm);
    waitForUser = false;
}

void MainWindow::on_actionexit_triggered() {

    waitForUser = false;
    algoStop = true;

    this->close();
    qApp->quit();
}

void MainWindow::generateRaceActivities(race r) {

    activityComboBox->addItem("");
    switch (r)  {

       case Elf:
            activityComboBox->addItems(elvesActivities);
       break;
       case Hobbit:
            activityComboBox->addItems(hobbitsActivities);
       break;
       case Valar:
            activityComboBox->addItems(valarsActivities);
       break;

        case Maiar:
              activityComboBox->addItems(maiarsActivities);
        break;

        case Dwarf:
              activityComboBox->addItems(dwarvesActivities);
        break;

    case Man:
          activityComboBox->addItems(menActivities);
    break;

    default:
        break;

    }

}

void MainWindow::generateRaceRealms(race r) {

    realmComboBox->addItem("");
    switch (r)  {

       case Elf:
            realmComboBox->addItems(elfRealms);
       break;
       case Hobbit:
            realmComboBox->addItems(hobbitRealms);
       break;
       case Valar:
            realmComboBox->addItems(valarRealms);
       break;

        case Maiar:
              realmComboBox->addItems(maiarRealms);
        break;

        case Dwarf:
              realmComboBox->addItems(dwarfRealms);
        break;

    case Man:
          realmComboBox->addItems(manRealms);
    break;

    default:
        break;

    }

}

void MainWindow::closeEvent(QCloseEvent* e) {

    this->on_actionexit_triggered();

}

max_stars_repo_name: drozdms/Akinator-MiddleEarthCharacters

max_issues_repo_name: drozdms/Akinator-MiddleEarthCharacters

max_forks_repo_name: drozdms/Akinator-MiddleEarthCharacters


text:
    /**
  *********************************************************************
*************************************************************************
***
*** \file  GizmodTimer.cpp
*** \brief GizmodTimer class body
***
*****************************************
  *****************************************
    **/

/*

  Copyright (c) 2007, Tim Burrell
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

#include "GizmodTimer.hpp"
#include "GizmoEventLIRC.hpp"
#include "../libH/Debug.hpp"
#include "../libH/Exception.hpp"
#include "../libH/UtilTime.hpp"
#include <boost/shared_ptr.hpp>
#include <boost/thread/thread.hpp>

using namespace std;
using namespace boost;
using namespace H;
using namespace Gizmod;

////////////////////////////////////////////////////////////////////////////
// Type Defs
///////////////////////////////////////

/**
 * \def    TIMER_GRANULARITY
 * \brief  Amount of time to wait before checking for a cancel
**/
#define	TIMER_GRANULARITY	0.05f

////////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////

/**
 * \brief GizmodTimer Default Constructor
**/
GizmodTimer::GizmodTimer(float Seconds, boost::python::object TimerFunction) : mThreadProc(this) {
	mCancel = false;
	mRepeats = 0;
	mTotalRepeats = 0;
	mSleepTime = Seconds;
	mTimerFunction = TimerFunction;
}

/**
 * \brief GizmodTimer Init Constructor
**/
GizmodTimer::GizmodTimer(float Seconds, boost::python::object TimerFunction, boost::python::object UserData) : mThreadProc(this) {
	mCancel = false;
	mRepeats = 0;
	mTotalRepeats = 0;
	mSleepTime = Seconds;
	mTimerFunction = TimerFunction;
	setUserData(UserData);
}

/**
 * \brief GizmodTimer Init Constructor
**/
GizmodTimer::GizmodTimer(float Seconds, boost::python::object TimerFunction, int Repeats, boost::python::object UserData) : mThreadProc(this) {
	mCancel = false;
	mRepeats = 0;
	mTotalRepeats = Repeats;
	mSleepTime = Seconds;
	mTimerFunction = TimerFunction;
	setUserData(UserData);
}

/**
 * \brief GizmodTimer Destructor
**/
GizmodTimer::~GizmodTimer() {
}

////////////////////////////////////////////////////////////////////////////
// Class Body
///////////////////////////////////////

/**
 * \brief  Create a thread and start its execution
**/
void GizmodTimer::start() {
	cdbg4 << "GizmodTimer :: start" << endl;
	boost::thread thrd(mThreadProc);
}

/**
 * \brief  Create a thread and start its execution
**/
void GizmodTimer::cancel() {
	cdbg4 << "GizmodTimer :: cancel" << endl;
	mCancel = true;
}

/**
 * \brief  Reset the timer's time
**/
void GizmodTimer::resetTimer() {
	mTotalSlept = 0.0f;
}

/**
 * \brief  Set the Timer's user data
 * \param  UserData User defined data
**/
void GizmodTimer::setUserData(boost::python::object UserData) {
	mUserData = UserData;
}

/**
 * \brief  Set the time to sleep before firing timer event
 * \param  Seconds Time to sleep
**/
void GizmodTimer::setTime(float Seconds) {
	mSleepTime = Seconds;
}

/**
 * \brief  The ThreadProc
**/
void GizmodTimer::threadProc() {
	cdbg4 << "GizmodTimer :: Sleeping [" << mSleepTime << "s]" << endl;

	mRepeats = -1;
	do {
		// count the number of times we've repeated
		mRepeats ++;

		// sleep the desired amount of time
		mTotalSlept = 0.0f;
		mCancel = false;
		while ( (!mCancel) && (mTotalSlept < mSleepTime) ) {
			float SleepStep = TIMER_GRANULARITY;
			if (mTotalSlept + SleepStep > mSleepTime)
				SleepStep = mSleepTime - mTotalSlept;
			cdbg5 << "GizmodTimer :: Slept [" << mTotalSlept<< "s] of [" << mSleepTime << "s] -- Sleeping [" << SleepStep << "s]" << endl;
			UtilTime::sleep(SleepStep);
			mTotalSlept += SleepStep + 0.0001f;
		}

		if (mCancel) {
			cdbg5 << "GizmodTimer :: Cancel Called" << endl;
			return;
		}

		// call the python timer function
		cdbg4 << "GizmodTimer :: Calling Python timerFunction" << endl;
		mutex::scoped_lock lock(mMutexScript);
		mTimerFunction(mUserData);
		cdbg5 << "GizmodTimer :: Python timerFunction exited." << endl;
		cdbg5 << "GizmodTimer :: Repeating: " << mRepeats << " of " << mTotalRepeats << endl;
	} while ( (!mCancel) && ( (mTotalRepeats == -1) || (mRepeats <= mTotalRepeats) ) );
}

max_stars_repo_name: pauljeremyturner/gizmod

max_issues_repo_name: pauljeremyturner/gizmod

max_forks_repo_name: pauljeremyturner/gizmod


text:
// Software License for MTL
//
// Copyright (c) 2007 The Trustees of Indiana University.
//               2008 Dresden University of Technology and the Trustees of Indiana University.
//               2010 SimuNova UG (haftungsbeschränkt), www.simunova.com.
// All rights reserved.
// Authors: Peter Gottschling and Andrew Lumsdaine
//
// This file is part of the Matrix Template Library
//
// See also license.mtl.txt in the distribution.

#ifndef MTL_STD_CONCEPT_INCLUDE
#define MTL_STD_CONCEPT_INCLUDE

#ifdef __GXX_CONCEPTS__
#  include <concepts>
#else
// Use Joel de Guzman's return type deduction
#  include <boost/numeric/ublas/detail/returntype_deduction.hpp>
#  include <boost/mpl/at.hpp>
#  include <boost/numeric/linear_algebra/pseudo_concept.hpp>
#endif

// #include <boost/numeric/mtl/utility/is_what.hpp>         -> leads to cyclic inclusions
// #include <boost/numeric/mtl/operation/mult_result.hpp>

namespace mtl {

/**
 * \defgroup Concepts Concepts
 */
/*@{*/

    // Use Joel de Guzman's return type deduction
    // Adapted from uBLAS
    // Differences:
    //   - Separate types for all operations
    //   - result_type like in concept

    /// Concept Addable: Binary operation
    /** In concept-free compilations also used for return type deduction.
        If available use decltype instead of meta-programming. */
    template<class X, class Y>
    struct Addable
    {
#    ifdef MTL_WITH_AUTO
	/// Result of addition
	typedef decltype(X() + Y())   result_type;
#    else
      private:
        typedef boost::numeric::ublas::type_deduction_detail::base_result_of<X, Y> base_type;
        static typename base_type::x_type x;
        static typename base_type::y_type y;
        static const std::size_t size = sizeof (
                   boost::numeric::ublas::type_deduction_detail::test<
                        typename base_type::x_type
                      , typename base_type::y_type
		   >(x + y)
                );

        static const std::size_t index = (size / sizeof (char)) - 1;
        typedef typename boost::mpl::at_c<
    	typename base_type::types, index>::type id;
      public:
	/// Result of addition
        typedef typename id::type result_type;
#    endif
    };

    /// Concept Subtractable: Binary operation
    /** In concept-free compilations also used for return type deduction.
        If available use decltype instead of meta-programming. */
    template<class X, class Y>
    struct Subtractable
    {
#    ifdef MTL_WITH_AUTO
	/// Result of addition
	typedef decltype(X() - Y())   result_type;
#    else
      private:
        typedef boost::numeric::ublas::type_deduction_detail::base_result_of<X, Y> base_type;
        static typename base_type::x_type x;
        static typename base_type::y_type y;
        static const std::size_t size = sizeof (
                   boost::numeric::ublas::type_deduction_detail::test<
                        typename base_type::x_type
                      , typename base_type::y_type
		   >(x - y)
                );

        static const std::size_t index = (size / sizeof (char)) - 1;
        typedef typename boost::mpl::at_c<
    	typename base_type::types, index>::type id;
      public:
	/// Result of subtraction
        typedef typename id::type result_type;
#    endif
    };

    /// Concept Multiplicable: Binary operation
    /** In concept-free compilations also used for return type deduction.
        If available use decltype instead of meta-programming.  */
    template<class X, class Y>
    struct Multiplicable
    {
#    ifdef MTL_WITH_AUTO
	/// Result of multiplication
	typedef decltype(X() * Y())   result_type;
#    else
      private:
        typedef boost::numeric::ublas::type_deduction_detail::base_result_of<X, Y> base_type;
        static typename base_type::x_type x;
        static typename base_type::y_type y;
        static const std::size_t size = sizeof (
                   boost::numeric::ublas::type_deduction_detail::test<
                        typename base_type::x_type
                      , typename base_type::y_type
                    >(x * y)
                );

        static const std::size_t index = (size / sizeof (char)) - 1;
        typedef typename boost::mpl::at_c<
    	typename base_type::types, index>::type id;
      public:
	/// Result of multiplication
        typedef typename id::type result_type;
#    endif
    };

    /// Concept Divisible: Binary operation
    /** In concept-free compilations also used for return type deduction.
        If available use decltype instead of meta-programming.  */
    template<class X, class Y>
    struct Divisible
    {
#    ifdef MTL_WITH_AUTO
	/// Result of division
	typedef decltype(X() / Y())   result_type;
#    else
      private:
        typedef boost::numeric::ublas::type_deduction_detail::base_result_of<X, Y> base_type;
        static typename base_type::x_type x;
        static typename base_type::y_type y;
        static const std::size_t size = sizeof (
                   boost::numeric::ublas::type_deduction_detail::test<
                        typename base_type::x_type
                      , typename base_type::y_type
                    >(x / y)
                );

        static const std::size_t index = (size / sizeof (char)) - 1;
        typedef typename boost::mpl::at_c<
    	typename base_type::types, index>::type id;
      public:
	/// Result of division
        typedef typename id::type result_type;
#    endif
    };

    /// Concept UnaryFunctor
    /** With concept corresponds to std::Callable1 */
    template <typename T>
    struct UnaryFunctor
    {
	/// Result type of operator()
	typedef associated_type result_type;

	/// The unary  function
	result_type operator()(T);
    };

    /// Concept UnaryStaticFunctor
    /**
       \par Refinement of:
       - std::Callable1 < T >
    */
    template <typename T>
    struct UnaryStaticFunctor
      : public UnaryFunctor<T>
    {
	/// Result type of apply
	typedef associated_type result_type;

	/// The unary static function
	static result_type apply(T);

	/// The application operator behaves like apply. Exists for compatibility with UnaryFunctor
	result_type operator()(T);
    };

    /// Concept BinaryFunctor
    /** With concept corresponds to std::Callable2 */
    template <typename T, typename U>
    struct BinaryFunctor
    {
	/// Result type of operator()
	typedef associated_type result_type;

	/// The unary  function
	result_type operator()(T, U);
    };

    /// Concept BinaryStaticFunctor
    /**
       \par Refinement of:
       - BinaryFunctor <T, U>
    */
    template <typename T, typename U>
    struct BinaryStaticFunctor
	: public BinaryFunctor <T, U>
    {
	/// Result type of apply
	typedef associated_type result_type;

	/// The unary static function
	static result_type apply(T, U);

	/// The application operator behaves like apply. Exists for compatibility with BinaryFunctor
	result_type operator()(T, U);
    };

/*@}*/ // end of group Concepts

} // namespace mtl

#endif // MTL_STD_CONCEPT_INCLUDE


text:
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"

#include <numeric>
#include <Eigen/CXX11/Tensor>

using Eigen::Tensor;

template <int DataLayout>
static void test_trivial_reductions() {
  {
    Tensor<float, 0, DataLayout> tensor;
    tensor.setRandom();
    array<ptrdiff_t, 0> reduction_axis;

    Tensor<float, 0, DataLayout> result = tensor.sum(reduction_axis);
    VERIFY_IS_EQUAL(result(), tensor());
  }

  {
    Tensor<float, 1, DataLayout> tensor(7);
    tensor.setRandom();
    array<ptrdiff_t, 0> reduction_axis;

    Tensor<float, 1, DataLayout> result = tensor.sum(reduction_axis);
    VERIFY_IS_EQUAL(result.dimension(0), 7);
    for (int i = 0; i < 7; ++i) {
      VERIFY_IS_EQUAL(result(i), tensor(i));
    }
  }

  {
    Tensor<float, 2, DataLayout> tensor(2, 3);
    tensor.setRandom();
    array<ptrdiff_t, 0> reduction_axis;

    Tensor<float, 2, DataLayout> result = tensor.sum(reduction_axis);
    VERIFY_IS_EQUAL(result.dimension(0), 2);
    VERIFY_IS_EQUAL(result.dimension(1), 3);
    for (int i = 0; i < 2; ++i) {
      for (int j = 0; j < 3; ++j) {
        VERIFY_IS_EQUAL(result(i, j), tensor(i, j));
      }
    }
  }
}

template <int DataLayout>
static void test_simple_reductions() {
  Tensor<float, 4, DataLayout> tensor(2, 3, 5, 7);
  tensor.setRandom();
  array<ptrdiff_t, 2> reduction_axis2;
  reduction_axis2[0] = 1;
  reduction_axis2[1] = 3;

  Tensor<float, 2, DataLayout> result = tensor.sum(reduction_axis2);
  VERIFY_IS_EQUAL(result.dimension(0), 2);
  VERIFY_IS_EQUAL(result.dimension(1), 5);
  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 5; ++j) {
      float sum = 0.0f;
      for (int k = 0; k < 3; ++k) {
        for (int l = 0; l < 7; ++l) {
          sum += tensor(i, k, j, l);
        }
      }
      VERIFY_IS_APPROX(result(i, j), sum);
    }
  }

  {
    Tensor<float, 0, DataLayout> sum1 = tensor.sum();
    VERIFY_IS_EQUAL(sum1.rank(), 0);

    array<ptrdiff_t, 4> reduction_axis4;
    reduction_axis4[0] = 0;
    reduction_axis4[1] = 1;
    reduction_axis4[2] = 2;
    reduction_axis4[3] = 3;
    Tensor<float, 0, DataLayout> sum2 = tensor.sum(reduction_axis4);
    VERIFY_IS_EQUAL(sum2.rank(), 0);

    VERIFY_IS_APPROX(sum1(), sum2());
  }

  reduction_axis2[0] = 0;
  reduction_axis2[1] = 2;
  result = tensor.prod(reduction_axis2);
  VERIFY_IS_EQUAL(result.dimension(0), 3);
  VERIFY_IS_EQUAL(result.dimension(1), 7);
  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 7; ++j) {
      float prod = 1.0f;
      for (int k = 0; k < 2; ++k) {
        for (int l = 0; l < 5; ++l) {
          prod *= tensor(k, i, l, j);
        }
      }
      VERIFY_IS_APPROX(result(i, j), prod);
    }
  }

  {
    Tensor<float, 0, DataLayout> prod1 = tensor.prod();
    VERIFY_IS_EQUAL(prod1.rank(), 0);

    array<ptrdiff_t, 4> reduction_axis4;
    reduction_axis4[0] = 0;
    reduction_axis4[1] = 1;
    reduction_axis4[2] = 2;
    reduction_axis4[3] = 3;
    Tensor<float, 0, DataLayout> prod2 = tensor.prod(reduction_axis4);
    VERIFY_IS_EQUAL(prod2.rank(), 0);

    VERIFY_IS_APPROX(prod1(), prod2());
  }

  reduction_axis2[0] = 0;
  reduction_axis2[1] = 2;
  result = tensor.maximum(reduction_axis2);
  VERIFY_IS_EQUAL(result.dimension(0), 3);
  VERIFY_IS_EQUAL(result.dimension(1), 7);
  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 7; ++j) {
      float max_val = std::numeric_limits<float>::lowest();
      for (int k = 0; k < 2; ++k) {
        for (int l = 0; l < 5; ++l) {
          max_val = (std::max)(max_val, tensor(k, i, l, j));
        }
      }
      VERIFY_IS_APPROX(result(i, j), max_val);
    }
  }

  {
    Tensor<float, 0, DataLayout> max1 = tensor.maximum();
    VERIFY_IS_EQUAL(max1.rank(), 0);

    array<ptrdiff_t, 4> reduction_axis4;
    reduction_axis4[0] = 0;
    reduction_axis4[1] = 1;
    reduction_axis4[2] = 2;
    reduction_axis4[3] = 3;
    Tensor<float, 0, DataLayout> max2 = tensor.maximum(reduction_axis4);
    VERIFY_IS_EQUAL(max2.rank(), 0);

    VERIFY_IS_APPROX(max1(), max2());
  }

  reduction_axis2[0] = 0;
  reduction_axis2[1] = 1;
  result = tensor.minimum(reduction_axis2);
  VERIFY_IS_EQUAL(result.dimension(0), 5);
  VERIFY_IS_EQUAL(result.dimension(1), 7);
  for (int i = 0; i < 5; ++i) {
    for (int j = 0; j < 7; ++j) {
      float min_val = (std::numeric_limits<float>::max)();
      for (int k = 0; k < 2; ++k) {
        for (int l = 0; l < 3; ++l) {
          min_val = (std::min)(min_val, tensor(k, l, i, j));
        }
      }
      VERIFY_IS_APPROX(result(i, j), min_val);
    }
  }

  {
    Tensor<float, 0, DataLayout> min1 = tensor.minimum();
    VERIFY_IS_EQUAL(min1.rank(), 0);

    array<ptrdiff_t, 4> reduction_axis4;
    reduction_axis4[0] = 0;
    reduction_axis4[1] = 1;
    reduction_axis4[2] = 2;
    reduction_axis4[3] = 3;
    Tensor<float, 0, DataLayout> min2 = tensor.minimum(reduction_axis4);
    VERIFY_IS_EQUAL(min2.rank(), 0);

    VERIFY_IS_APPROX(min1(), min2());
  }

  reduction_axis2[0] = 0;
  reduction_axis2[1] = 1;
  result = tensor.mean(reduction_axis2);
  VERIFY_IS_EQUAL(result.dimension(0), 5);
  VERIFY_IS_EQUAL(result.dimension(1), 7);
  for (int i = 0; i < 5; ++i) {
    for (int j = 0; j < 7; ++j) {
      float sum = 0.0f;
      int count = 0;
      for (int k = 0; k < 2; ++k) {
        for (int l = 0; l < 3; ++l) {
          sum += tensor(k, l, i, j);
          ++count;
        }
      }
      VERIFY_IS_APPROX(result(i, j), sum / count);
    }
  }

  {
    Tensor<float, 0, DataLayout> mean1 = tensor.mean();
    VERIFY_IS_EQUAL(mean1.rank(), 0);

    array<ptrdiff_t, 4> reduction_axis4;
    reduction_axis4[0] = 0;
    reduction_axis4[1] = 1;
    reduction_axis4[2] = 2;
    reduction_axis4[3] = 3;
    Tensor<float, 0, DataLayout> mean2 = tensor.mean(reduction_axis4);
    VERIFY_IS_EQUAL(mean2.rank(), 0);

    VERIFY_IS_APPROX(mean1(), mean2());
  }

  {
    Tensor<int, 1> ints(10);
    std::iota(ints.data(), ints.data() + ints.dimension(0), 0);

    TensorFixedSize<bool, Sizes<> > all;
    all = ints.all();
    VERIFY(!all());
    all = (ints >= ints.constant(0)).all();
    VERIFY(all());

    TensorFixedSize<bool, Sizes<> > any;
    any = (ints > ints.constant(10)).any();
    VERIFY(!any());
    any = (ints < ints.constant(1)).any();
    VERIFY(any());
  }
}

template <int DataLayout>
static void test_reductions_in_expr() {
  Tensor<float, 4, DataLayout> tensor(2, 3, 5, 7);
  tensor.setRandom();
  array<ptrdiff_t, 2> reduction_axis2;
  reduction_axis2[0] = 1;
  reduction_axis2[1] = 3;

  Tensor<float, 2, DataLayout> result(2, 5);
  result = result.constant(1.0f) - tensor.sum(reduction_axis2);
  VERIFY_IS_EQUAL(result.dimension(0), 2);
  VERIFY_IS_EQUAL(result.dimension(1), 5);
  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 5; ++j) {
      float sum = 0.0f;
      for (int k = 0; k < 3; ++k) {
        for (int l = 0; l < 7; ++l) {
          sum += tensor(i, k, j, l);
        }
      }
      VERIFY_IS_APPROX(result(i, j), 1.0f - sum);
    }
  }
}

template <int DataLayout>
static void test_full_reductions() {
  Tensor<float, 2, DataLayout> tensor(2, 3);
  tensor.setRandom();
  array<ptrdiff_t, 2> reduction_axis;
  reduction_axis[0] = 0;
  reduction_axis[1] = 1;

  Tensor<float, 0, DataLayout> result = tensor.sum(reduction_axis);
  VERIFY_IS_EQUAL(result.rank(), 0);

  float sum = 0.0f;
  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 3; ++j) {
      sum += tensor(i, j);
    }
  }
  VERIFY_IS_APPROX(result(0), sum);

  result = tensor.square().sum(reduction_axis).sqrt();
  VERIFY_IS_EQUAL(result.rank(), 0);

  sum = 0.0f;
  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 3; ++j) {
      sum += tensor(i, j) * tensor(i, j);
    }
  }
  VERIFY_IS_APPROX(result(), sqrtf(sum));
}

struct UserReducer {
  static const bool PacketAccess = false;
  UserReducer(float offset) : offset_(offset) {}
  void reduce(const float val, float* accum) { *accum += val * val; }
  float initialize() const { return 0; }
  float finalize(const float accum) const { return 1.0f / (accum + offset_); }

 private:
  const float offset_;
};

template <int DataLayout>
static void test_user_defined_reductions() {
  Tensor<float, 2, DataLayout> tensor(5, 7);
  tensor.setRandom();
  array<ptrdiff_t, 1> reduction_axis;
  reduction_axis[0] = 1;

  UserReducer reducer(10.0f);
  Tensor<float, 1, DataLayout> result = tensor.reduce(reduction_axis, reducer);
  VERIFY_IS_EQUAL(result.dimension(0), 5);
  for (int i = 0; i < 5; ++i) {
    float expected = 10.0f;
    for (int j = 0; j < 7; ++j) {
      expected += tensor(i, j) * tensor(i, j);
    }
    expected = 1.0f / expected;
    VERIFY_IS_APPROX(result(i), expected);
  }
}

template <int DataLayout>
static void test_tensor_maps() {
  int inputs[2 * 3 * 5 * 7];
  TensorMap<Tensor<int, 4, DataLayout> > tensor_map(inputs, 2, 3, 5, 7);
  TensorMap<Tensor<const int, 4, DataLayout> > tensor_map_const(inputs, 2, 3, 5,
                                                                7);
  const TensorMap<Tensor<const int, 4, DataLayout> > tensor_map_const_const(
      inputs, 2, 3, 5, 7);

  tensor_map.setRandom();
  array<ptrdiff_t, 2> reduction_axis;
  reduction_axis[0] = 1;
  reduction_axis[1] = 3;

  Tensor<int, 2, DataLayout> result = tensor_map.sum(reduction_axis);
  Tensor<int, 2, DataLayout> result2 = tensor_map_const.sum(reduction_axis);
  Tensor<int, 2, DataLayout> result3 =
      tensor_map_const_const.sum(reduction_axis);

  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 5; ++j) {
      int sum = 0;
      for (int k = 0; k < 3; ++k) {
        for (int l = 0; l < 7; ++l) {
          sum += tensor_map(i, k, j, l);
        }
      }
      VERIFY_IS_EQUAL(result(i, j), sum);
      VERIFY_IS_EQUAL(result2(i, j), sum);
      VERIFY_IS_EQUAL(result3(i, j), sum);
    }
  }
}

template <int DataLayout>
static void test_static_dims() {
  Tensor<float, 4, DataLayout> in(72, 53, 97, 113);
  Tensor<float, 2, DataLayout> out(72, 97);
  in.setRandom();

#if !EIGEN_HAS_CONSTEXPR
  array<int, 2> reduction_axis;
  reduction_axis[0] = 1;
  reduction_axis[1] = 3;
#else
  Eigen::IndexList<Eigen::type2index<1>, Eigen::type2index<3> > reduction_axis;
#endif

  out = in.maximum(reduction_axis);

  for (int i = 0; i < 72; ++i) {
    for (int j = 0; j < 97; ++j) {
      float expected = -1e10f;
      for (int k = 0; k < 53; ++k) {
        for (int l = 0; l < 113; ++l) {
          expected = (std::max)(expected, in(i, k, j, l));
        }
      }
      VERIFY_IS_APPROX(out(i, j), expected);
    }
  }
}

template <int DataLayout>
static void test_innermost_last_dims() {
  Tensor<float, 4, DataLayout> in(72, 53, 97, 113);
  Tensor<float, 2, DataLayout> out(97, 113);
  in.setRandom();

// Reduce on the innermost dimensions.
#if !EIGEN_HAS_CONSTEXPR
  array<int, 2> reduction_axis;
  reduction_axis[0] = 0;
  reduction_axis[1] = 1;
#else
  // This triggers the use of packets for ColMajor.
  Eigen::IndexList<Eigen::type2index<0>, Eigen::type2index<1> > reduction_axis;
#endif

  out = in.maximum(reduction_axis);

  for (int i = 0; i < 97; ++i) {
    for (int j = 0; j < 113; ++j) {
      float expected = -1e10f;
      for (int k = 0; k < 53; ++k) {
        for (int l = 0; l < 72; ++l) {
          expected = (std::max)(expected, in(l, k, i, j));
        }
      }
      VERIFY_IS_APPROX(out(i, j), expected);
    }
  }
}

template <int DataLayout>
static void test_innermost_first_dims() {
  Tensor<float, 4, DataLayout> in(72, 53, 97, 113);
  Tensor<float, 2, DataLayout> out(72, 53);
  in.setRandom();

// Reduce on the innermost dimensions.
#if !EIGEN_HAS_CONSTEXPR
  array<int, 2> reduction_axis;
  reduction_axis[0] = 2;
  reduction_axis[1] = 3;
#else
  // This triggers the use of packets for RowMajor.
  Eigen::IndexList<Eigen::type2index<2>, Eigen::type2index<3>> reduction_axis;
#endif

  out = in.maximum(reduction_axis);

  for (int i = 0; i < 72; ++i) {
    for (int j = 0; j < 53; ++j) {
      float expected = -1e10f;
      for (int k = 0; k < 97; ++k) {
        for (int l = 0; l < 113; ++l) {
          expected = (std::max)(expected, in(i, j, k, l));
        }
      }
      VERIFY_IS_APPROX(out(i, j), expected);
    }
  }
}

template <int DataLayout>
static void test_reduce_middle_dims() {
  Tensor<float, 4, DataLayout> in(72, 53, 97, 113);
  Tensor<float, 2, DataLayout> out(72, 53);
  in.setRandom();

// Reduce on the innermost dimensions.
#if !EIGEN_HAS_CONSTEXPR
  array<int, 2> reduction_axis;
  reduction_axis[0] = 1;
  reduction_axis[1] = 2;
#else
  // This triggers the use of packets for RowMajor.
  Eigen::IndexList<Eigen::type2index<1>, Eigen::type2index<2>> reduction_axis;
#endif

  out = in.maximum(reduction_axis);

  for (int i = 0; i < 72; ++i) {
    for (int j = 0; j < 113; ++j) {
      float expected = -1e10f;
      for (int k = 0; k < 53; ++k) {
        for (int l = 0; l < 97; ++l) {
          expected = (std::max)(expected, in(i, k, l, j));
        }
      }
      VERIFY_IS_APPROX(out(i, j), expected);
    }
  }
}

void test_cxx11_tensor_reduction() {
  CALL_SUBTEST(test_trivial_reductions<ColMajor>());
  CALL_SUBTEST(test_trivial_reductions<RowMajor>());
  CALL_SUBTEST(test_simple_reductions<ColMajor>());
  CALL_SUBTEST(test_simple_reductions<RowMajor>());
  CALL_SUBTEST(test_reductions_in_expr<ColMajor>());
  CALL_SUBTEST(test_reductions_in_expr<RowMajor>());
  CALL_SUBTEST(test_full_reductions<ColMajor>());
  CALL_SUBTEST(test_full_reductions<RowMajor>());
  CALL_SUBTEST(test_user_defined_reductions<ColMajor>());
  CALL_SUBTEST(test_user_defined_reductions<RowMajor>());
  CALL_SUBTEST(test_tensor_maps<ColMajor>());
  CALL_SUBTEST(test_tensor_maps<RowMajor>());
  CALL_SUBTEST(test_static_dims<ColMajor>());
  CALL_SUBTEST(test_static_dims<RowMajor>());
  CALL_SUBTEST(test_innermost_last_dims<ColMajor>());
  CALL_SUBTEST(test_innermost_last_dims<RowMajor>());
  CALL_SUBTEST(test_innermost_first_dims<ColMajor>());
  CALL_SUBTEST(test_innermost_first_dims<RowMajor>());
  CALL_SUBTEST(test_reduce_middle_dims<ColMajor>());
  CALL_SUBTEST(test_reduce_middle_dims<RowMajor>());
}

max_stars_repo_name: RokKos/eol-cloth

max_issues_repo_name: RokKos/eol-cloth

max_forks_repo_name: RokKos/eol-cloth


text:
#include <cctbx/adptbx/hirshfeld.h>
#include <scitbx/boost_python/container_conversions.h>
#include <boost/python/class.hpp>
#include <boost/python/with_custodian_and_ward.hpp>
#include <boost/python/return_arg.hpp>
#include <boost/python/return_by_value.hpp>
#include <boost/python/return_value_policy.hpp>
#include <boost/python/make_function.hpp>

namespace cctbx { namespace adptbx { namespace boost_python {

  template <typename T>
  struct mean_square_displacement_wrapper
  {
    typedef mean_square_displacement<T> wt;

    static void wrap(char const *name) {
      using namespace boost::python;
      return_value_policy<return_by_value> rbv;
      class_<wt>(name, no_init)
        .def(init<uctbx::unit_cell const &,
                  scitbx::vec3<T> const &>
             ((arg("unit_cell"), arg("z")))
             [with_custodian_and_ward<1, 2>()])
        .def("__call__", &wt::operator(), return_self<>())
        .add_property("value", &wt::value)
        .add_property("grad_u",
                      make_function(&wt::grad_u, rbv))
        .add_property("grad_z",
                      make_function(&wt::grad_z, rbv))
        .add_property("grad_g",
                      make_function(&wt::grad_g, rbv))
        .add_property("grad_unit_cell_params",
                      make_function(&wt::grad_unit_cell_params, rbv))
        .add_property("well_defined", &wt::well_defined)
        ;
    }
  };

  template <typename T>
  struct relative_hirshfeld_difference_wrapper
  {
    typedef relative_hirshfeld_difference<T> wt;

    static void wrap(char const *name) {
      using namespace boost::python;
      using namespace scitbx::boost_python::container_conversions;
      return_value_policy<return_by_value> rbv;
      tuple_mapping_fixed_size<af::tiny<T, 2*(3+6)> >();
      class_<wt>(name, no_init)
      .def(init<uctbx::unit_cell const &,
                scitbx::vec3<T> const &,
                scitbx::sym_mat3<T> const &,
                scitbx::vec3<T> const &,
                scitbx::sym_mat3<T> const &,
                sgtbx::rt_mx const &>
           ((arg("unit_cell"),
             arg("site_1"), arg("u_star_1"),
             arg("site_2"), arg("u_star_2"), arg("rt_mx_2"))))
      .add_property("value", &wt::value)
      .add_property("grad_x1", make_function(&wt::grad_x1, rbv))
      .add_property("grad_x2", make_function(&wt::grad_x2, rbv))
      .add_property("grad_u1", make_function(&wt::grad_u1, rbv))
      .add_property("grad_u2", make_function(&wt::grad_u2, rbv))
      .add_property("grad_unit_cell_params",
                    make_function(&wt::grad_unit_cell_params, rbv))
      .def("esd", &wt::esd,
           (arg("crystallographic_variance_matrix_packed_u"),
            arg("index_x1"), arg("index_u1"), arg("index_x2"), arg("index_u2"),
            arg("a_b_c_alpha_beta_gamma_sigmas")))
      ;
    }
  };

  void wrap_hirshfeld() {
    mean_square_displacement_wrapper<double>
    ::wrap("mean_square_displacement");
    relative_hirshfeld_difference_wrapper<double>
    ::wrap("relative_hirshfeld_difference");
  }

}}}


text:
/*=============================================================================
  Copyright (c) 2010-2016 Bolero MURAKAMI
  https://github.com/bolero-MURAKAMI/Sprig

  Distributed under the Boost Software License, Version 1.0. (See accompanying
  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#ifndef SPRIG_UTILITY_CONTAINER_HPP
#define SPRIG_UTILITY_CONTAINER_HPP

#include <sprig/config/config.hpp>

#ifdef SPRIG_USING_PRAGMA_ONCE
#	pragma once
#endif	// #ifdef SPRIG_USING_PRAGMA_ONCE

#include <utility>
#include <functional>
#include <boost/utility/enable_if.hpp>
#include <sprig/type_traits/is_call_copy_param.hpp>

namespace sprig {
	//
	// push_back_
	//
	template<typename T1, typename T2 = typename T1::value_type, typename Dummy = void>
	struct push_back_ {};
	template<typename T1, typename T2>
	struct push_back_<T1, T2, typename boost::enable_if<sprig::is_call_copy_param<T2> >::type>
		: public std::binary_function<T1, T2, void>
	{
	private:
		typedef std::binary_function<T1, T2, void> binary_function_type;
	public:
		typedef typename binary_function_type::result_type result_type;
		typedef typename binary_function_type::first_argument_type first_argument_type;
		typedef typename binary_function_type::second_argument_type second_argument_type;
	public:
		result_type operator()(first_argument_type& lhs, second_argument_type rhs) const {
			lhs.push_back(rhs);
		}
	};
	template<typename T1, typename T2>
	struct push_back_<T1, T2, typename boost::disable_if<sprig::is_call_copy_param<T2> >::type>
		: public std::binary_function<T1, T2, void>
	{
	private:
		typedef std::binary_function<T1, T2, void> binary_function_type;
	public:
		typedef typename binary_function_type::result_type result_type;
		typedef typename binary_function_type::first_argument_type first_argument_type;
		typedef typename binary_function_type::second_argument_type second_argument_type;
	public:
		result_type operator()(first_argument_type& lhs, second_argument_type const& rhs) const {
			lhs.push_back(rhs);
		}
	};
	//
	// any_push_back_
	//
	struct any_push_back_ {
		template<typename T1, typename T2>
		typename boost::enable_if<sprig::is_call_copy_param<T2> >::type
		operator()(T1& lhs, T2 rhs) const {
			lhs.push_back(rhs);
		}
		template<typename T1, typename T2>
		typename boost::disable_if<sprig::is_call_copy_param<T2> >::type
		operator()(T1& lhs, T2 const& rhs) const {
			lhs.push_back(rhs);
		}
	};
	//
	// push_front_
	//
	template<typename T1, typename T2 = typename T1::value_type, typename Dummy = void>
	struct push_front_ {};
	template<typename T1, typename T2>
	struct push_front_<T1, T2, typename boost::enable_if<sprig::is_call_copy_param<T2> >::type>
		: public std::binary_function<T1, T2, void>
	{
	private:
		typedef std::binary_function<T1, T2, void> binary_function_type;
	public:
		typedef typename binary_function_type::result_type result_type;
		typedef typename binary_function_type::first_argument_type first_argument_type;
		typedef typename binary_function_type::second_argument_type second_argument_type;
	public:
		result_type operator()(first_argument_type& lhs, second_argument_type rhs) const {
			lhs.push_front(rhs);
		}
	};
	template<typename T1, typename T2>
	struct push_front_<T1, T2, typename boost::disable_if<sprig::is_call_copy_param<T2> >::type>
		: public std::binary_function<T1, T2, void>
	{
	private:
		typedef std::binary_function<T1, T2, void> binary_function_type;
	public:
		typedef typename binary_function_type::result_type result_type;
		typedef typename binary_function_type::first_argument_type first_argument_type;
		typedef typename binary_function_type::second_argument_type second_argument_type;
	public:
		result_type operator()(first_argument_type& lhs, second_argument_type const& rhs) const {
			lhs.push_front(rhs);
		}
	};
	//
	// any_push_front_
	//
	struct any_push_front_ {
		template<typename T1, typename T2>
		typename boost::enable_if<sprig::is_call_copy_param<T2> >::type
		operator()(T1& lhs, T2 rhs) const {
			lhs.push_front(rhs);
		}
		template<typename T1, typename T2>
		typename boost::disable_if<sprig::is_call_copy_param<T2> >::type
		operator()(T1& lhs, T2 const& rhs) const {
			lhs.push_front(rhs);
		}
	};
}	// namespace sprig

#endif	// #ifndef SPRIG_UTILITY_CONTAINER_HPP

max_stars_repo_name: bolero-MURAKAMI/Sprig

max_issues_repo_name: bolero-MURAKAMI/Sprig

max_forks_repo_name: bolero-MURAKAMI/Sprig


text:
/******************************************************************************\
 *                                                                            *
 *           ____                  _        _        _                        *
 *          | __ )  ___   ___  ___| |_     / \   ___| |_ ___  _ __            *
 *          |  _ \ / _ \ / _ \/ __| __|   / _ \ / __| __/ _ \| '__|           *
 *          | |_) | (_) | (_) \__ \ |_ _ / ___ \ (__| || (_) | |              *
 *          |____/ \___/ \___/|___/\__(_)_/   \_\___|\__\___/|_|              *
 *                                                                            *
 *                                                                            *
 *                                                                            *
 * Copyright (C) 2011 - 2014                                                  *
 * Dominik Charousset <dominik.charousset@haw-hamburg.de>                     *
 *                                                                            *
 * Distributed under the Boost Software License, Version 1.0. See             *
 * accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt  *
\******************************************************************************/

#include <cstdint>
#include <stdexcept>

#include "boost/actor/config.hpp"

#include "boost/actor/detail/cs_thread.hpp"

namespace {

typedef void* vptr;
typedef void (*cst_fun)(vptr);

// Boost's coroutine minimal stack size is pretty small
// and easily causes stack overflows when using libcppa
// in debug mode or with logging
#if defined(BOOST_ACTOR_DEBUG_MODE) || defined(BOOST_ACTOR_LOG_LEVEL)
constexpr size_t stack_multiplier = 4;
#else
constexpr size_t stack_multiplier = 2;
#endif

} // namespace <anonmyous>

#if defined(BOOST_ACTOR_DISABLE_CONTEXT_SWITCHING) || defined(BOOST_ACTOR_STANDALONE_BUILD)

namespace boost {
namespace actor {
namespace detail {

cs_thread::cs_thread() : m_impl(nullptr) { }

cs_thread::cs_thread(cst_fun, vptr) : m_impl(nullptr) { }

cs_thread::~cs_thread() { }

void cs_thread::swap(cs_thread&, cs_thread&) {
    throw std::logic_error("libcppa was compiled using "
                           "BOOST_ACTOR_DISABLE_CONTEXT_SWITCHING");
}

const bool cs_thread::is_disabled_feature = true;

} } // namespace actor
} // namespace boost::detail

#else // BOOST_ACTOR_DISABLE_CONTEXT_SWITCHING  || BOOST_ACTOR_STANDALONE_BUILD

// optional valgrind include
#ifdef BOOST_ACTOR_ANNOTATE_VALGRIND
#   include <valgrind/valgrind.h>
#endif

BOOST_ACTOR_PUSH_WARNINGS
// boost includes
#include <boost/version.hpp>
#include <boost/context/all.hpp>
#include <boost/coroutine/all.hpp>
BOOST_ACTOR_POP_WARNINGS

namespace boost {
namespace actor {
namespace detail {

void cst_trampoline(intptr_t iptr);

namespace {

#ifdef BOOST_ACTOR_ANNOTATE_VALGRIND
    typedef int vg_member;
    inline void vg_register(vg_member& stack_id, vptr ptr1, vptr ptr2) {
        stack_id = VALGRIND_STACK_REGISTER(ptr1, ptr2);
    }
    inline void vg_deregister(vg_member stack_id) {
        VALGRIND_STACK_DEREGISTER(stack_id);
    }
#else
    struct vg_member { };
    inline void vg_register(vg_member&, vptr, vptr) {/*NOP*/}
    inline void vg_deregister(const vg_member&) { }
#endif

/* Interface dependent on Boost version:
 *
 * === namespace aliases ===
 *
 * ctxn:
 *     namespace of context library; alias for boost::context or boost::ctx
 *
 * === types ===
 *
 * context:
 *     execution context; either fcontext_t or fcontext_t*
 *
 * converted_context:
 *     additional member for converted_cs_thread;
 *     needed if context is defined as fcontext_t*
 *
 * ctx_stack_info:
 *     result of new_stack(), needed to delete stack properly in some versions
 *
 * stack_allocator:
 *     a stack allocator for cs_thread instances
 *
 * === functions ===
 *
 * void init_converted_context(converted_context&, context&)
 *
 * void ctx_switch(context&, context&, cst_impl*):
 *     implements the context switching from one cs_thread to another
 *
 * ctx_stack_info new_stack(context&, stack_allocator&, vg_member&):
 *     allocates a stack, prepares execution of context
 *     and (optionally) registers the new stack to valgrind
 *
 * void del_stack(stack_allocator&, ctx_stack_info, vg_member&):
 *     destroys the stack and (optionally) deregisters it from valgrind
 */
#if BOOST_VERSION >= 105400
    // === namespace aliases ===
    namespace ctxn = boost::context;
    // === types ===
    typedef ctxn::fcontext_t*                  context;
    typedef ctxn::fcontext_t                   converted_context;
    typedef boost::coroutines::stack_context   ctx_stack_info;
    typedef boost::coroutines::stack_allocator stack_allocator;
    // === functions ===
    inline void init_converted_context(converted_context& cctx, context& ctx) {
        ctx = &cctx;
    }
    inline void ctx_switch(context& from, context& to, cst_impl* ptr) {
        ctxn::jump_fcontext(from, to, (intptr_t) ptr);
    }
    ctx_stack_info new_stack(context& ctx,
                                     stack_allocator& alloc,
                                     vg_member& vgm) {
        auto mss = static_cast<intptr_t>(  stack_allocator::minimum_stacksize()
                                         * stack_multiplier);
        ctx_stack_info sinf;
        alloc.allocate(sinf, static_cast<size_t>(mss));
        ctx = ctxn::make_fcontext(sinf.sp, sinf.size, cst_trampoline);
        vg_register(vgm,
                    ctx->fc_stack.sp,
                    reinterpret_cast<vptr>(
                        reinterpret_cast<intptr_t>(ctx->fc_stack.sp) - mss));
        return sinf;
    }
    inline void del_stack(stack_allocator& alloc,
                          ctx_stack_info sctx,
                          vg_member& vgm) {
        vg_deregister(vgm);
        alloc.deallocate(sctx);
    }
#else
#   error libcppa context switching requires Boost in version >= 1.54
#endif

} // namespace <anonymous>

// base class for cs_thread pimpls
struct cst_impl {

    virtual ~cst_impl();

    virtual void run() = 0;

    inline void swap(cst_impl* to) {
        ctx_switch(m_ctx, to->m_ctx, to);
    }

    context m_ctx;

};

cst_impl::~cst_impl() { }

namespace {

// a cs_thread representing a thread ('converts' the thread to a cs_thread)
struct converted_cs_thread : cst_impl {

    converted_cs_thread() {
        init_converted_context(m_converted, m_ctx);
    }

    void run() override {
        throw std::logic_error("converted_cs_thread::run called");
    }

    converted_context m_converted;

};

// a cs_thread executing a function
struct fun_cs_thread : cst_impl {

    fun_cs_thread(cst_fun fun, vptr arg) : m_fun(fun), m_arg(arg) {
        m_stack_info = new_stack(m_ctx, m_alloc, m_vgm);
    }

    ~fun_cs_thread() {
        del_stack(m_alloc, m_stack_info, m_vgm);
    }

    void run() override {
        m_fun(m_arg);
    }

    cst_fun         m_fun;        // thread function
    vptr            m_arg;        // argument for thread function invocation
    stack_allocator m_alloc;      // allocates memory for our stack
    vg_member       m_vgm;        // valgrind meta informations (optionally)
    ctx_stack_info  m_stack_info; // needed to delete stack in destructor

};

} // namespace <anonymous>

void cst_trampoline(intptr_t iptr) {
    auto ptr = (cst_impl*) iptr;
    ptr->run();
}

cs_thread::cs_thread() : m_impl(new converted_cs_thread) { }

cs_thread::cs_thread(cst_fun f, vptr x) : m_impl(new fun_cs_thread(f, x)) { }

void cs_thread::swap(cs_thread& from, cs_thread& to) {
    from.m_impl->swap(to.m_impl);
}

cs_thread::~cs_thread() {
    delete m_impl;
}

const bool cs_thread::is_disabled_feature = false;

} } // namespace actor
} // namespace boost::detail

#endif // BOOST_ACTOR_DISABLE_CONTEXT_SWITCHING


text:
/*
 * naive.hpp
 *
 *  Created on: Apr 30, 2011
 *      Author: stewie
 */

#ifndef NAIVE_HPP_
#define NAIVE_HPP_

#include <utility>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>

#include "../../core/BooleanDynamics.hpp"
#include "../../core/Attractor.hpp"

namespace bn {

namespace cycle_finder {

typedef boost::multi_index::multi_index_container<State,
		boost::multi_index::indexed_by<boost::multi_index::sequenced<>,
				boost::multi_index::hashed_unique<boost::multi_index::identity<
						State>, BitsetHasher> > > StateSet;

Attractor naive(BooleanDynamics& net, State s);

template<class Terminator> Attractor naive(BooleanDynamics& net, State s,
		Terminator t) {
	StateSet stateSet;
	for (size_t iter = 0; t(iter); net.update(s), ++iter) {
		const std::pair<StateSet::const_iterator, bool> p = stateSet.push_back(
				s);
		if (!p.second)
			return Attractor(std::make_pair(p.first, stateSet.end()));
	}
	return EMPTY_ATTRACTOR;
}

} // namespace cycle_finder

} // namespace bn

#endif /* NAIVE_HPP_ */

max_stars_repo_name: Markfrancisrogers/BooleanNetwork

max_issues_repo_name: Markfrancisrogers/BooleanNetwork

max_forks_repo_name: Markfrancisrogers/BooleanNetwork