void svm_problem::save(std::ostream &outStream) const

/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 *
 * http://example.com
 * ---------------------------------------------------------------------
 */

/*
All rights reserved.

*/

#include <cstdio>
#include <sstream>

#include <nupic/algorithms/Svm.hpp>

namespace nupic {
namespace algorithms {
namespace svm {

using namespace std;

void svm_parameter::print() const {
  std::cout << "kernel = " << kernel << std::endl
            << "probability = " << probability << std::endl
            << "gamma = " << gamma << std::endl
            << "C = " << C << std::endl
            << "eps = " << eps << std::endl
            << "cache_size = " << cache_size << std::endl
            << "shrinking = " << shrinking << std::endl;
}

int svm_parameter::persistent_size() const {
  stringstream b;
  b << kernel << ' ' << probability << ' ' << gamma << ' ' << C << ' ' << eps
    << ' ' << cache_size << ' ' << shrinking << ' ' << weight_label << ' '
    << weight << ' ';

  return b.str().size();
}

void svm_parameter::save(std::ostream &outStream) const {
  outStream << kernel << ' ' << probability << ' ' << gamma << ' ' << C << ' '
            << eps << ' ' << cache_size << ' ' << shrinking << ' '
            << weight_label << ' ' << weight << ' ';
}

void svm_parameter::load(std::istream &inStream) {
  inStream >> kernel >> probability >> gamma >> C >> eps >> cache_size >>
      shrinking >> weight_label >> weight;
}

void svm_parameter::read(SvmParameterProto::Reader &proto) {
  kernel = proto.getKernel();
  probability = proto.getProbability();
  gamma = proto.getGamma();
  C = proto.getC();
  eps = proto.getEps();
  cache_size = proto.getCacheSize();
  shrinking = proto.getShrinking();

  auto weightList = proto.getWeight();
  size_t size = weightList.size();
  weight.resize(size);
  for (size_t i = 0; i < size; i++) {
    weight[i] = weightList[i];
  }

  auto labelList = proto.getWeightLabel();
  size = labelList.size();
  weight_label.resize(size);
  for (size_t i = 0; i < size; i++) {
    weight_label[i] = labelList[i];
  }
}

void svm_parameter::write(SvmParameterProto::Builder &proto) const {
  proto.setKernel(kernel);
  proto.setProbability(probability);
  proto.setGamma(gamma);
  proto.setC(C);
  proto.setEps(eps);
  proto.setCacheSize(cache_size);
  proto.setShrinking(shrinking);

  size_t size = weight.size();
  auto weightList = proto.initWeight(size);
  for (size_t i = 0; i < size; i++) {
    weightList.set(i, weight[i]);
  }

  size = weight_label.size();
  auto labelList = proto.initWeightLabel(size);
  for (size_t i = 0; i < size; i++) {
    labelList.set(i, weight_label[i]);
  }
}

int svm_problem::persistent_size() const {
  stringstream b;

  b << size() << " " << n_dims() << " ";

  return b.str().size() + y_.size() * sizeof(label_type) +
         size() * n_dims() * sizeof(feature_type) + 1;
}

{
  outStream << size() << " " << n_dims() << " ";

  nupic::binary_save(outStream, y_);

  for (int i = 0; i < size(); ++i)
    nupic::binary_save(outStream, x_[i], x_[i] + n_dims());
  outStream << " ";
}

void svm_problem::load(std::istream &inStream) {
  int s = 0;
  inStream >> s >> n_dims_;

  if (recover_)
    for (size_t i = 0; i != x_.size(); ++i)
      delete[] x_[i];

  y_.resize(s, 0);
  x_.resize(s, nullptr);

  inStream.ignore(1);
  nupic::binary_load(inStream, y_);

  for (int i = 0; i < size(); ++i) {
#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
    x_[i] = (float *)_aligned_malloc(4 * n_dims(), 16);
#else
    x_[i] = new feature_type[n_dims()];
#endif

    std::fill(x_[i], x_[i] + n_dims(), (float)0);
    nupic::binary_load(inStream, x_[i], x_[i] + n_dims());
  }
}

void svm_problem::read(SvmProblemProto::Reader &proto) {
  recover_ = proto.getRecover();
  n_dims_ = proto.getNDims();

  auto yList = proto.getY();
  size_t size = yList.size();
  y_.resize(size);
  for (size_t i = 0; i < size; i++) {
    y_[i] = yList[i];
  }

  for (auto &elem : x_)
    delete[] elem;

  x_.clear();
  for (auto list : proto.getX()) {
    size_t size = list.size();
    float *values = new float[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    x_.push_back(values);
  }
}

void svm_problem::write(SvmProblemProto::Builder &proto) const {
  proto.setRecover(recover_);
  proto.setNDims(n_dims_);

  size_t size = y_.size();
  auto yList = proto.initY(size);
  for (size_t i = 0; i < size; i++) {
    yList.set(i, y_[i]);
  }

  size = x_.size();
  auto xList = proto.initX(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = xList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, x_[i][j]);
    }
  }
}

int svm_problem01::persistent_size() const {
  stringstream b;
  b << size() << " " << n_dims() << " " << threshold_ << " ";
  int n = b.str().size();

  n += y_.size() * sizeof(float);
  n += nnz_.size() * sizeof(int);

  for (int i = 0; i != size(); ++i)
    n += nnz_[i] * sizeof(feature_type);

  return n + 1;
}

void svm_problem01::save(std::ostream &outStream) const {
  outStream << size() << " " << n_dims() << " " << threshold_ << " ";

  nupic::binary_save(outStream, y_);
  nupic::binary_save(outStream, nnz_);

  for (int i = 0; i < size(); ++i)
    nupic::binary_save(outStream, x_[i], x_[i] + nnz_[i]);
  outStream << " ";
}

void svm_problem01::load(std::istream &inStream) {
  int s = 0;
  inStream >> s >> n_dims_ >> threshold_;

  if (recover_)
    for (auto &elem : x_)
      delete[] elem;

  y_.resize(s, 0);
  nnz_.resize(s, 0);
  x_.resize(s, nullptr);

  inStream.ignore(1);
  nupic::binary_load(inStream, y_);
  nupic::binary_load(inStream, nnz_);

  for (int i = 0; i < s; ++i) {
    x_[i] = new feature_type[nnz_[i]];
    nupic::binary_load(inStream, x_[i], x_[i] + nnz_[i]);
  }
}

void svm_problem01::read(SvmProblem01Proto::Reader &proto) {
  recover_ = proto.getRecover();
  n_dims_ = proto.getNDims();
  threshold_ = proto.getThreshold();

  auto yList = proto.getY();
  size_t size = yList.size();
  y_.resize(size);
  for (size_t i = 0; i < size; i++) {
    y_[i] = yList[i];
  }

  auto nnzList = proto.getNnz();
  nnz_.resize(nnzList.size());
  size = nnzList.size();
  nnz_.resize(size);
  for (size_t i = 0; i < size; i++) {
    nnz_[i] = nnzList[i];
  }

  for (auto &elem : x_)
    delete[] elem;

  x_.clear();
  for (auto list : proto.getX()) {
    size_t size = list.size();
    int *values = new int[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    x_.push_back(values);
  }
}

void svm_problem01::write(SvmProblem01Proto::Builder &proto) const {
  proto.setRecover(recover_);
  proto.setNDims(n_dims_);
  proto.setThreshold(threshold_);

  size_t size = y_.size();
  auto yList = proto.initY(size);
  for (size_t i = 0; i < size; i++) {
    yList.set(i, y_[i]);
  }

  size = nnz_.size();
  auto nnzList = proto.initNnz(size);
  for (size_t i = 0; i < size; i++) {
    nnzList.set(i, nnz_[i]);
  }

  size = x_.size();
  auto xList = proto.initX(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = xList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, x_[i][j]);
    }
  }
}

svm_model::~svm_model() {
  // in all cases, ownership of the mem for the sv is with svm_model

  if (sv_mem == nullptr) {
    for (size_t i = 0; i != sv.size(); ++i)

#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
      _aligned_free(sv[i]);
#else
      delete[] sv[i];
#endif

  } else {
#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
    _aligned_free(sv_mem);
#else
    delete[] sv_mem;
#endif

    sv_mem = nullptr;
    sv.clear();
  }

  for (size_t i = 0; i != sv_coef.size(); ++i)
    delete[] sv_coef[i];
}

void svm_model::print() const {
  std::cout << "n classes = " << n_class() << " n sv = " << size()
            << " n dims = " << n_dims() << std::endl;

  std::cout << "Support vectors: " << std::endl;
  for (size_t i = 0; i != sv.size(); ++i) {
    for (int j = 0; j != n_dims(); ++j)
      std::cout << sv[i][j] << " ";
    std::cout << std::endl;
  }

  std::cout << "Support vector coefficients: " << std::endl;
  for (size_t i = 0; i != sv_coef.size(); ++i) {
    for (int j = 0; j != size(); ++j)
      std::cout << sv_coef[i][j] << " ";
    std::cout << std::endl;
  }

  std::cout << "Rho: " << std::endl;
  for (size_t i = 0; i != rho.size(); ++i)
    std::cout << rho[i] << " ";
  std::cout << std::endl;

  if (!probA.empty()) {
    std::cout << "Probabilities A: " << std::endl;
    for (size_t i = 0; i != probA.size(); ++i)
      std::cout << probA[i] << " ";
    std::cout << std::endl;

    std::cout << "Probabilities B: " << std::endl;
    for (size_t i = 0; i != probB.size(); ++i)
      std::cout << probB[i] << " ";
    std::cout << std::endl;
  }
}

int svm_model::persistent_size() const {
  stringstream b;
  b << n_class() << " " << size() << " " << n_dims() << " ";

  int n = b.str().size();

  n += sv.size() * n_dims() * sizeof(float) + 1;

  {
    stringstream b2;
    for (auto &elem : sv_coef) {
      for (int j = 0; j < size(); ++j)
        b2 << elem[j] << " ";
    }
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << rho << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << label << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << n_sv << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << probA << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << probB << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << w << " ";
    n += b2.str().size();
  }

  return n;
}

void svm_model::save(std::ostream &outStream) const {
  outStream << n_class() << " " << size() << " " << n_dims() << " ";

  for (auto &elem : sv)
    nupic::binary_save(outStream, elem, elem + n_dims());
  outStream << " ";

  for (auto &elem : sv_coef)
    for (int j = 0; j < size(); ++j)
      outStream << elem[j] << " ";

  outStream << rho << ' ' << label << ' ' << n_sv << ' ' << probA << ' '
            << probB << ' ' << w << ' ';
}

void svm_model::load(std::istream &inStream) {
  int n_class = 0, l = 0;
  inStream >> n_class >> l >> n_dims_;

  if (sv_mem == nullptr) {
    for (auto &elem : sv)
      delete[] elem;

  } else {
    delete[] sv_mem;
    sv_mem = nullptr;
  }

#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
  sv_mem = (float *)_aligned_malloc(4 * l * n_dims(), 16);
#else
  sv_mem = new float[l * n_dims()];
#endif

  std::fill(sv_mem, sv_mem + l * n_dims(), (float)0);

  sv.resize(l, nullptr);
  inStream.ignore(1);
  for (int i = 0; i < l; ++i) {
    sv[i] = sv_mem + i * n_dims();
    nupic::binary_load(inStream, sv[i], sv[i] + n_dims());
  }

  for (auto &elem : sv_coef)
    delete[] elem;

  sv_coef.resize(n_class - 1, nullptr);
  for (int i = 0; i < n_class - 1; ++i) {
    sv_coef[i] = new float[l];
    for (int j = 0; j < l; ++j)
      inStream >> sv_coef[i][j];
  }

  inStream >> rho >> label >> n_sv >> probA >> probB >> w;
}

void svm_model::read(SvmModelProto::Reader &proto) {
  n_dims_ = proto.getNDims();

  if (sv_mem == nullptr) {
    for (auto &elem : sv)
      delete[] elem;
  } else {
    delete[] sv_mem;
    sv_mem = nullptr;
  }
  sv.clear();

  for (auto list : proto.getSv()) {
    size_t size = list.size();
    float *values = new float[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    sv.push_back(values);
  }

  for (auto &elem : sv_coef)
    delete[] elem;
  sv_coef.clear();

  for (auto list : proto.getSvCoef()) {
    size_t size = list.size();
    float *values = new float[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    sv_coef.push_back(values);
  }

  auto wList = proto.getW();
  size_t size = wList.size();
  w.resize(size);
  for (size_t i = 0; i < size; i++) {
    auto values = wList[i];
    size_t len = values.size();
    w[i].resize(len);
    for (size_t j = 0; j < len; j++) {
      w[i][j] = values[j];
    }
  }

  auto rhoList = proto.getRho();
  size = rhoList.size();
  rho.resize(size);
  for (size_t i = 0; i < size; i++) {
    rho[i] = rhoList[i];
  }

  auto probAList = proto.getProbA();
  size = probAList.size();
  probA.resize(size);
  for (size_t i = 0; i < size; i++) {
    probA[i] = probAList[i];
  }

  auto probBList = proto.getProbB();
  size = probBList.size();
  probB.resize(size);
  for (size_t i = 0; i < size; i++) {
    probB[i] = probBList[i];
  }

  auto labelList = proto.getLabel();
  size = labelList.size();
  label.resize(size);
  for (size_t i = 0; i < size; i++) {
    label[i] = labelList[i];
  }

  auto nsvList = proto.getNSv();
  size = nsvList.size();
  n_sv.resize(size);
  for (size_t i = 0; i < size; i++) {
    n_sv[i] = nsvList[i];
  }
}

void svm_model::write(SvmModelProto::Builder &proto) const {

  proto.setNDims(n_dims_);

  size_t size = sv.size();
  auto svList = proto.initSv(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = svList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, sv[i][j]);
    }
  }

  size = sv_coef.size();
  auto svCoefList = proto.initSvCoef(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = svCoefList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, sv_coef[i][j]);
    }
  }

  size = rho.size();
  auto rhoList = proto.initRho(size);
  for (size_t i = 0; i < size; i++) {
    rhoList.set(i, rho[i]);
  }

  size = label.size();
  auto labelList = proto.initLabel(size);
  for (size_t i = 0; i < size; i++) {
    labelList.set(i, label[i]);
  }

  size = n_sv.size();
  auto nsvList = proto.initNSv(size);
  for (size_t i = 0; i < size; i++) {
    nsvList.set(i, n_sv[i]);
  }

  size = probA.size();
  auto probAList = proto.initProbA(size);
  for (size_t i = 0; i < size; i++) {
    probAList.set(i, probA[i]);
  }

  size = probB.size();
  auto probBList = proto.initProbB(size);
  for (size_t i = 0; i < size; i++) {
    probBList.set(i, probB[i]);
  }

  size = w.size();
  auto wList = proto.initW(size);
  for (size_t i = 0; i < size; i++) {
    size_t len = w[i].size();
    auto dims = wList.init(i, len);
    for (size_t j = 0; j < len; j++) {
      dims.set(j, w[i][j]);
    }
  }
}

void svm_dense::write(SvmDenseProto::Builder &proto) const {
  auto paramProto = proto.getParam();
  svm_.param_.write(paramProto);

  if (svm_.model_) {
    auto modelProto = proto.getModel();
    svm_.model_->write(modelProto);
  }
  if (svm_.problem_) {
    auto problemProto = proto.getProblem();
    svm_.problem_->write(problemProto);
  }
}

void svm_dense::read(SvmDenseProto::Reader &proto) {
  auto paramProto = proto.getParam();
  svm_.param_.read(paramProto);

  if (svm_.model_) {
    delete svm_.model_;
    svm_.model_ = nullptr;
  }
  if (proto.hasModel()) {
    auto modelProto = proto.getModel();
    svm_.model_ = new svm_model;
    svm_.model_->read(modelProto);
  }
  if (svm_.problem_) {
    delete svm_.problem_;
    svm_.problem_ = nullptr;
  }
  if (proto.hasProblem()) {
    auto problemProto = proto.getProblem();
    svm_.problem_ = new svm_problem(1, false);
    svm_.problem_->read(problemProto);
  }
}

void svm_01::write(Svm01Proto::Builder &proto) const {
  auto paramProto = proto.getParam();
  svm_.param_.write(paramProto);

  if (svm_.model_) {
    auto modelProto = proto.getModel();
    svm_.model_->write(modelProto);
  }
  if (svm_.problem_) {
    auto problemProto = proto.getProblem();
    svm_.problem_->write(problemProto);
  }
}

void svm_01::read(Svm01Proto::Reader &proto) {
  auto paramProto = proto.getParam();
  svm_.param_.read(paramProto);

  if (svm_.model_) {
    delete svm_.model_;
    svm_.model_ = nullptr;
  }
  if (proto.hasModel()) {
    auto modelProto = proto.getModel();
    svm_.model_ = new svm_model;
    svm_.model_->read(modelProto);
  }
  if (svm_.problem_) {
    delete svm_.problem_;
    svm_.problem_ = nullptr;
  }
  if (proto.hasProblem()) {
    auto problemProto = proto.getProblem();
    svm_.problem_ = new svm_problem01(1, false);
    svm_.problem_->read(problemProto);
  }
}
} // namespace svm
} // namespace algorithms
} // namespace nupic


/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 *
 * http://example.com
 * ---------------------------------------------------------------------
 */

/*
All rights reserved.

*/

#include <cstdio>
#include <sstream>

#include <nupic/algorithms/Svm.hpp>

namespace nupic {
namespace algorithms {
namespace svm {

using namespace std;

void svm_parameter::print() const {
  std::cout << "kernel = " << kernel << std::endl
            << "probability = " << probability << std::endl
            << "gamma = " << gamma << std::endl
            << "C = " << C << std::endl
            << "eps = " << eps << std::endl
            << "cache_size = " << cache_size << std::endl
            << "shrinking = " << shrinking << std::endl;
}

int svm_parameter::persistent_size() const {
  stringstream b;
  b << kernel << ' ' << probability << ' ' << gamma << ' ' << C << ' ' << eps
    << ' ' << cache_size << ' ' << shrinking << ' ' << weight_label << ' '
    << weight << ' ';

  return b.str().size();
}

void svm_parameter::save(std::ostream &outStream) const {
  outStream << kernel << ' ' << probability << ' ' << gamma << ' ' << C << ' '
            << eps << ' ' << cache_size << ' ' << shrinking << ' '
            << weight_label << ' ' << weight << ' ';
}

void svm_parameter::load(std::istream &inStream) {
  inStream >> kernel >> probability >> gamma >> C >> eps >> cache_size >>
      shrinking >> weight_label >> weight;
}

void svm_parameter::read(SvmParameterProto::Reader &proto) {
  kernel = proto.getKernel();
  probability = proto.getProbability();
  gamma = proto.getGamma();
  C = proto.getC();
  eps = proto.getEps();
  cache_size = proto.getCacheSize();
  shrinking = proto.getShrinking();

  auto weightList = proto.getWeight();
  size_t size = weightList.size();
  weight.resize(size);
  for (size_t i = 0; i < size; i++) {
    weight[i] = weightList[i];
  }

  auto labelList = proto.getWeightLabel();
  size = labelList.size();
  weight_label.resize(size);
  for (size_t i = 0; i < size; i++) {
    weight_label[i] = labelList[i];
  }
}

void svm_parameter::write(SvmParameterProto::Builder &proto) const {
  proto.setKernel(kernel);
  proto.setProbability(probability);
  proto.setGamma(gamma);
  proto.setC(C);
  proto.setEps(eps);
  proto.setCacheSize(cache_size);
  proto.setShrinking(shrinking);

  size_t size = weight.size();
  auto weightList = proto.initWeight(size);
  for (size_t i = 0; i < size; i++) {
    weightList.set(i, weight[i]);
  }

  size = weight_label.size();
  auto labelList = proto.initWeightLabel(size);
  for (size_t i = 0; i < size; i++) {
    labelList.set(i, weight_label[i]);
  }
}

int svm_problem::persistent_size() const {
  stringstream b;

  b << size() << " " << n_dims() << " ";

  return b.str().size() + y_.size() * sizeof(label_type) +
         size() * n_dims() * sizeof(feature_type) + 1;
}

void svm_problem::save(std::ostream &outStream) const {
  outStream << size() << " " << n_dims() << " ";

  nupic::binary_save(outStream, y_);

  for (int i = 0; i < size(); ++i)
    nupic::binary_save(outStream, x_[i], x_[i] + n_dims());
  outStream << " ";
}

void svm_problem::load(std::istream &inStream) {
  int s = 0;
  inStream >> s >> n_dims_;

  if (recover_)
    for (size_t i = 0; i != x_.size(); ++i)
      delete[] x_[i];

  y_.resize(s, 0);
  x_.resize(s, nullptr);

  inStream.ignore(1);
  nupic::binary_load(inStream, y_);

  for (int i = 0; i < size(); ++i) {
#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
    x_[i] = (float *)_aligned_malloc(4 * n_dims(), 16);
#else
    x_[i] = new feature_type[n_dims()];
#endif

    std::fill(x_[i], x_[i] + n_dims(), (float)0);
    nupic::binary_load(inStream, x_[i], x_[i] + n_dims());
  }
}

void svm_problem::read(SvmProblemProto::Reader &proto) {
  recover_ = proto.getRecover();
  n_dims_ = proto.getNDims();

  auto yList = proto.getY();
  size_t size = yList.size();
  y_.resize(size);
  for (size_t i = 0; i < size; i++) {
    y_[i] = yList[i];
  }

  for (auto &elem : x_)
    delete[] elem;

  x_.clear();
  for (auto list : proto.getX()) {
    size_t size = list.size();
    float *values = new float[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    x_.push_back(values);
  }
}

void svm_problem::write(SvmProblemProto::Builder &proto) const {
  proto.setRecover(recover_);
  proto.setNDims(n_dims_);

  size_t size = y_.size();
  auto yList = proto.initY(size);
  for (size_t i = 0; i < size; i++) {
    yList.set(i, y_[i]);
  }

  size = x_.size();
  auto xList = proto.initX(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = xList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, x_[i][j]);
    }
  }
}

int svm_problem01::persistent_size() const {
  stringstream b;
  b << size() << " " << n_dims() << " " << threshold_ << " ";
  int n = b.str().size();

  n += y_.size() * sizeof(float);
  n += nnz_.size() * sizeof(int);

  for (int i = 0; i != size(); ++i)
    n += nnz_[i] * sizeof(feature_type);

  return n + 1;
}

void svm_problem01::save(std::ostream &outStream) const {
  outStream << size() << " " << n_dims() << " " << threshold_ << " ";

  nupic::binary_save(outStream, y_);
  nupic::binary_save(outStream, nnz_);

  for (int i = 0; i < size(); ++i)
    nupic::binary_save(outStream, x_[i], x_[i] + nnz_[i]);
  outStream << " ";
}

void svm_problem01::load(std::istream &inStream) {
  int s = 0;
  inStream >> s >> n_dims_ >> threshold_;

  if (recover_)
    for (auto &elem : x_)
      delete[] elem;

  y_.resize(s, 0);
  nnz_.resize(s, 0);
  x_.resize(s, nullptr);

  inStream.ignore(1);
  nupic::binary_load(inStream, y_);
  nupic::binary_load(inStream, nnz_);

  for (int i = 0; i < s; ++i) {
    x_[i] = new feature_type[nnz_[i]];
    nupic::binary_load(inStream, x_[i], x_[i] + nnz_[i]);
  }
}

void svm_problem01::read(SvmProblem01Proto::Reader &proto) {
  recover_ = proto.getRecover();
  n_dims_ = proto.getNDims();
  threshold_ = proto.getThreshold();

  auto yList = proto.getY();
  size_t size = yList.size();
  y_.resize(size);
  for (size_t i = 0; i < size; i++) {
    y_[i] = yList[i];
  }

  auto nnzList = proto.getNnz();
  nnz_.resize(nnzList.size());
  size = nnzList.size();
  nnz_.resize(size);
  for (size_t i = 0; i < size; i++) {
    nnz_[i] = nnzList[i];
  }

  for (auto &elem : x_)
    delete[] elem;

  x_.clear();
  for (auto list : proto.getX()) {
    size_t size = list.size();
    int *values = new int[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    x_.push_back(values);
  }
}

void svm_problem01::write(SvmProblem01Proto::Builder &proto) const {
  proto.setRecover(recover_);
  proto.setNDims(n_dims_);
  proto.setThreshold(threshold_);

  size_t size = y_.size();
  auto yList = proto.initY(size);
  for (size_t i = 0; i < size; i++) {
    yList.set(i, y_[i]);
  }

  size = nnz_.size();
  auto nnzList = proto.initNnz(size);
  for (size_t i = 0; i < size; i++) {
    nnzList.set(i, nnz_[i]);
  }

  size = x_.size();
  auto xList = proto.initX(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = xList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, x_[i][j]);
    }
  }
}

svm_model::~svm_model() {
  // in all cases, ownership of the mem for the sv is with svm_model

  if (sv_mem == nullptr) {
    for (size_t i = 0; i != sv.size(); ++i)

#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
      _aligned_free(sv[i]);
#else
      delete[] sv[i];
#endif

  } else {
#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
    _aligned_free(sv_mem);
#else
    delete[] sv_mem;
#endif

    sv_mem = nullptr;
    sv.clear();
  }

  for (size_t i = 0; i != sv_coef.size(); ++i)
    delete[] sv_coef[i];
}

void svm_model::print() const {
  std::cout << "n classes = " << n_class() << " n sv = " << size()
            << " n dims = " << n_dims() << std::endl;

  std::cout << "Support vectors: " << std::endl;
  for (size_t i = 0; i != sv.size(); ++i) {
    for (int j = 0; j != n_dims(); ++j)
      std::cout << sv[i][j] << " ";
    std::cout << std::endl;
  }

  std::cout << "Support vector coefficients: " << std::endl;
  for (size_t i = 0; i != sv_coef.size(); ++i) {
    for (int j = 0; j != size(); ++j)
      std::cout << sv_coef[i][j] << " ";
    std::cout << std::endl;
  }

  std::cout << "Rho: " << std::endl;
  for (size_t i = 0; i != rho.size(); ++i)
    std::cout << rho[i] << " ";
  std::cout << std::endl;

  if (!probA.empty()) {
    std::cout << "Probabilities A: " << std::endl;
    for (size_t i = 0; i != probA.size(); ++i)
      std::cout << probA[i] << " ";
    std::cout << std::endl;

    std::cout << "Probabilities B: " << std::endl;
    for (size_t i = 0; i != probB.size(); ++i)
      std::cout << probB[i] << " ";
    std::cout << std::endl;
  }
}

int svm_model::persistent_size() const {
  stringstream b;
  b << n_class() << " " << size() << " " << n_dims() << " ";

  int n = b.str().size();

  n += sv.size() * n_dims() * sizeof(float) + 1;

  {
    stringstream b2;
    for (auto &elem : sv_coef) {
      for (int j = 0; j < size(); ++j)
        b2 << elem[j] << " ";
    }
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << rho << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << label << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << n_sv << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << probA << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << probB << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << w << " ";
    n += b2.str().size();
  }

  return n;
}

void svm_model::save(std::ostream &outStream) const {
  outStream << n_class() << " " << size() << " " << n_dims() << " ";

  for (auto &elem : sv)
    nupic::binary_save(outStream, elem, elem + n_dims());
  outStream << " ";

  for (auto &elem : sv_coef)
    for (int j = 0; j < size(); ++j)
      outStream << elem[j] << " ";

  outStream << rho << ' ' << label << ' ' << n_sv << ' ' << probA << ' '
            << probB << ' ' << w << ' ';
}

void svm_model::load(std::istream &inStream) {
  int n_class = 0, l = 0;
  inStream >> n_class >> l >> n_dims_;

  if (sv_mem == nullptr) {
    for (auto &elem : sv)
      delete[] elem;

  } else {
    delete[] sv_mem;
    sv_mem = nullptr;
  }

#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
  sv_mem = (float *)_aligned_malloc(4 * l * n_dims(), 16);
#else
  sv_mem = new float[l * n_dims()];
#endif

  std::fill(sv_mem, sv_mem + l * n_dims(), (float)0);

  sv.resize(l, nullptr);
  inStream.ignore(1);
  for (int i = 0; i < l; ++i) {
    sv[i] = sv_mem + i * n_dims();
    nupic::binary_load(inStream, sv[i], sv[i] + n_dims());
  }

  for (auto &elem : sv_coef)
    delete[] elem;

  sv_coef.resize(n_class - 1, nullptr);
  for (int i = 0; i < n_class - 1; ++i) {
    sv_coef[i] = new float[l];
    for (int j = 0; j < l; ++j)
      inStream >> sv_coef[i][j];
  }

  inStream >> rho >> label >> n_sv >> probA >> probB >> w;
}

void svm_model::read(SvmModelProto::Reader &proto) {
  n_dims_ = proto.getNDims();

  if (sv_mem == nullptr) {
    for (auto &elem : sv)
      delete[] elem;
  } else {
    delete[] sv_mem;
    sv_mem = nullptr;
  }
  sv.clear();

  for (auto list : proto.getSv()) {
    size_t size = list.size();
    float *values = new float[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    sv.push_back(values);
  }

  for (auto &elem : sv_coef)
    delete[] elem;
  sv_coef.clear();

  for (auto list : proto.getSvCoef()) {
    size_t size = list.size();
    float *values = new float[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    sv_coef.push_back(values);
  }

  auto wList = proto.getW();
  size_t size = wList.size();
  w.resize(size);
  for (size_t i = 0; i < size; i++) {
    auto values = wList[i];
    size_t len = values.size();
    w[i].resize(len);
    for (size_t j = 0; j < len; j++) {
      w[i][j] = values[j];
    }
  }

  auto rhoList = proto.getRho();
  size = rhoList.size();
  rho.resize(size);
  for (size_t i = 0; i < size; i++) {
    rho[i] = rhoList[i];
  }

  auto probAList = proto.getProbA();
  size = probAList.size();
  probA.resize(size);
  for (size_t i = 0; i < size; i++) {
    probA[i] = probAList[i];
  }

  auto probBList = proto.getProbB();
  size = probBList.size();
  probB.resize(size);
  for (size_t i = 0; i < size; i++) {
    probB[i] = probBList[i];
  }

  auto labelList = proto.getLabel();
  size = labelList.size();
  label.resize(size);
  for (size_t i = 0; i < size; i++) {
    label[i] = labelList[i];
  }

  auto nsvList = proto.getNSv();
  size = nsvList.size();
  n_sv.resize(size);
  for (size_t i = 0; i < size; i++) {
    n_sv[i] = nsvList[i];
  }
}

void svm_model::write(SvmModelProto::Builder &proto) const {

  proto.setNDims(n_dims_);

  size_t size = sv.size();
  auto svList = proto.initSv(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = svList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, sv[i][j]);
    }
  }

  size = sv_coef.size();
  auto svCoefList = proto.initSvCoef(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = svCoefList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, sv_coef[i][j]);
    }
  }

  size = rho.size();
  auto rhoList = proto.initRho(size);
  for (size_t i = 0; i < size; i++) {
    rhoList.set(i, rho[i]);
  }

  size = label.size();
  auto labelList = proto.initLabel(size);
  for (size_t i = 0; i < size; i++) {
    labelList.set(i, label[i]);
  }

  size = n_sv.size();
  auto nsvList = proto.initNSv(size);
  for (size_t i = 0; i < size; i++) {
    nsvList.set(i, n_sv[i]);
  }

  size = probA.size();
  auto probAList = proto.initProbA(size);
  for (size_t i = 0; i < size; i++) {
    probAList.set(i, probA[i]);
  }

  size = probB.size();
  auto probBList = proto.initProbB(size);
  for (size_t i = 0; i < size; i++) {
    probBList.set(i, probB[i]);
  }

  size = w.size();
  auto wList = proto.initW(size);
  for (size_t i = 0; i < size; i++) {
    size_t len = w[i].size();
    auto dims = wList.init(i, len);
    for (size_t j = 0; j < len; j++) {
      dims.set(j, w[i][j]);
    }
  }
}

void svm_dense::write(SvmDenseProto::Builder &proto) const {
  auto paramProto = proto.getParam();
  svm_.param_.write(paramProto);

  if (svm_.model_) {
    auto modelProto = proto.getModel();
    svm_.model_->write(modelProto);
  }
  if (svm_.problem_) {
    auto problemProto = proto.getProblem();
    svm_.problem_->write(problemProto);
  }
}

void svm_dense::read(SvmDenseProto::Reader &proto) {
  auto paramProto = proto.getParam();
  svm_.param_.read(paramProto);

  if (svm_.model_) {
    delete svm_.model_;
    svm_.model_ = nullptr;
  }
  if (proto.hasModel()) {
    auto modelProto = proto.getModel();
    svm_.model_ = new svm_model;
    svm_.model_->read(modelProto);
  }
  if (svm_.problem_) {
    delete svm_.problem_;
    svm_.problem_ = nullptr;
  }
  if (proto.hasProblem()) {
    auto problemProto = proto.getProblem();
    svm_.problem_ = new svm_problem(1, false);
    svm_.problem_->read(problemProto);
  }
}

void svm_01::write(Svm01Proto::Builder &proto) const

void svm_01::read(Svm01Proto::Reader &proto) {
  auto paramProto = proto.getParam();
  svm_.param_.read(paramProto);

  if (svm_.model_) {
    delete svm_.model_;
    svm_.model_ = nullptr;
  }
  if (proto.hasModel()) {
    auto modelProto = proto.getModel();
    svm_.model_ = new svm_model;
    svm_.model_->read(modelProto);
  }
  if (svm_.problem_) {
    delete svm_.problem_;
    svm_.problem_ = nullptr;
  }
  if (proto.hasProblem()) {
    auto problemProto = proto.getProblem();
    svm_.problem_ = new svm_problem01(1, false);
    svm_.problem_->read(problemProto);
  }
}
} // namespace svm
} // namespace algorithms
} // namespace nupic


/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 *
 * http://example.com
 * ---------------------------------------------------------------------
 */

/*
All rights reserved.

*/

#include <cstdio>
#include <sstream>

#include <nupic/algorithms/Svm.hpp>

namespace nupic {
namespace algorithms {
namespace svm {

using namespace std;

void svm_parameter::print() const {
  std::cout << "kernel = " << kernel << std::endl
            << "probability = " << probability << std::endl
            << "gamma = " << gamma << std::endl
            << "C = " << C << std::endl
            << "eps = " << eps << std::endl
            << "cache_size = " << cache_size << std::endl
            << "shrinking = " << shrinking << std::endl;
}

int svm_parameter::persistent_size() const {
  stringstream b;
  b << kernel << ' ' << probability << ' ' << gamma << ' ' << C << ' ' << eps
    << ' ' << cache_size << ' ' << shrinking << ' ' << weight_label << ' '
    << weight << ' ';

  return b.str().size();
}

void svm_parameter::save(std::ostream &outStream) const {
  outStream << kernel << ' ' << probability << ' ' << gamma << ' ' << C << ' '
            << eps << ' ' << cache_size << ' ' << shrinking << ' '
            << weight_label << ' ' << weight << ' ';
}

void svm_parameter::load(std::istream &inStream) {
  inStream >> kernel >> probability >> gamma >> C >> eps >> cache_size >>
      shrinking >> weight_label >> weight;
}

void svm_parameter::read(SvmParameterProto::Reader &proto) {
  kernel = proto.getKernel();
  probability = proto.getProbability();
  gamma = proto.getGamma();
  C = proto.getC();
  eps = proto.getEps();
  cache_size = proto.getCacheSize();
  shrinking = proto.getShrinking();

  auto weightList = proto.getWeight();
  size_t size = weightList.size();
  weight.resize(size);
  for (size_t i = 0; i < size; i++) {
    weight[i] = weightList[i];
  }

  auto labelList = proto.getWeightLabel();
  size = labelList.size();
  weight_label.resize(size);
  for (size_t i = 0; i < size; i++) {
    weight_label[i] = labelList[i];
  }
}

void svm_parameter::write(SvmParameterProto::Builder &proto) const {
  proto.setKernel(kernel);
  proto.setProbability(probability);
  proto.setGamma(gamma);
  proto.setC(C);
  proto.setEps(eps);
  proto.setCacheSize(cache_size);
  proto.setShrinking(shrinking);

  size_t size = weight.size();
  auto weightList = proto.initWeight(size);
  for (size_t i = 0; i < size; i++) {
    weightList.set(i, weight[i]);
  }

  size = weight_label.size();
  auto labelList = proto.initWeightLabel(size);
  for (size_t i = 0; i < size; i++) {
    labelList.set(i, weight_label[i]);
  }
}

int svm_problem::persistent_size() const {
  stringstream b;

  b << size() << " " << n_dims() << " ";

  return b.str().size() + y_.size() * sizeof(label_type) +
         size() * n_dims() * sizeof(feature_type) + 1;
}

void svm_problem::save(std::ostream &outStream) const {
  outStream << size() << " " << n_dims() << " ";

  nupic::binary_save(outStream, y_);

  for (int i = 0; i < size(); ++i)
    nupic::binary_save(outStream, x_[i], x_[i] + n_dims());
  outStream << " ";
}

void svm_problem::load(std::istream &inStream) {
  int s = 0;
  inStream >> s >> n_dims_;

  if (recover_)
    for (size_t i = 0; i != x_.size(); ++i)
      delete[] x_[i];

  y_.resize(s, 0);
  x_.resize(s, nullptr);

  inStream.ignore(1);
  nupic::binary_load(inStream, y_);

  for (int i = 0; i < size(); ++i) {
#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
    x_[i] = (float *)_aligned_malloc(4 * n_dims(), 16);
#else
    x_[i] = new feature_type[n_dims()];
#endif

    std::fill(x_[i], x_[i] + n_dims(), (float)0);
    nupic::binary_load(inStream, x_[i], x_[i] + n_dims());
  }
}

void svm_problem::read(SvmProblemProto::Reader &proto) {
  recover_ = proto.getRecover();
  n_dims_ = proto.getNDims();

  auto yList = proto.getY();
  size_t size = yList.size();
  y_.resize(size);
  for (size_t i = 0; i < size; i++) {
    y_[i] = yList[i];
  }

  for (auto &elem : x_)
    delete[] elem;

  x_.clear();
  for (auto list : proto.getX()) {
    size_t size = list.size();
    float *values = new float[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    x_.push_back(values);
  }
}

void svm_problem::write(SvmProblemProto::Builder &proto) const {
  proto.setRecover(recover_);
  proto.setNDims(n_dims_);

  size_t size = y_.size();
  auto yList = proto.initY(size);
  for (size_t i = 0; i < size; i++) {
    yList.set(i, y_[i]);
  }

  size = x_.size();
  auto xList = proto.initX(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = xList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, x_[i][j]);
    }
  }
}

int svm_problem01::persistent_size() const {
  stringstream b;
  b << size() << " " << n_dims() << " " << threshold_ << " ";
  int n = b.str().size();

  n += y_.size() * sizeof(float);
  n += nnz_.size() * sizeof(int);

  for (int i = 0; i != size(); ++i)
    n += nnz_[i] * sizeof(feature_type);

  return n + 1;
}

void svm_problem01::save(std::ostream &outStream) const {
  outStream << size() << " " << n_dims() << " " << threshold_ << " ";

  nupic::binary_save(outStream, y_);
  nupic::binary_save(outStream, nnz_);

  for (int i = 0; i < size(); ++i)
    nupic::binary_save(outStream, x_[i], x_[i] + nnz_[i]);
  outStream << " ";
}

void svm_problem01::load(std::istream &inStream) {
  int s = 0;
  inStream >> s >> n_dims_ >> threshold_;

  if (recover_)
    for (auto &elem : x_)
      delete[] elem;

  y_.resize(s, 0);
  nnz_.resize(s, 0);
  x_.resize(s, nullptr);

  inStream.ignore(1);
  nupic::binary_load(inStream, y_);
  nupic::binary_load(inStream, nnz_);

  for (int i = 0; i < s; ++i) {
    x_[i] = new feature_type[nnz_[i]];
    nupic::binary_load(inStream, x_[i], x_[i] + nnz_[i]);
  }
}

void svm_problem01::read(SvmProblem01Proto::Reader &proto) {
  recover_ = proto.getRecover();
  n_dims_ = proto.getNDims();
  threshold_ = proto.getThreshold();

  auto yList = proto.getY();
  size_t size = yList.size();
  y_.resize(size);
  for (size_t i = 0; i < size; i++) {
    y_[i] = yList[i];
  }

  auto nnzList = proto.getNnz();
  nnz_.resize(nnzList.size());
  size = nnzList.size();
  nnz_.resize(size);
  for (size_t i = 0; i < size; i++) {
    nnz_[i] = nnzList[i];
  }

  for (auto &elem : x_)
    delete[] elem;

  x_.clear();
  for (auto list : proto.getX()) {
    size_t size = list.size();
    int *values = new int[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    x_.push_back(values);
  }
}

void svm_problem01::write(SvmProblem01Proto::Builder &proto) const {
  proto.setRecover(recover_);
  proto.setNDims(n_dims_);
  proto.setThreshold(threshold_);

  size_t size = y_.size();
  auto yList = proto.initY(size);
  for (size_t i = 0; i < size; i++) {
    yList.set(i, y_[i]);
  }

  size = nnz_.size();
  auto nnzList = proto.initNnz(size);
  for (size_t i = 0; i < size; i++) {
    nnzList.set(i, nnz_[i]);
  }

  size = x_.size();
  auto xList = proto.initX(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = xList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, x_[i][j]);
    }
  }
}

svm_model::~svm_model() {
  // in all cases, ownership of the mem for the sv is with svm_model

  if (sv_mem == nullptr) {
    for (size_t i = 0; i != sv.size(); ++i)

#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
      _aligned_free(sv[i]);
#else
      delete[] sv[i];
#endif

  } else {
#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
    _aligned_free(sv_mem);
#else
    delete[] sv_mem;
#endif

    sv_mem = nullptr;
    sv.clear();
  }

  for (size_t i = 0; i != sv_coef.size(); ++i)
    delete[] sv_coef[i];
}

void svm_model::print() const {
  std::cout << "n classes = " << n_class() << " n sv = " << size()
            << " n dims = " << n_dims() << std::endl;

  std::cout << "Support vectors: " << std::endl;
  for (size_t i = 0; i != sv.size(); ++i) {
    for (int j = 0; j != n_dims(); ++j)
      std::cout << sv[i][j] << " ";
    std::cout << std::endl;
  }

  std::cout << "Support vector coefficients: " << std::endl;
  for (size_t i = 0; i != sv_coef.size(); ++i) {
    for (int j = 0; j != size(); ++j)
      std::cout << sv_coef[i][j] << " ";
    std::cout << std::endl;
  }

  std::cout << "Rho: " << std::endl;
  for (size_t i = 0; i != rho.size(); ++i)
    std::cout << rho[i] << " ";
  std::cout << std::endl;

  if (!probA.empty()) {
    std::cout << "Probabilities A: " << std::endl;
    for (size_t i = 0; i != probA.size(); ++i)
      std::cout << probA[i] << " ";
    std::cout << std::endl;

    std::cout << "Probabilities B: " << std::endl;
    for (size_t i = 0; i != probB.size(); ++i)
      std::cout << probB[i] << " ";
    std::cout << std::endl;
  }
}

int svm_model::persistent_size() const {
  stringstream b;
  b << n_class() << " " << size() << " " << n_dims() << " ";

  int n = b.str().size();

  n += sv.size() * n_dims() * sizeof(float) + 1;

  {
    stringstream b2;
    for (auto &elem : sv_coef) {
      for (int j = 0; j < size(); ++j)
        b2 << elem[j] << " ";
    }
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << rho << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << label << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << n_sv << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << probA << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << probB << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << w << " ";
    n += b2.str().size();
  }

  return n;
}

void svm_model::save(std::ostream &outStream) const {
  outStream << n_class() << " " << size() << " " << n_dims() << " ";

  for (auto &elem : sv)
    nupic::binary_save(outStream, elem, elem + n_dims());
  outStream << " ";

  for (auto &elem : sv_coef)
    for (int j = 0; j < size(); ++j)
      outStream << elem[j] << " ";

  outStream << rho << ' ' << label << ' ' << n_sv << ' ' << probA << ' '
            << probB << ' ' << w << ' ';
}

void svm_model::load(std::istream &inStream) {
  int n_class = 0, l = 0;
  inStream >> n_class >> l >> n_dims_;

  if (sv_mem == nullptr) {
    for (auto &elem : sv)
      delete[] elem;

  } else {
    delete[] sv_mem;
    sv_mem = nullptr;
  }

#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
  sv_mem = (float *)_aligned_malloc(4 * l * n_dims(), 16);
#else
  sv_mem = new float[l * n_dims()];
#endif

  std::fill(sv_mem, sv_mem + l * n_dims(), (float)0);

  sv.resize(l, nullptr);
  inStream.ignore(1);
  for (int i = 0; i < l; ++i) {
    sv[i] = sv_mem + i * n_dims();
    nupic::binary_load(inStream, sv[i], sv[i] + n_dims());
  }

  for (auto &elem : sv_coef)
    delete[] elem;

  sv_coef.resize(n_class - 1, nullptr);
  for (int i = 0; i < n_class - 1; ++i) {
    sv_coef[i] = new float[l];
    for (int j = 0; j < l; ++j)
      inStream >> sv_coef[i][j];
  }

  inStream >> rho >> label >> n_sv >> probA >> probB >> w;
}

void svm_model::read(SvmModelProto::Reader &proto) {
  n_dims_ = proto.getNDims();

  if (sv_mem == nullptr) {
    for (auto &elem : sv)
      delete[] elem;
  } else {
    delete[] sv_mem;
    sv_mem = nullptr;
  }
  sv.clear();

  for (auto list : proto.getSv()) {
    size_t size = list.size();
    float *values = new float[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    sv.push_back(values);
  }

  for (auto &elem : sv_coef)
    delete[] elem;
  sv_coef.clear();

  for (auto list : proto.getSvCoef()) {
    size_t size = list.size();
    float *values = new float[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    sv_coef.push_back(values);
  }

  auto wList = proto.getW();
  size_t size = wList.size();
  w.resize(size);
  for (size_t i = 0; i < size; i++) {
    auto values = wList[i];
    size_t len = values.size();
    w[i].resize(len);
    for (size_t j = 0; j < len; j++) {
      w[i][j] = values[j];
    }
  }

  auto rhoList = proto.getRho();
  size = rhoList.size();
  rho.resize(size);
  for (size_t i = 0; i < size; i++) {
    rho[i] = rhoList[i];
  }

  auto probAList = proto.getProbA();
  size = probAList.size();
  probA.resize(size);
  for (size_t i = 0; i < size; i++) {
    probA[i] = probAList[i];
  }

  auto probBList = proto.getProbB();
  size = probBList.size();
  probB.resize(size);
  for (size_t i = 0; i < size; i++) {
    probB[i] = probBList[i];
  }

  auto labelList = proto.getLabel();
  size = labelList.size();
  label.resize(size);
  for (size_t i = 0; i < size; i++) {
    label[i] = labelList[i];
  }

  auto nsvList = proto.getNSv();
  size = nsvList.size();
  n_sv.resize(size);
  for (size_t i = 0; i < size; i++) {
    n_sv[i] = nsvList[i];
  }
}

void svm_model::write(SvmModelProto::Builder &proto) const {

  proto.setNDims(n_dims_);

  size_t size = sv.size();
  auto svList = proto.initSv(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = svList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, sv[i][j]);
    }
  }

  size = sv_coef.size();
  auto svCoefList = proto.initSvCoef(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = svCoefList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, sv_coef[i][j]);
    }
  }

  size = rho.size();
  auto rhoList = proto.initRho(size);
  for (size_t i = 0; i < size; i++) {
    rhoList.set(i, rho[i]);
  }

  size = label.size();
  auto labelList = proto.initLabel(size);
  for (size_t i = 0; i < size; i++) {
    labelList.set(i, label[i]);
  }

  size = n_sv.size();
  auto nsvList = proto.initNSv(size);
  for (size_t i = 0; i < size; i++) {
    nsvList.set(i, n_sv[i]);
  }

  size = probA.size();
  auto probAList = proto.initProbA(size);
  for (size_t i = 0; i < size; i++) {
    probAList.set(i, probA[i]);
  }

  si

  auto probBList = proto.initProbB(size);
  for (size_t i = 0; i < size; i++) {
    probBList.set(i, probB[i]);
  }

  size = w.size();
  auto wList = proto.initW(size);
  for (size_t i = 0; i < size; i++) {
    size_t len = w[i].size();
    auto dims = wList.init(i, len);
    for (size_t j = 0; j < len; j++) {
      dims.set(j, w[i][j]);
    }
  }
}

void svm_dense::write(SvmDenseProto::Builder &proto) const {
  auto paramProto = proto.getParam();
  svm_.param_.write(paramProto);

  if (svm_.model_) {
    auto modelProto = proto.getModel();
    svm_.model_->write(modelProto);
  }
  if (svm_.problem_) {
    auto problemProto = proto.getProblem();
    svm_.problem_->write(problemProto);
  }
}

void svm_dense::read(SvmDenseProto::Reader &proto) {
  auto paramProto = proto.getParam();
  svm_.param_.read(paramProto);

  if (svm_.model_) {
    delete svm_.model_;
    svm_.model_ = nullptr;
  }
  if (proto.hasModel()) {
    auto modelProto = proto.getModel();
    svm_.model_ = new svm_model;
    svm_.model_->read(modelProto);
  }
  if (svm_.problem_) {
    delete svm_.problem_;
    svm_.problem_ = nullptr;
  }
  if (proto.hasProblem()) {
    auto problemProto = proto.getProblem();
    svm_.problem_ = new svm_problem(1, false);
    svm_.problem_->read(problemProto);
  }
}

void svm_01::write(Svm01Proto::Builder &proto) const {
  auto paramProto = proto.getParam();
  svm_.param_.write(paramProto);

  if (svm_.model_) {
    auto modelProto = proto.getModel();
    svm_.model_->write(modelProto);
  }
  if (svm_.problem_) {
    auto problemProto = proto.getProblem();
    svm_.problem_->write(problemProto);
  }
}

void svm_01::read(Svm01Proto::Reader &proto) {
  auto paramProto = proto.getParam();
  svm_.param_.read(paramProto);

  if (svm_.model_) {
    delete svm_.model_;
    svm_.model_ = nullptr;
  }
  if (proto.hasModel()) {
    auto modelProto = proto.getModel();
    svm_.model_ = new svm_model;
    svm_.model_->read(modelProto);
  }
  if (svm_.problem_) {
    delete svm_.problem_;
    svm_.problem_ = nullptr;
  }
  if (proto.hasProblem()) {
    auto problemProto = proto.getProblem();
    svm_.problem_ = new svm_problem01(1, false);
    svm_.problem_->read(problemProto);
  }
}
} // namespace svm
} // namespace algorithms
} // namespace nupic


/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 *
 * http://example.com
 * ---------------------------------------------------------------------
 */

/*
All rights reserved.

*/

#include <cstdio>
#include <sstream>

#include <nupic/algorithms/Svm.hpp>

namespace nupic {
namespace algorithms {
namespace svm {

using namespace std;

void svm_parameter::print() const {
  std::cout << "kernel = " << kernel << std::endl
            << "probability = " << probability << std::endl
            << "gamma = " << gamma << std::endl
            << "C = " << C << std::endl
            << "eps = " << eps << std::endl
            << "cache_size = " << cache_size << std::endl
            << "shrinking = " << shrinking << std::endl;
}

int svm_parameter::persistent_size() const {
  stringstream b;
  b << kernel << ' ' << probability << ' ' << gamma << ' ' << C << ' ' << eps
    << ' ' << cache_size << ' ' << shrinking << ' ' << weight_label << ' '
    << weight << ' ';

  return b.str().size();
}

void svm_parameter::save(std::ostream &outStream) const {
  outStream << kernel << ' ' << probability << ' ' << gamma << ' ' << C << ' '
            << eps << ' ' << cache_size << ' ' << shrinking << ' '
            << weight_label << ' ' << weight << ' ';
}

void svm_parameter::load(std::istream &inStream) {
  inStream >> kernel >> probability >> gamma >> C >> eps >> cache_size >>
      shrinking >> weight_label >> weight;
}

void svm_parameter::read(SvmParameterProto::Reader &proto) {
  kernel = proto.getKernel();
  probability = proto.getProbability();
  gamma = proto.getGamma();
  C = proto.getC();
  eps = proto.getEps();
  cache_size = proto.getCacheSize();
  shrinking = proto.getShrinking();

  auto weightList = proto.getWeight();
  size_t size = weightList.size();
  weight.resize(size);
  for (size_t i = 0; i < size; i++) {
    weight[i] = weightList[i];
  }

  auto labelList = proto.getWeightLabel();
  size = labelList.size();
  weight_label.resize(size);
  for (size_t i = 0; i < size; i++) {
    weight_label[i] = labelList[i];
  }
}

void svm_parameter::write(SvmParameterProto::Builder &proto) const {
  proto.setKernel(kernel);
  proto.setProbability(probability);
  proto.setGamma(gamma);
  proto.setC(C);
  proto.setEps(eps);
  proto.setCacheSize(cache_size);
  proto.setShrinking(shrinking);

  size_t size = weight.size();
  auto weightList = proto.initWeight(size);
  for (size_t i = 0; i < size; i++) {
    weightList.set(i, weight[i]);
  }

  size = weight_label.size();
  auto labelList = proto.initWeightLabel(size);
  for (size_t i = 0; i < size; i++) {
    labelList.set(i, weight_label[i]);
  }
}

int svm_problem::persistent_size() const {
  stringstream b;

  b << size() << " " << n_dims() << " ";

  return b.str().size() + y_.size() * sizeof(label_type) +
         size() * n_dims() * sizeof(feature_type) + 1;
}

void svm_problem::save(std::ostream &outStream) const {
  outStream << size() << " " << n_dims() << " ";

  nupic::binary_save(outStream, y_);

  for (int i = 0; i < size(); ++i)
    nupic::binary_save(outStream, x_[i], x_[i] + n_dims());
  outStream << " ";
}

void svm_problem::load(std::istream &inStream) {
  int s = 0;
  inStream >> s >> n_dims_;

  if (recover_)
    for (size_t i = 0; i != x_.size(); ++i)
      delete[] x_[i];

  y_.resize(s, 0);
  x_.resize(s, nullptr);

  inStream.ignore(1);
  nupic::binary_load(inStream, y_);

  for (int i = 0; i < size(); ++i) {
#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
    x_[i] = (float *)_aligned_malloc(4 * n_dims(), 16);
#else
    x_[i] = new feature_type[n_dims()];
#endif

    std::fill(x_[i], x_[i] + n_dims(), (float)0);
    nupic::binary_load(inStream, x_[i], x_[i] + n_dims());
  }
}

void svm_problem::read(SvmProblemProto::Reader &proto) {
  recover_ = proto.getRecover();
  n_dims_ = proto.getNDims();

  auto yList = proto.getY();
  size_t size = yList.size();
  y_.resize(size);
  for (size_t i = 0; i < size; i++) {
    y_[i] = yList[i];
  }

  for (auto &elem : x_)
    delete[] elem;

  x_.clear();
  for (auto list : proto.getX()) {
    size_t size = list.size();
    float *values = new float[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    x_.push_back(values);
  }
}

void svm_problem::write(SvmProblemProto::Builder &proto) const {
  proto.setRecover(recover_);
  proto.setNDims(n_dims_);

  size_t size = y_.size();
  auto yList = proto.initY(size);
  for (size_t i = 0; i < size; i++) {
    yList.set(i, y_[i]);
  }

  size = x_.size();
  auto xList = proto.initX(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = xList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, x_[i][j]);
    }
  }
}

int svm_problem01::persistent_size() const {
  stringstream b;
  b << size() << " " << n_dims() << " " << threshold_ << " ";
  int n = b.str().size();

  n += y_.size() * sizeof(float);
  n += nnz_.size() * sizeof(int);

  for (int i = 0; i != size(); ++i)
    n += nnz_[i] * sizeof(feature_type);

  return n + 1;
}

void svm_problem01::save(std::ostream &outStream) const {
  outStream << size() << " " << n_dims() << " " << threshold_ << " ";

  nupic::binary_save(outStream, y_);
  nupic::binary_save(outStream, nnz_);

  for (int i = 0; i < size(); ++i)
    nupic::binary_save(outStream, x_[i], x_[i] + nnz_[i]);
  outStream << " ";
}

void svm_problem01::load(std::istream &inStream) {
  int s = 0;
  inStream >> s >> n_dims_ >> threshold_;

  if (recover_)
    for (auto &elem : x_)
      delete[] elem;

  y_.resize(s, 0);
  nnz_.resize(s, 0);
  x_.resize(s, nullptr);

  inStream.ignore(1);
  nupic::binary_load(inStream, y_);
  nupic::binary_load(inStream, nnz_);

  for (int i = 0; i < s; ++i) {
    x_[i] = new feature_type[nnz_[i]];
    nupic::binary_load(inStream, x_[i], x_[i] + nnz_[i]);
  }
}

void svm_problem01::read(SvmProblem01Proto::Reader &proto) {
  recover_ = proto.getRecover();
  n_dims_ = proto.getNDims();
  threshold_ = proto.getThreshold();

  auto yList = proto.getY();
  size_t size = yList.size();
  y_.resize(size);
  for (size_t i = 0; i < size; i++) {
    y_[i] = yList[i];
  }

  auto nnzList = proto.getNnz();
  nnz_.resize(nnzList.size());
  size = nnzList.size();
  nnz_.resize(size);
  for (size_t i = 0; i < size; i++) {
    nnz_[i] = nnzList[i];
  }

  for (auto &elem : x_)
    delete[] elem;

  x_.clear();
  for (auto list : proto.getX()) {
    size_t size = list.size();
    int *values = new int[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    x_.push_back(values);
  }
}

void svm_problem01::write(SvmProblem01Proto::Builder &proto) const {
  proto.setRecover(recover_);
  proto.setNDims(n_dims_);
  proto.setThreshold(threshold_);

  size_t size = y_.size();
  auto yList = proto.initY(size);
  for (size_t i = 0; i < size; i++) {
    yList.set(i, y_[i]);
  }

  size = nnz_.size();
  auto nnzList = proto.initNnz(size);
  for (size_t i = 0; i < size; i++) {
    nnzList.set(i, nnz_[i]);
  }

  size = x_.size();
  auto xList = proto.initX(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = xList.init(i, n_dims_);

  }
}

svm_model::~svm_model() {
  // in all cases, ownership of the mem for the sv is with svm_model

  if (sv_mem == nullptr) {
    for (size_t i = 0; i != sv.size(); ++i)

#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
      _aligned_free(sv[i]);
#else
      delete[] sv[i];
#endif

  } else {
#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
    _aligned_free(sv_mem);
#else
    delete[] sv_mem;
#endif

    sv_mem = nullptr;
    sv.clear();
  }

  for (size_t i = 0; i != sv_coef.size(); ++i)
    delete[] sv_coef[i];
}

void svm_model::print() const {
  std::cout << "n classes = " << n_class() << " n sv = " << size()
            << " n dims = " << n_dims() << std::endl;

  std::cout << "Support vectors: " << std::endl;
  for (size_t i = 0; i != sv.size(); ++i) {
    for (int j = 0; j != n_dims(); ++j)
      std::cout << sv[i][j] << " ";
    std::cout << std::endl;
  }

  std::cout << "Support vector coefficients: " << std::endl;
  for (size_t i = 0; i != sv_coef.size(); ++i) {
    for (int j = 0; j != size(); ++j)
      std::cout << sv_coef[i][j] << " ";
    std::cout << std::endl;
  }

  std::cout << "Rho: " << std::endl;
  for (size_t i = 0; i != rho.size(); ++i)
    std::cout << rho[i] << " ";
  std::cout << std::endl;

  if (!probA.empty()) {
    std::cout << "Probabilities A: " << std::endl;
    for (size_t i = 0; i != probA.size(); ++i)
      std::cout << probA[i] << " ";
    std::cout << std::endl;

    std::cout << "Probabilities B: " << std::endl;
    for (size_t i = 0; i != probB.size(); ++i)
      std::cout << probB[i] << " ";
    std::cout << std::endl;
  }
}

int svm_model::persistent_size() const {
  stringstream b;
  b << n_class() << " " << size() << " " << n_dims() << " ";

  int n = b.str().size();

  n += sv.size() * n_dims() * sizeof(float) + 1;

  {
    stringstream b2;
    for (auto &elem : sv_coef) {
      for (int j = 0; j < size(); ++j)
        b2 << elem[j] << " ";
    }
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << rho << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << label << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << n_sv << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << probA << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << probB << " ";
    n += b2.str().size();
  }

  {
    stringstream b2;
    b2 << w << " ";
    n += b2.str().size();
  }

  return n;
}

void svm_model::save(std::ostream &outStream) const {
  outStream << n_class() << " " << size() << " " << n_dims() << " ";

  for (auto &elem : sv)
    nupic::binary_save(outStream, elem, elem + n_dims());
  outStream << " ";

  for (auto &elem : sv_coef)
    for (int j = 0; j < size(); ++j)
      outStream << elem[j] << " ";

  outStream << rho << ' ' << label << ' ' << n_sv << ' ' << probA << ' '
            << probB << ' ' << w << ' ';
}

void svm_model::load(std::istream &inStream) {
  int n_class = 0, l = 0;
  inStream >> n_class >> l >> n_dims_;

  if (sv_mem == nullptr) {
    for (auto &elem : sv)
      delete[] elem;

  } else {
    delete[] sv_mem;
    sv_mem = nullptr;
  }

#if defined(NTA_OS_WINDOWS) && defined(NTA_COMPILER_MSVC)
  sv_mem = (float *)_aligned_malloc(4 * l * n_dims(), 16);
#else
  sv_mem = new float[l * n_dims()];
#endif

  std::fill(sv_mem, sv_mem + l * n_dims(), (float)0);

  sv.resize(l, nullptr);
  inStream.ignore(1);
  for (int i = 0; i < l; ++i) {
    sv[i] = sv_mem + i * n_dims();
    nupic::binary_load(inStream, sv[i], sv[i] + n_dims());
  }

  for (auto &elem : sv_coef)
    delete[] elem;

  sv_coef.resize(n_class - 1, nullptr);
  for (int i = 0; i < n_class - 1; ++i) {
    sv_coef[i] = new float[l];
    for (int j = 0; j < l; ++j)
      inStream >> sv_coef[i][j];
  }

  inStream >> rho >> label >> n_sv >> probA >> probB >> w;
}

void svm_model::read(SvmModelProto::Reader &proto) {
  n_dims_ = proto.getNDims();

  if (sv_mem == nullptr) {
    for (auto &elem : sv)
      delete[] elem;
  } else {
    delete[] sv_mem;
    sv_mem = nullptr;
  }
  sv.clear();

  for (auto list : proto.getSv()) {
    size_t size = list.size();
    float *values = new float[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    sv.push_back(values);
  }

  for (auto &elem : sv_coef)
    delete[] elem;
  sv_coef.clear();

  for (auto list : proto.getSvCoef()) {
    size_t size = list.size();
    float *values = new float[size];
    for (size_t i = 0; i < size; i++) {
      values[i] = list[i];
    }
    sv_coef.push_back(values);
  }

  auto wList = proto.getW();
  size_t size = wList.size();
  w.resize(size);
  for (size_t i = 0; i < size; i++) {
    auto values = wList[i];
    size_t len = values.size();
    w[i].resize(len);
    for (size_t j = 0; j < len; j++) {
      w[i][j] = values[j];
    }
  }

  auto rhoList = proto.getRho();
  size = rhoList.size();
  rho.resize(size);
  for (size_t i = 0; i < size; i++) {
    rho[i] = rhoList[i];
  }

  auto probAList = proto.getProbA();
  size = probAList.size();
  probA.resize(size);
  for (size_t i = 0; i < size; i++) {
    probA[i] = probAList[i];
  }

  auto probBList = proto.getProbB();
  size = probBList.size();
  probB.resize(size);
  for (size_t i = 0; i < size; i++) {
    probB[i] = probBList[i];
  }

  auto labelList = proto.getLabel();
  size = labelList.size();
  label.resize(size);
  for (size_t i = 0; i < size; i++) {
    label[i] = labelList[i];
  }

  auto nsvList = proto.getNSv();
  size = nsvList.size();
  n_sv.resize(size);
  for (size_t i = 0; i < size; i++) {
    n_sv[i] = nsvList[i];
  }
}

void svm_model::write(SvmModelProto::Builder &proto) const {

  proto.setNDims(n_dims_);

  size_t size = sv.size();
  auto svList = proto.initSv(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = svList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, sv[i][j]);
    }
  }

  size = sv_coef.size();
  auto svCoefList = proto.initSvCoef(size);
  for (size_t i = 0; i < size; i++) {
    auto dims = svCoefList.init(i, n_dims_);
    for (int j = 0; j < n_dims_; j++) {
      dims.set(j, sv_coef[i][j]);
    }
  }

  size = rho.size();
  auto rhoList = proto.initRho(size);
  for (size_t i = 0; i < size; i++) {
    rhoList.set(i, rho[i]);
  }

  size = label.size();
  auto labelList = proto.initLabel(size);
  for (size_t i = 0; i < size; i++) {
    labelList.set(i, label[i]);
  }

  size = n_sv.size();
  auto nsvList = proto.initNSv(size);
  for (size_t i = 0; i < size; i++) {
    nsvList.set(i, n_sv[i]);
  }

  size = probA.size();
  auto probAList = proto.initProbA(size);
  for (size_t i = 0; i < size; i++) {
    probAList.set(i, probA[i]);
  }

  size = probB.size();
  auto probBList = proto.initProbB(size);
  for (size_t i = 0; i < size; i++) {
    probBList.set(i, probB[i]);
  }

  size = w.size();
  auto wList = proto.initW(size);
  for (size_t i = 0; i < size; i++) {
    size_t len = w[i].size();
    auto dims = wList.init(i, len);
    for (size_t j = 0; j < len; j++) {
      dims.set(j, w[i][j]);
    }
  }
}

void svm_dense::write(SvmDenseProto::Builder &proto) const {
  auto paramProto = proto.getParam();
  svm_.param_.write(paramProto);

  if (svm_.model_) {
    auto modelProto = proto.getModel();
    svm_.model_->write(modelProto);
  }
  if (svm_.problem_) {
    auto problemProto = proto.getProblem();
    svm_.problem_->write(problemProto);
  }
}

void svm_dense::read(SvmDenseProto::Reader &proto) {
  auto paramProto = proto.getParam();
  svm_.param_.read(paramProto);

  if (svm_.model_) {
    delete svm_.model_;
    svm_.model_ = nullptr;
  }
  if (proto.hasModel()) {
    auto modelProto = proto.getModel();
    svm_.model_ = new svm_model;
    svm_.model_->read(modelProto);
  }
  if (svm_.problem_) {
    delete svm_.problem_;
    svm_.problem_ = nullptr;
  }
  if (proto.hasProblem()) {
    auto problemProto = proto.getProblem();
    svm_.problem_ = new svm_problem(1, false);
    svm_.problem_->read(problemProto);
  }
}

void svm_01::write(Svm01Proto::Builder &proto) const {
  auto paramProto = proto.getParam();
  svm_.param_.write(paramProto);

  if (svm_.model_) {
    auto modelProto = proto.getModel();
    svm_.model_->write(modelProto);
  }
  if (svm_.problem_) {
    auto problemProto = proto.getProblem();
    svm_.problem_->write(problemProto);
  }
}

void svm_01::read(Svm01Proto::Reader &proto) {
  auto paramProto = proto.getParam();
  svm_.param_.read(paramProto);

  if (svm_.model_) {
    delete svm_.model_;
    svm_.model_ = nullptr;
  }
  if (proto.hasModel()) {
    auto modelProto = proto.getModel();
    svm_.model_ = new svm_model;
    svm_.model_->read(modelProto);
  }
  if (svm_.problem_) {
    delete svm_.problem_;
    svm_.problem_ = nullptr;
  }
  if (proto.hasProblem()) {
    auto problemProto = proto.getProblem();
    svm_.problem_ = new svm_problem01(1, false);
    svm_.problem_->read(problemProto);
  }
}
} // namespace svm
} // namespace algorithms
} // namespace nupic


ResourceDataSyncS3Destination::ResourceDataSyncS3Destination(JsonView jsonValue) :
    m_bucketNameHasBeenSet(false),
    m_prefixHasBeenSet(false),
    m_syncFormat(ResourceDataSyncS3Format::NOT_SET),
    m_syncFormatHasBeenSet(false),
    m_regionHasBeenSet(false),
    m_aWSKMSKeyARNHasBeenSet(false),
    m_destinationDataSharingHasBeenSet(false)

/**
 */

#include <aws/ssm/model/ResourceDataSyncS3Destination.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::Utils::Json;
using namespace Aws::Utils;

namespace Aws
{
namespace SSM
{
namespace Model
{

ResourceDataSyncS3Destination::ResourceDataSyncS3Destination() :
    m_bucketNameHasBeenSet(false),
    m_prefixHasBeenSet(false),
    m_syncFormat(ResourceDataSyncS3Format::NOT_SET),
    m_syncFormatHasBeenSet(false),
    m_regionHasBeenSet(false),
    m_aWSKMSKeyARNHasBeenSet(false),
    m_destinationDataSharingHasBeenSet(false)
{
}

{
  *this = jsonValue;
}

ResourceDataSyncS3Destination& ResourceDataSyncS3Destination::operator =(JsonView jsonValue)
{
  if(jsonValue.ValueExists("BucketName"))
  {
    m_bucketName = jsonValue.GetString("BucketName");

    m_bucketNameHasBeenSet = true;
  }

  if(jsonValue.ValueExists("Prefix"))
  {
    m_prefix = jsonValue.GetString("Prefix");

    m_prefixHasBeenSet = true;
  }

  if(jsonValue.ValueExists("SyncFormat"))
  {
    m_syncFormat = ResourceDataSyncS3FormatMapper::GetResourceDataSyncS3FormatForName(jsonValue.GetString("SyncFormat"));

    m_syncFormatHasBeenSet = true;
  }

  if(jsonValue.ValueExists("Region"))
  {
    m_region = jsonValue.GetString("Region");

    m_regionHasBeenSet = true;
  }

  if(jsonValue.ValueExists("AWSKMSKeyARN"))
  {
    m_aWSKMSKeyARN = jsonValue.GetString("AWSKMSKeyARN");

    m_aWSKMSKeyARNHasBeenSet = true;
  }

  if(jsonValue.ValueExists("DestinationDataSharing"))
  {
    m_destinationDataSharing = jsonValue.GetObject("DestinationDataSharing");

    m_destinationDataSharingHasBeenSet = true;
  }

  return *this;
}

JsonValue ResourceDataSyncS3Destination::Jsonize() const
{
  JsonValue payload;

  if(m_bucketNameHasBeenSet)
  {
   payload.WithString("BucketName", m_bucketName);

  }

  if(m_prefixHasBeenSet)
  {
   payload.WithString("Prefix", m_prefix);

  }

  if(m_syncFormatHasBeenSet)
  {
   payload.WithString("SyncFormat", ResourceDataSyncS3FormatMapper::GetNameForResourceDataSyncS3Format(m_syncFormat));
  }

  if(m_regionHasBeenSet)
  {
   payload.WithString("Region", m_region);

  }

  if(m_aWSKMSKeyARNHasBeenSet)
  {
   payload.WithString("AWSKMSKeyARN", m_aWSKMSKeyARN);

  }

  if(m_destinationDataSharingHasBeenSet)
  {
   payload.WithObject("DestinationDataSharing", m_destinationDataSharing.Jsonize());

  }

  return payload;
}

} // namespace Model
} // namespace SSM
} // namespace Aws


/**
 */

#include <aws/ssm/model/ResourceDataSyncS3Destination.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::Utils::Json;
using namespace Aws::Utils;

namespace Aws
{
namespace SSM
{
namespace Model
{

ResourceDataSyncS3Destination::ResourceDataSyncS3Destination() :
    m_bucketNameHasBeenSet(false),
    m_prefixHasBeenSet(false),
    m_syncFormat(ResourceDataSyncS3Format::NOT_SET),
    m_syncFormatHasBeenSet(false),
    m_regionHasBeenSet(false),
    m_aWSKMSKeyARNHasBeenSet(false),
    m_destinationDataSharingHasBeenSet(false)
{
}

ResourceDataSyncS3Destination::ResourceDataSyncS3Destination(JsonView jsonValue) :
    m_bucketNameHasBeenSet(false),
    m_prefixHasBeenSet(false),
    m_syncFormat(ResourceDataSyncS3Format::NOT_SET),
    m_syncFormatHasBeenSet(false),
    m_regionHasBeenSet(false),
    m_aWSKMSKeyARNHasBeenSet(false),
    m_destinationDataSharingHasBeenSet(false)

ResourceDataSyncS3Destination& ResourceDataSyncS3Destination::operator =(JsonView jsonValue)
{
  if(jsonValue.ValueExists("BucketName"))
  {
    m_bucketName = jsonValue.GetString("BucketName");

    m_bucketNameHasBeenSet = true;
  }

  if(jsonValue.ValueExists("Prefix"))
  {
    m_prefix = jsonValue.GetString("Prefix");

    m_prefixHasBeenSet = true;
  }

  if(jsonValue.ValueExists("SyncFormat"))
  {
    m_syncFormat = ResourceDataSyncS3FormatMapper::GetResourceDataSyncS3FormatForName(jsonValue.GetString("SyncFormat"));

    m_syncFormatHasBeenSet = true;
  }

  if(jsonValue.ValueExists("Region"))
  {
    m_region = jsonValue.GetString("Region");

    m_regionHasBeenSet = true;
  }

  if(jsonValue.ValueExists("AWSKMSKeyARN"))
  {
    m_aWSKMSKeyARN = jsonValue.GetString("AWSKMSKeyARN");

    m_aWSKMSKeyARNHasBeenSet = true;
  }

  if(jsonValue.ValueExists("DestinationDataSharing"))
  {
    m_destinationDataSharing = jsonValue.GetObject("DestinationDataSharing");

    m_destinationDataSharingHasBeenSet = true;
  }

  return *this;
}

JsonValue ResourceDataSyncS3Destination::Jsonize() const
{
  JsonValue payload;

  if(m_bucketNameHasBeenSet)
  {
   payload.WithString("BucketName", m_bucketName);

  }

  if(m_prefixHasBeenSet)
  {
   payload.WithString("Prefix", m_prefix);

  }

  if(m_syncFormatHasBeenSet)
  {
   payload.WithString("SyncFormat", ResourceDataSyncS3FormatMapper::GetNameForResourceDataSyncS3Format(m_syncFormat));
  }

  if(m_regionHasBeenSet)
  {
   payload.WithString("Region", m_region);

  }

  if(m_aWSKMSKeyARNHasBeenSet)
  {
   payload.WithString("AWSKMSKeyARN", m_aWSKMSKeyARN);

  }

  if(m_destinationDataSharingHasBeenSet)
  {
   payload.WithObject("DestinationDataSharing", m_destinationDataSharing.Jsonize());

  }

  return payload;
}

} // namespace Model
} // namespace SSM
} // namespace Aws


/**
 */

#include <aws/ssm/model/ResourceDataSyncS3Destination.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::Utils::Json;
using namespace Aws::Utils;

namespace Aws
{
namespace SSM
{
namespace Model
{

ResourceDataSyncS3Destination::ResourceDataSyncS3Destination() :
    m_bucketNameHasBeenSet(false),
    m_prefixHasBeenSet(false),
    m_syncFormat(ResourceDataSyncS3Format::NOT_SET),
    m_syncFormatHasBeenSet(false),
    m_regionHasBeenSet(false),
    m_aWSKMSKeyARNHasBeenSet(false),
    m_destinationDataSharingHasBeenSet(false)
{
}

ResourceDataSyncS3Destination::ResourceDataSyncS3Destination(JsonView jsonValue) :
    m_bucketNameHasBeenSet(false),
    m_prefixHasBeenSet(false),
    m_syncFormat(ResourceDataSyncS3Format::NOT_SET),
    m_syncFormatHasBeenSet(false),
    m_regionHasBeenSet(false),
    m_aWSKMSKeyARNHasBeenSet(false),
    m_destinationDataSharingHasBeenSet(false)
{

}

ResourceDataSyncS3Destination& ResourceDataSyncS3Destination::operator =(JsonView jsonValue)
{
  if(jsonValue.ValueExists("BucketName"))
  {
    m_bucketName = jsonValue.GetString("BucketName");

    m_bucketNameHasBeenSet = true;
  }

  if(jsonValue.ValueExists("Prefix"))
  {
    m_prefix = jsonValue.GetString("Prefix");

    m_prefixHasBeenSet = true;
  }

  if(jsonValue.ValueExists("SyncFormat"))
  {
    m_syncFormat = ResourceDataSyncS3FormatMapper::GetResourceDataSyncS3FormatForName(jsonValue.GetString("SyncFormat"));

    m_syncFormatHasBeenSet = true;
  }

  if(jsonValue.ValueExists("Region"))
  {
    m_region = jsonValue.GetString("Region");

    m_regionHasBeenSet = true;
  }

  if(jsonValue.ValueExists("AWSKMSKeyARN"))
  {
    m_aWSKMSKeyARN = jsonValue.GetString("AWSKMSKeyARN");

    m_aWSKMSKeyARNHasBeenSet = true;
  }

  if(jsonValue.ValueExists("DestinationDataSharing"))
  {
    m_destinationDataSharing = jsonValue.GetObject("DestinationDataSharing");

    m_destinationDataSharingHasBeenSet = true;
  }

  return *this;
}

JsonValue ResourceDataSyncS3Destination::Jsonize() const
{
  JsonValue payload;

  if(m_bucketNameHasBeenSet)
  {
   payload.WithString("BucketName", m_bucketName);

  }

  if(m_prefixHasBeenSet)
  {
   payload.WithString("Prefix", m_prefix);

  }

  if(m_syncFormatHasBeenSet)
  {
   payload.WithString("SyncFormat", ResourceDataSyncS3FormatMapper::GetNameForResourceDataSyncS3Format(m_syncFormat));
  }

  if(m_regionHasBeenSet)
  {
   payload.WithString("Region", m_region);

  }

  if(m_aWSKMSKeyARNHasBeenSet)
  {
   payload.WithString("AWSKMSKeyARN", m_aWSKMSKeyARN);

  }

  if(m_destinationDataSharingHasBeenSet)
  {
   payload.WithObject("DestinationDataSharing", m_destinationDataSharing.Jsonize());

  }

  return payload;
}

} // namespace Model
} // namespace SSM
} // namespace Aws


EXPORT char* rreplace(char* regex, char* str, char* replacement, char* result)

/*
 *
 * All rights reserved.
 *
 *
 *
 */

#include "UNIV.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <sstream>
#include <iosfwd>
#include <iomanip>
#include "pcre.h"
#include "SchemeFFI.h"
#include "SchemePrivate.h"

#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#include <AppKit/AppKit.h>
#else
#include <time.h>
#endif

#ifdef _WIN32
#include <malloc.h>
#include <Windows.h>

enum Windows_Color_Convert
{
    Black   = 0,
    Red     = FOREGROUND_RED,
    Green   = FOREGROUND_GREEN,
    Yellow  = FOREGROUND_RED   | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
    Blue    = FOREGROUND_BLUE  | FOREGROUND_INTENSITY,
    Magenta = FOREGROUND_RED   | FOREGROUND_BLUE,
    Cyan    = FOREGROUND_GREEN | FOREGROUND_BLUE,
    White   = FOREGROUND_RED   | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
};

enum Windows_BGColor_convert
{
    BGBlack   = 0,
    BGRed     = BACKGROUND_RED,
    BGGreen   = BACKGROUND_GREEN,
    BGYellow  = BACKGROUND_RED   | BACKGROUND_GREEN | BACKGROUND_INTENSITY,
    BGBlue    = BACKGROUND_BLUE,
    BGMagenta = BACKGROUND_RED   | BACKGROUND_BLUE,
    BGCyan    = BACKGROUND_GREEN | BACKGROUND_BLUE,
    BGWhite   = BACKGROUND_RED   | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY,
};

int WINDOWS_COLORS[] = { Black, Red, Green, Yellow, Blue, Magenta, Cyan, White };
int WINDOWS_BGCOLORS[] = { BGBlack, BGRed, BGGreen, BGYellow, BGBlue, BGMagenta, BGCyan, BGWhite };

#endif

static char base64_codesafe_encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
                                                'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
                                                'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
                                                'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
                                                'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
                                                'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                                                'w', 'x', 'y', 'z', '0', '1', '2', '3',
                                                '4', '5', '6', '7', '8', '9', '_', '-'};

static char base64_std_encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
                                           'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
                                           'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
                                           'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
                                           'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
                                           'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                                           'w', 'x', 'y', 'z', '0', '1', '2', '3',
                                           '4', '5', '6', '7', '8', '9', '+', '/'};

static char *base64_std_decoding_table = NULL;
static char *base64_codesafe_decoding_table = NULL;
static int _base64_mod_table[] = {0, 2, 1};

void base64_std_build_decoding_table() {

  base64_std_decoding_table = (char*) malloc(256);

    for (int i = 0; i < 64; i++)
        base64_std_decoding_table[(unsigned char) base64_std_encoding_table[i]] = i;
}

void base64_codesafe_build_decoding_table() {

  base64_codesafe_decoding_table = (char*) malloc(256);

    for (int i = 0; i < 64; i++)
        base64_codesafe_decoding_table[(unsigned char) base64_codesafe_encoding_table[i]] = i;
}

void base64_std_cleanup() {
    free(base64_std_decoding_table);
}

void base64_codesafe_cleanup() {
    free(base64_codesafe_decoding_table);
}

EXPORT char* cname_encode(char *data, size_t input_length, size_t *output_length)
{
    *output_length = 4 * ((input_length + 2) / 3);

    char *encoded_data = (char*) malloc(*output_length+1);
    encoded_data[*output_length] = 0;
    if (encoded_data == NULL) return NULL;

    for (unsigned i = 0, j = 0; i < input_length;) {

        uint32_t octet_a = i < input_length ? data[i++] : 0;
        uint32_t octet_b = i < input_length ? data[i++] : 0;
        uint32_t octet_c = i < input_length ? data[i++] : 0;

        uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;

        encoded_data[j++] = base64_codesafe_encoding_table[(triple >> 3 * 6) & 0x3F];
        encoded_data[j++] = base64_codesafe_encoding_table[(triple >> 2 * 6) & 0x3F];
        encoded_data[j++] = base64_codesafe_encoding_table[(triple >> 1 * 6) & 0x3F];
        encoded_data[j++] = base64_codesafe_encoding_table[(triple >> 0 * 6) & 0x3F];
    }

    for (int i = 0; i < _base64_mod_table[input_length % 3]; i++) {
      encoded_data[*output_length - 1 - i] = 0; //'$';
    }

    return encoded_data;
}

EXPORT char* cname_decode(char *data, size_t input_length, size_t *output_length)
{
    if (base64_codesafe_decoding_table == NULL) base64_codesafe_build_decoding_table();

    char* d2 = NULL;
    // pad with $'s
    if (input_length % 4 != 0) {
      int lgthdiff = (4-(input_length % 4));
      char* d2 = (char*) malloc(input_length+lgthdiff);
      memcpy(d2,data,input_length);
      input_length = input_length+lgthdiff;
      for(int i=0;i<lgthdiff;i++) {
        d2[input_length-1-i] = '$';
      }
      data = d2;
    }

    if (input_length % 4 != 0) return NULL;
    *output_length = input_length / 4 * 3;
    if (data[input_length - 1] == '$') (*output_length)--;
    if (data[input_length - 2] == '$') (*output_length)--;

    char *decoded_data = (char*) malloc(*output_length+1);
    decoded_data[*output_length] = 0;
    if (decoded_data == NULL) return NULL;

    for (unsigned i = 0, j = 0; i < input_length;) {

        uint32_t sextet_a = data[i] == '$' ? 0 & i++ : base64_codesafe_decoding_table[unsigned(data[i++])];
        uint32_t sextet_b = data[i] == '$' ? 0 & i++ : base64_codesafe_decoding_table[unsigned(data[i++])];
        uint32_t sextet_c = data[i] == '$' ? 0 & i++ : base64_codesafe_decoding_table[unsigned(data[i++])];
        uint32_t sextet_d = data[i] == '$' ? 0 & i++ : base64_codesafe_decoding_table[unsigned(data[i++])];

        uint32_t triple = (sextet_a << 3 * 6)
        + (sextet_b << 2 * 6)
        + (sextet_c << 1 * 6)
        + (sextet_d << 0 * 6);

        if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
        if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
        if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
    }
    if (d2) free(d2);
    return decoded_data;
}

EXPORT char* base64_encode(const unsigned char *data, size_t input_length, size_t *output_length)
{
    *output_length = 4 * ((input_length + 2) / 3);

    char *encoded_data = (char*) malloc(*output_length+1);
    encoded_data[*output_length]=0;

    if (encoded_data == NULL) return NULL;

    for (unsigned i = 0, j = 0; i < input_length;) {

        uint32_t octet_a = i < input_length ? data[i++] : 0;
        uint32_t octet_b = i < input_length ? data[i++] : 0;
        uint32_t octet_c = i < input_length ? data[i++] : 0;

        uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;

        encoded_data[j++] = base64_std_encoding_table[(triple >> 3 * 6) & 0x3F];
        encoded_data[j++] = base64_std_encoding_table[(triple >> 2 * 6) & 0x3F];
        encoded_data[j++] = base64_std_encoding_table[(triple >> 1 * 6) & 0x3F];
        encoded_data[j++] = base64_std_encoding_table[(triple >> 0 * 6) & 0x3F];
    }

    for (int i = 0; i < _base64_mod_table[input_length % 3]; i++)
        encoded_data[*output_length - 1 - i] = '=';

    return encoded_data;
}

EXPORT unsigned char* base64_decode(const char *data, size_t input_length, size_t *output_length)
{
    if (base64_std_decoding_table == NULL) base64_std_build_decoding_table();

    if (input_length % 4 != 0) return NULL;

    *output_length = input_length / 4 * 3;
    if (data[input_length - 1] == '=') (*output_length)--;
    if (data[input_length - 2] == '=') (*output_length)--;

    unsigned char *decoded_data = (unsigned char*) malloc(*output_length);
    if (decoded_data == NULL) return NULL;

    for (unsigned i = 0, j = 0; i < input_length;) {

        uint32_t sextet_a = data[i] == '=' ? 0 & i++ : base64_std_decoding_table[unsigned(data[i++])];
        uint32_t sextet_b = data[i] == '=' ? 0 & i++ : base64_std_decoding_table[unsigned(data[i++])];
        uint32_t sextet_c = data[i] == '=' ? 0 & i++ : base64_std_decoding_table[unsigned(data[i++])];
        uint32_t sextet_d = data[i] == '=' ? 0 & i++ : base64_std_decoding_table[unsigned(data[i++])];

        uint32_t triple = (sextet_a << 3 * 6)
        + (sextet_b << 2 * 6)
        + (sextet_c << 1 * 6)
        + (sextet_d << 0 * 6);

        if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
        if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
        if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
    }

    return decoded_data;
}

EXPORT bool rmatch(char* regex, const char* str)
{
  const char* data = str;
  char* pattern = regex;

  pcre *re;
  const char *error;
  int erroffset;

  re = pcre_compile(    pattern, /* the pattern */
                        0, /* default options */
                        &error, /* for error message */
                        &erroffset, /* for error offset */
                        NULL); /* use default character tables */

  int rc;
  int ovector[30];
  rc = pcre_exec(       re, /* result of pcre_compile() */
                        NULL, /* we didn’t study the pattern */
                        data, /* the subject string */
                        strlen(data), /* the length of the subject string */
                        0, /* start at offset 0 in the subject */
                        0, /* default options */
                        ovector, /* vector of integers for substring information */
                        30); /* number of elements (NOT size in bytes) */

  return (rc>=0) ? true : false;
}

//      rc = pcre_exec( re, /* result of pcre_compile() */
//                      NULL, /* we didn’t study the pattern */
//                      data, /* the subject string */
//                      strlen(data), /* the length of the subject string */
//                      0, /* start at offset 0 in the subject */
//                      60); /* number of elements (NOT size in bytes) */

//      // if failed to match return empty list

EXPORT int64_t rmatches(char* regex, char* str, char** results, int64_t maxnum)
    {
  char* data = str;
  char* pattern = regex;
        pcre *re;
        const char *error;
        int erroffset;
        re = pcre_compile(      pattern, /* the pattern */
                                0, /* default options */
                                &error, /* for error message */
                                &erroffset, /* for error offset */
                                NULL); /* use default character tables */

        // pointer to hold return results
        int rc;
        int ovector[60];
  int64_t num=0;

        while(true) {
            rc = pcre_exec(     re, /* result of pcre_compile() */
                                NULL, /* we didn’t study the pattern */
                                data, /* the subject string */
                                strlen(data), /* the length of the subject string */
                                0, /* start at offset 0 in the subject */
                                0, /* default options */
                                ovector, /* vector of integers for substring information */
                                60); /* number of elements (NOT size in bytes) */

            if(rc<1 || num>=maxnum) {
        return num;
            }
            int range = ovector[1] - ovector[0];
            char* b = (char*) alloca(range+1);
            b[range] = '\0';
            char* a = data+ovector[0];
            char* substring = strncpy(b, a, range);
      char* tmp = (char*) malloc(range+1);
      tmp[range] = '\0';
      strncpy(tmp,substring,range);
      results[num]=tmp;
      num++;
            data = data+range+ovector[0];
        }
  return 0;
}

EXPORT bool rsplit(const char* regex, const char* str, char* a, char* b)
{ // TODO: harmonize with FFI
  int length = strlen(str);
  pcre *re;
  const char *error;
  int erroffset;
  // should probably move this regex compile to global
  re = pcre_compile(    regex, /* the regex */
                        0, /* default options */
                        &error, /* for error message */
                        &erroffset, /* for error offset */
                        NULL); /* use default character tables */
  int rc;
  int ovector[60];
  rc = pcre_exec(       re, /* result of pcre_compile() */
                        NULL, /* we didn’t study the regex */
                        str, /* the subject string */
                        strlen(str), /* the length of the subject string */
                        0, /* start at offset 0 in the subject */
                        0, /* default options */
                        ovector, /* vector of integers for substring information */
                        60); /* number of elements (NOT size in bytes) */

  if(rc<1 || rc>1) return false; // then we failed
  int range = ovector[0];
  int range2 = ovector[1];
  a[range] = '\0';;
  memcpy(a, str, range);
  b[length - range2] = '\0';
  memcpy(b, str + range2, length - range2);
  return true;
}

{

  char* data = str; //string_value(pair_car(args));
        char* pattern = regex; //string_value(pair_cadr(args));
  char* replace = replacement;

        pcre *re;
        const char *error;
        int erroffset;
        re = pcre_compile(      pattern, /* the pattern */
                                0, /* default options */
                                &error, /* for error message */
                                &erroffset, /* for error offset */
                                NULL); /* use default character tables */

        int rc;
        int ovector[60];

        rc = pcre_exec( re, /* result of pcre_compile() */
                        NULL, /* we didn’t study the pattern */
                        data, /* the subject string */
                        strlen(data), /* the length of the subject string */
                        0, /* start at offset 0 in the subject */
                        0, /* default options */
                        ovector, /* vector of integers for substring information */
                        60); /* number of elements (NOT size in bytes) */

        // no match found return original string
        if(rc<1) {strcpy(result,str); return result;} // Return mk_string(_sc,data);
        // ok we have a match
        // first replace any groups in replace string (i.e. $1 $2 ...)
        char* res = (char*) "";
        char* sep = (char*) "$";
        char* tmp = 0;
  int datalength = strlen(data);
        int pos,range,size,cnt = 0;
  strcpy(result,replace);
        char* p = strtok(result,sep);
  if(p==NULL) { strcpy(result, str); return result; };
        do{
            char* cc;
            pos = strtol(p,&cc,10);
            range = (pos>0 && pos<20) ? ovector[(pos*2)+1] - ovector[pos*2] : 0;
      if(pos>=rc || range < 0 || range > datalength) {
        range = 0;
        cc = p;
      }
            size = strlen(res);
            tmp = (char*) alloca(size+range+strlen(cc)+1);
            tmp[size+range+strlen(cc)] = '\0';
            memcpy(tmp,res,size);
            memcpy(tmp+size,data+ovector[pos*2],range);
            memcpy(tmp+size+range,cc,strlen(cc));
            res = tmp;
            p = strtok(NULL, sep);
      cnt++;
        }while(p);
        // now we can use "rep" to replace the original regex match (i.e. ovector[0]-ovector[1])
        int lgth = ovector[0] + strlen(res) + strlen(data) - ovector[1] + 1;
        range = ovector[1] - ovector[0];
        if(lgth>4096) return str;
        result[lgth - 1] = '\0'; // TODO: lots of this can be simplified
        memcpy(result,data,ovector[0]);
        memcpy(result+ovector[0],res,strlen(res));
        memcpy(result+ovector[0]+strlen(res),data+ovector[1],strlen(data)-ovector[1]);
        return result;
}

EXPORT const char* sys_sharedir(){
  return extemp::UNIV::SHARE_DIR.c_str();
}

EXPORT char* sys_slurp_file(const char* fname)
{
    std::string filename(fname);
    std::string sharedir_filename(extemp::UNIV::SHARE_DIR + "/" + filename);

    // check raw path first, then prepend SHARE_DIR
    std::FILE *fp = std::fopen(filename.c_str(), "rb");
    if (!fp) {
      fp = std::fopen(sharedir_filename.c_str(), "rb");
    }

  if(fp){
    std::fseek(fp, 0, SEEK_END);
    size_t file_size = std::ftell(fp);
    char* buf = (char*)malloc(file_size*sizeof(char));
    std::rewind(fp);
    std::fread(buf, 1, file_size, fp);
    std::fclose(fp);

    buf[file_size-1] = '\0';
    return buf;
  }
  return NULL;
}

EXPORT int register_for_window_events()
{
#ifdef __APPLE__
  // to give Extempore it's own dock icon, etc
  return (int)[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
#else
  // implement the required "receive events" functionality for Linux
  // or Windows if necessary
  return 1;
#endif
}

namespace extemp
{

namespace UNIV
{

std::string SHARE_DIR = std::string(EXT_SHARE_DIR);
uint32_t NUM_FRAMES = 1024;
uint32_t CHANNELS = 2;
uint32_t IN_CHANNELS = 0;
uint32_t SAMPLE_RATE = 44100;
volatile uint64_t TIME = 0l;
uint64_t DEVICE_TIME = 0l;
double AUDIO_CLOCK_NOW = 0.0;
double AUDIO_CLOCK_BASE = 0.0;
uint64_t TIME_DIVISION = 1;
bool AUDIO_NONE = false;
uint32_t AUDIO_DEVICE = -1;
uint32_t AUDIO_IN_DEVICE = -1;
std::string AUDIO_DEVICE_NAME;
std::string AUDIO_IN_DEVICE_NAME;
double AUDIO_OUTPUT_LATENCY = 0.0;
double CLOCK_OFFSET = 0.0;
std::unordered_map<std::string, std::string> CMDPARAMS;
std::string ARCH;
std::string CPU;
std::vector<std::string> ATTRS;

// 0 is for ansi, 1 is for MSDos CMD shell
#ifdef _WIN32
uint32_t EXT_TERM = 1;
#else
uint32_t EXT_TERM = 0;
#endif
bool EXT_LOADBASE = true;

double midi2frq(double pitch)
{
    return 220.0 * pow(2.0,(pitch - 57.0)/12);
}

double frqRatio(double semitones)
{
    return pow(2.0, (semitones/12.0));
}

bool file_check(const std::string& filename)
{
    FILE* fd = fopen(filename.c_str(),"r");
    if(fd == NULL){
        return false;
    }else{
        fclose(fd);
        return true;
    }
}

struct dump_stack_frame {
    int op;
    pointer args;
    pointer envir;
    pointer code;
};

void printSchemeCell(scheme* _sc, std::stringstream& ss, pointer val, bool full, bool stringquotes)
{
    if(val == 0) {
        ss << "-ERROR BAD POINTER-";
        return;
    }
    if (pointer_type(val) > T_LAST_SYSTEM_TYPE) {
        printf("Bad cell type - not printing\n");
        return;
    }

    if(is_string(val)) {
        if(stringquotes) {
            ss << "\"" << string_value(val) << "\"";
        }else{
            ss << string_value(val);
        }
    }else if(is_symbol(val)){
        ss << symname(val);
    }else if(is_character(val)){
        ss << charvalue(val);
    }else if(is_environment(val)){
        ss << "#<ENVIRONMENT " << val << " ";
        if(full) {
            if(is_vector(val->_object._cons._car)) {
                ss << "<VECTOR-FRAME>";
            }else{
                printSchemeCell(_sc, ss, val->_object._cons._car, full, stringquotes);
            }
            ss << " ";
            printSchemeCell(_sc, ss, val->_object._cons._cdr, full, stringquotes);
        }
        ss << ">";
    }else if(is_proc(val)){
        ss << "#<PROC " << procname(val) << ">";
    }else if(is_foreign(val)){
        ss << "#<FOREIGN>";
    }else if(is_macro(val)){
        ss << "#<MACRO>";
    }else if(is_closure(val)){
        ss << "#<<CLOSURE " << val << ">";
        if(full) {
            ss << "<CODE ";
            printSchemeCell(_sc, ss, val->_object._cons._car, full, stringquotes);
            ss << "> ";
            printSchemeCell(_sc, ss, val->_object._cons._cdr, full, stringquotes);
            ss << ">>";
        }
    }else if(is_continuation(val)){
        ss << "#<<CONTINUATION " << val << ">";
        if(full) {
            unsigned int* stack = (unsigned int*) cptr_value(pair_cdr(val));
            int nframes = stack[0];
            dump_stack_frame* frames = (dump_stack_frame*)&stack[1];
            for(int j=0;j<nframes;j++)
            {
                ss << std::endl << std::endl << "FRAME(" << j << ")--------------------------";
                ss << std::endl << "OPCODE: " << frames[j].op; // << std::endl << "----------" << std::endl;

                // print args
                ss << std::endl << "ARGS: ";
                pointer args = frames[j].args;
                extemp::UNIV::printSchemeCell(_sc, ss, args, true, stringquotes);

                // copy code
                ss << std::endl << "CODE: ";
                pointer code = frames[j].code;
                extemp::UNIV::printSchemeCell(_sc, ss, code, true, stringquotes);

                ss << std::endl << "ENVIR: ";
                pointer envir = frames[j].envir;
                extemp::UNIV::printSchemeCell(_sc, ss, envir, true, stringquotes);
            }
        }
        ss << std::endl << ">>";
    }else if(is_cptr(val)){
        void* p = cptr_value(val);
        ss << "#<CPTR: " << p << ">";
    }else if(is_vector(val)){
        if(true) {
            ss << "#(";
            int i;
            long long num=val->_size;//  /2+ivalue_unchecked(val)%2;
            if(num > 1000 && !full) { // exit if larger than 1000 elements
                ss << " -- " << num << " elements -- )";
                return;
            }
            for(i=0; i<num; i++) {
                /* Vector cells will be treated like ordinary cells */
                printSchemeCell(_sc, ss, vector_elem(val,i), full, stringquotes);
                if(i+1 < num) ss << " ";
            }
            ss << ")";
        }
    }else if(is_port(val)){
        ss << "#<PORT" << val << ">";
    }else if(is_pair(val)){
        int lgth = list_length(_sc, val);
        if(lgth<0) // is pair
        {
            ss << "(";
            printSchemeCell(_sc, ss, val->_object._cons._car, full, stringquotes);
            ss << " . ";
            printSchemeCell(_sc, ss, val->_object._cons._cdr, full, stringquotes);
            ss << ")";
        }else if(lgth>1000 && !full) {
            ss << "( -- " << lgth << " elements -- )";
            return;
        }else{ // is list
            ss << "(";
            for(int i=0;i<lgth;i++)
            {
                printSchemeCell(_sc, ss, list_ref(_sc, i, val), full, stringquotes);
                if(i<(lgth-1)) ss << " ";
            }
            ss << ")";
        }
    }else if(is_foreign(val)){
        ss << "#<FOREIGN FUNC>";
    }else if(val == _sc->NIL){
        if(full) {
            ss << "()";
        }else{
            ss << "NIL";
        }
    }else if(_sc->T == val){
        ss << "#t";
    }else if(_sc->F == val){
        ss << "#f";
    }else if(is_integer(val)){
        ss << ivalue(val);
    }else if(is_rational(val)){
        ss << val->_object._number.value.ratvalue.n << "/" << val->_object._number.value.ratvalue.d;
    }else if(is_real(val)){
        if(full){
            ss << std::fixed << std::showpoint << std::setprecision(23) << rvalue(val);
        }else{
            ss << std::fixed << std::showpoint << /* << std::setprecision(15) <<*/ rvalue(val);
        }
    }else if(_sc->EOF_OBJ == val){
      ss << "#<EOF>";
    }else{
        ss << "UNKOWN VALUE: " << val << " (GC'd?) ";
    }

    return;
}

}

} //End Namespace