<commit_before>#include <cmath>
#include <stdexcept>
#include <algorithm>
#include <Eigen/Core>
#include <Eigen/QR>

#include <iostream>
#include <fstream>

template <
  class Scalar = double,
  class Index = ptrdiff_t,
  Index _NumCoefficients = Eigen::Dynamic,
  Index _NumOutputs = Eigen::Dynamic,
  Index _NumKnots = Eigen::Dynamic>
class SplineProblem {
public:
  static constexpr Index _NumSegments
    = (_NumKnots != Eigen::Dynamic) ? (_NumKnots - 1) : Eigen::Dynamic;
  static constexpr Index _Dimension
    = (_NumSegments != Eigen::Dynamic && _NumCoefficients != Eigen::Dynamic)
      ? (_NumSegments * _NumCoefficients) : Eigen::Dynamic;

  using TimeVector = Eigen::Matrix<Scalar, _NumKnots, 1>;
  using OutputVector = Eigen::Matrix<Scalar, _NumOutputs, 1>;
  using OutputMatrix = Eigen::Matrix<Scalar, _NumCoefficients, _NumOutputs>;
  using CoefficientVector = Eigen::Matrix<Scalar, _NumCoefficients, 1>;
  using CoefficientMatrix = Eigen::Matrix<Scalar, _NumCoefficients, _NumCoefficients>;

  explicit SplineProblem(const TimeVector& _times);
  SplineProblem(const TimeVector& _times, Index _numCoefficients, Index _numOutputs);

  CoefficientVector createTimeVector(Scalar _t, Index _i) const;
  CoefficientMatrix createTimeMatrix(Scalar _t) const;
  CoefficientMatrix createCoefficientMatrix() const;

  void addConstantConstraint(Index _knot, Index _derivative, const OutputVector& _value);
  void addContinuityConstraint(Index _knot, Index _derivative);

  void fit();
  Index getSegmentIndex(Scalar _t) const;
  OutputVector interpolate(Scalar _t, Index _derivative) const;

//private:
  using SolutionMatrix = Eigen::Matrix<Scalar, _NumOutputs, _NumCoefficients>;

  Index mNumKnots;
  Index mNumSegments;
  Index mNumCoefficients;
  Index mNumOutputs;
  Index mDimension;

  Eigen::Matrix<Scalar, _NumCoefficients, _NumCoefficients> mCoefficientMatrix;

  Index mRowIndex;
  TimeVector mTimes;
  Eigen::Matrix<Scalar, _Dimension, _Dimension> mA;
  Eigen::Matrix<Scalar, _Dimension, _NumOutputs> mB;

  std::vector<SolutionMatrix> mSolution; // length _NumSegments
};

// ---

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::SplineProblem(const TimeVector& _times)
    : SplineProblem(_times, _NumCoefficients, _NumOutputs)
{
  static_assert(_NumCoefficients != Eigen::Dynamic,
    "_NumOutputs must be static to use this constructor.");
  static_assert(_NumOutputs != Eigen::Dynamic,
    "_NumOutputs must be static to use this constructor.");
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::SplineProblem(const TimeVector& _times, Index _numCoefficients, Index _numOutputs)
    : mNumKnots(_times.size()),
      mNumSegments(std::max<Index>(mNumKnots - 1, 0)),
      mNumCoefficients(_numCoefficients),
      mNumOutputs(_numOutputs),
      mDimension(mNumSegments * _numCoefficients),
      mCoefficientMatrix(createCoefficientMatrix()),
      mRowIndex(0),
      mTimes(_times),
      mA(mDimension, mDimension),
      mB(mDimension, _numOutputs),
      mSolution(mNumSegments, SolutionMatrix(_numOutputs, _numCoefficients))
{
  mA.setZero();
  mB.setZero();

  std::cout << "\n\n"
            << "mNumKnots = " << mNumKnots << "\n"
            << "mNumSegments = " << mNumSegments << "\n"
            << "mNumCoefficients = " << mNumCoefficients << "\n"
            << "mNumOutputs = " << mNumOutputs << "\n"
            << "mDimension = " << mDimension << "\n"
            << "\n\n"
            << std::flush;

  if (!std::is_sorted(mTimes.data(), mTimes.data() + mTimes.size())) {
    throw std::runtime_error("Times are not monotonically increasing.");
  }
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
void SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::addConstantConstraint(
    Index _knot, Index _derivative, const OutputVector& _value)
{
  assert(0 <= _knot && _knot < mNumKnots);
  assert(0 <= _derivative && _derivative < mNumCoefficients);
  assert(_value.size() == mNumOutputs);

  const CoefficientVector timeVector = createTimeVector(mTimes[_knot], _derivative);
  const CoefficientVector derivativeVector = mCoefficientMatrix.row(_derivative);
  const CoefficientVector coeffVector = derivativeVector.cwiseProduct(timeVector);

  // Position constraint on segment before this knot.
  if (_knot > 0) {
    assert(mRowIndex < mDimension);

    mA.block(mRowIndex, (_knot - 1) * mNumCoefficients, 1, mNumCoefficients)
      = coeffVector.transpose();
    mB.row(mRowIndex) = _value;

    ++mRowIndex;
  }

  // Position constraint on segment after this knot.
  if (_knot + 1 < mNumKnots) {
    assert(mRowIndex < mDimension);

    mA.block(mRowIndex, _knot * mNumCoefficients, 1, mNumCoefficients)
      = coeffVector.transpose();
    mB.row(mRowIndex) = _value;

    ++mRowIndex;
  }
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
void SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::addContinuityConstraint(Index _knot, Index _derivative)
{
  assert(0 <= _knot && _knot < mNumKnots);
  assert(_knot != 0 && _knot + 1 != mNumKnots);
  assert(0 <= _derivative && _derivative < mNumCoefficients);
  assert(mRowIndex < mDimension);

  const CoefficientVector derivativeVector = mCoefficientMatrix.row(_derivative);
  const CoefficientVector timeVector = createTimeVector(mTimes[_knot], _derivative);
  const CoefficientVector coeffVector = derivativeVector.cwiseProduct(timeVector);

  mA.block(mRowIndex, (_knot - 1) * mNumCoefficients, 1, mNumCoefficients)
    = coeffVector.transpose();
  mA.block(mRowIndex,  _knot      * mNumCoefficients, 1, mNumCoefficients)
    = -coeffVector.transpose();
  mB.row(mRowIndex).setZero();

  ++mRowIndex;
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
auto SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::createTimeVector(Scalar _t, Index _i) const -> CoefficientVector
{
  CoefficientVector exponents(mNumCoefficients);

  for (Index j = 0; j < mNumCoefficients; ++j) {
    if (j > _i) {
      exponents[j] = std::pow(_t, j - _i);
    } else if (j == _i) {
      exponents[j] = 1;
    } else {
      exponents[j] = 0;
    }
  }

  return exponents;
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
void SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::fit()
{
  std::cout << "!!! " << mRowIndex << " ?= " << mDimension << std::endl;
  assert(mRowIndex == mDimension);

  using MatrixType = Eigen::Matrix<Scalar, _Dimension, _Dimension>;

  // Perform the QR decomposition once.
  Eigen::HouseholderQR<MatrixType> solver = mA.householderQr();

  for (Index ioutput = 0; ioutput < mNumOutputs; ++ioutput) {
    // Solve for the spline coefficients for each output dimension.
    Eigen::Matrix<Scalar, _Dimension, 1> solutionVector
      = solver.solve(mB.col(ioutput));

    // Split the coefficients by segment.
    for (Index isegment = 0; isegment < mNumSegments; ++isegment) {
      SolutionMatrix& solutionMatrix = mSolution[isegment];
      solutionMatrix.row(ioutput) = solutionVector.segment(
        isegment * mNumCoefficients, mNumCoefficients);
    }
  }
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
auto SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::createCoefficientMatrix() const -> CoefficientMatrix
{
  CoefficientMatrix coefficients(mNumCoefficients, mNumCoefficients);
  coefficients.setZero();

  if (mNumCoefficients > 0) {
    coefficients.row(0).setOnes();
  }

  for (Index i = 1; i < mNumCoefficients; ++i) {
    for (Index j = i; j < mNumCoefficients; ++j) {
      coefficients(i, j) = (j - i + 1) * coefficients(i - 1, j);
    }
  }
  return coefficients;
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
auto SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::getSegmentIndex(Scalar _t) const -> Index
{
  if (_t <= mTimes[0]) {
    return 0;
  } else if (_t >= mTimes[mNumKnots - 1]) {
    return mNumSegments - 1;
  } else {
    auto it = std::lower_bound(mTimes.data(), mTimes.data() + mTimes.size(), _t);
    return it - mTimes.data() - 1;
  }
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
auto SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::interpolate(Scalar _t, Index _derivative) const -> OutputVector
{
  const CoefficientVector timeVector = createTimeVector(_t, _derivative);
  const CoefficientVector derivativeVector = mCoefficientMatrix.row(_derivative);
  const CoefficientVector evaluationVector = derivativeVector.cwiseProduct(timeVector);
  const Index segmentIndex = getSegmentIndex(_t);
  const SolutionMatrix& solutionMatrix = mSolution[segmentIndex];

  OutputVector output(mNumOutputs);

  for (Index ioutput = 0; ioutput < mNumOutputs; ++ioutput) {
    const CoefficientVector solutionVector = solutionMatrix.row(ioutput);
    output[ioutput] = evaluationVector.dot(solutionVector);
  }

  return output;
}

// ---

int main(int argc, char **argv)
{
  using Eigen::VectorXd;

  using Vector1d = Eigen::Matrix<double, 1, 1>;

  auto Value = [](double x, double y) {
    Eigen::Matrix<double, 2, 1> v;
    v << x, y;
    return v;
  };

  VectorXd times(3);
  times << 0, 1, 3;

  //SplineProblem<double, ptrdiff_t, 4, 2, 3> problem(times, 4, 2);
  SplineProblem<double, ptrdiff_t, 4, 2, 3> problem(times);
  problem.addConstantConstraint(0, 1, Value(0, 0));
  problem.addConstantConstraint(0, 0, Value(5, 7));
  problem.addConstantConstraint(1, 0, Value(6, 8));
  problem.addContinuityConstraint(1, 1);
  problem.addContinuityConstraint(1, 2);
  problem.addConstantConstraint(2, 0, Value(0, 2));
  problem.addConstantConstraint(2, 1, Value(0, 0));
  problem.fit();

  std::cout << "A =\n" << problem.mA << "\n\n";
  std::cout << "b =\n" << problem.mB.transpose() << "\n\n";
  for (int i = 0; i < problem.mSolution.size(); ++i) {
    std::cout << "x =\n" << problem.mSolution[i] << "\n\n";
  }

  std::ofstream csv("/tmp/data.csv", std::ios::binary);
  std::cout << "\n\n";
  for (double t = times[0]; t <= times[times.size() - 1] + 1e-3; t += 0.05) {
    csv << t << '\t' << problem.interpolate(t, 0).transpose() << '\t' << problem.getSegmentIndex(t) << '\n';
  }

  return 0;
}
<commit_msg>Cleaned up typedefs.<commit_after>#include <cmath>
#include <stdexcept>
#include <algorithm>
#include <Eigen/Core>
#include <Eigen/QR>

#include <iostream>
#include <fstream>

template <
  class _Scalar = double,
  class _Index = ptrdiff_t,
  _Index _NumCoefficients = Eigen::Dynamic,
  _Index _NumOutputs = Eigen::Dynamic,
  _Index _NumKnots = Eigen::Dynamic>
class SplineProblem {
public:
  using Scalar = _Scalar;
  using Index = _Index;

  static constexpr Index NumCoefficientsAtCompileTime = _NumCoefficients;
  static constexpr Index NumOutputsAtCompileTime = _NumOutputs;
  static constexpr Index NumKnotsAtCompileTime= _NumKnots;
  static constexpr Index NumSegmentsAtCompileTime
    = (_NumKnots != Eigen::Dynamic)
      ? (NumKnotsAtCompileTime - 1)
      : Eigen::Dynamic;
  static constexpr Index DimensionAtCompileTime
    = (NumSegmentsAtCompileTime != Eigen::Dynamic && _NumCoefficients != Eigen::Dynamic)
      ? (NumSegmentsAtCompileTime * NumCoefficientsAtCompileTime)
      : Eigen::Dynamic;

  using TimeVector = Eigen::Matrix<Scalar, NumKnotsAtCompileTime, 1>;
  using OutputVector = Eigen::Matrix<Scalar, NumOutputsAtCompileTime, 1>;
  using OutputMatrix = Eigen::Matrix<Scalar, NumCoefficientsAtCompileTime, NumOutputsAtCompileTime>;
  using CoefficientVector = Eigen::Matrix<Scalar, NumCoefficientsAtCompileTime, 1>;
  using CoefficientMatrix = Eigen::Matrix<Scalar, NumCoefficientsAtCompileTime, NumCoefficientsAtCompileTime>;

  explicit SplineProblem(const TimeVector& _times);
  SplineProblem(const TimeVector& _times, Index _numCoefficients, Index _numOutputs);

  CoefficientVector createTimeVector(Scalar _t, Index _i) const;
  CoefficientMatrix createTimeMatrix(Scalar _t) const;
  CoefficientMatrix createCoefficientMatrix() const;

  void addConstantConstraint(Index _knot, Index _derivative, const OutputVector& _value);
  void addContinuityConstraint(Index _knot, Index _derivative);

  void fit();
  Index getSegmentIndex(Scalar _t) const;
  OutputVector interpolate(Scalar _t, Index _derivative) const;

//private:
  using SolutionMatrix = Eigen::Matrix<Scalar, NumOutputsAtCompileTime, NumCoefficientsAtCompileTime>;

  Index mNumKnots;
  Index mNumSegments;
  Index mNumCoefficients;
  Index mNumOutputs;
  Index mDimension;

  Eigen::Matrix<Scalar, _NumCoefficients, _NumCoefficients> mCoefficientMatrix;

  Index mRowIndex;
  TimeVector mTimes;
  Eigen::Matrix<Scalar, DimensionAtCompileTime, DimensionAtCompileTime> mA;
  Eigen::Matrix<Scalar, DimensionAtCompileTime, NumOutputsAtCompileTime> mB;

  std::vector<SolutionMatrix> mSolution; // length _NumSegments
};

// ---

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::SplineProblem(const TimeVector& _times)
    : SplineProblem(_times, NumCoefficientsAtCompileTime, NumOutputsAtCompileTime)
{
  static_assert(NumCoefficientsAtCompileTime != Eigen::Dynamic,
    "NumCoefficientsAtCompileTime must be static to use this constructor.");
  static_assert(NumOutputsAtCompileTime != Eigen::Dynamic,
    "NumOutputsAtCompileTime must be static to use this constructor.");
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::SplineProblem(const TimeVector& _times, Index _numCoefficients, Index _numOutputs)
    : mNumKnots(_times.size()),
      mNumSegments(std::max<Index>(mNumKnots - 1, 0)),
      mNumCoefficients(_numCoefficients),
      mNumOutputs(_numOutputs),
      mDimension(mNumSegments * _numCoefficients),
      mCoefficientMatrix(createCoefficientMatrix()),
      mRowIndex(0),
      mTimes(_times),
      mA(mDimension, mDimension),
      mB(mDimension, _numOutputs),
      mSolution(mNumSegments, SolutionMatrix(_numOutputs, _numCoefficients))
{
  mA.setZero();
  mB.setZero();

  std::cout << "\n\n"
            << "mNumKnots = " << mNumKnots << "\n"
            << "mNumSegments = " << mNumSegments << "\n"
            << "mNumCoefficients = " << mNumCoefficients << "\n"
            << "mNumOutputs = " << mNumOutputs << "\n"
            << "mDimension = " << mDimension << "\n"
            << "\n\n"
            << std::flush;

  if (!std::is_sorted(mTimes.data(), mTimes.data() + mTimes.size())) {
    throw std::runtime_error("Times are not monotonically increasing.");
  }
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
void SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::addConstantConstraint(
    Index _knot, Index _derivative, const OutputVector& _value)
{
  assert(0 <= _knot && _knot < mNumKnots);
  assert(0 <= _derivative && _derivative < mNumCoefficients);
  assert(_value.size() == mNumOutputs);

  const CoefficientVector timeVector = createTimeVector(mTimes[_knot], _derivative);
  const CoefficientVector derivativeVector = mCoefficientMatrix.row(_derivative);
  const CoefficientVector coeffVector = derivativeVector.cwiseProduct(timeVector);

  // Position constraint on segment before this knot.
  if (_knot > 0) {
    assert(mRowIndex < mDimension);

    mA.block(mRowIndex, (_knot - 1) * mNumCoefficients, 1, mNumCoefficients)
      = coeffVector.transpose();
    mB.row(mRowIndex) = _value;

    ++mRowIndex;
  }

  // Position constraint on segment after this knot.
  if (_knot + 1 < mNumKnots) {
    assert(mRowIndex < mDimension);

    mA.block(mRowIndex, _knot * mNumCoefficients, 1, mNumCoefficients)
      = coeffVector.transpose();
    mB.row(mRowIndex) = _value;

    ++mRowIndex;
  }
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
void SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::addContinuityConstraint(Index _knot, Index _derivative)
{
  assert(0 <= _knot && _knot < mNumKnots);
  assert(_knot != 0 && _knot + 1 != mNumKnots);
  assert(0 <= _derivative && _derivative < mNumCoefficients);
  assert(mRowIndex < mDimension);

  const CoefficientVector derivativeVector = mCoefficientMatrix.row(_derivative);
  const CoefficientVector timeVector = createTimeVector(mTimes[_knot], _derivative);
  const CoefficientVector coeffVector = derivativeVector.cwiseProduct(timeVector);

  mA.block(mRowIndex, (_knot - 1) * mNumCoefficients, 1, mNumCoefficients)
    = coeffVector.transpose();
  mA.block(mRowIndex,  _knot      * mNumCoefficients, 1, mNumCoefficients)
    = -coeffVector.transpose();
  mB.row(mRowIndex).setZero();

  ++mRowIndex;
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
auto SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::createTimeVector(Scalar _t, Index _i) const -> CoefficientVector
{
  CoefficientVector exponents(mNumCoefficients);

  for (Index j = 0; j < mNumCoefficients; ++j) {
    if (j > _i) {
      exponents[j] = std::pow(_t, j - _i);
    } else if (j == _i) {
      exponents[j] = 1;
    } else {
      exponents[j] = 0;
    }
  }

  return exponents;
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
void SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::fit()
{
  std::cout << "!!! " << mRowIndex << " ?= " << mDimension << std::endl;
  assert(mRowIndex == mDimension);

  using MatrixType = Eigen::Matrix<Scalar, DimensionAtCompileTime, DimensionAtCompileTime>;

  // Perform the QR decomposition once.
  Eigen::HouseholderQR<MatrixType> solver = mA.householderQr();

  for (Index ioutput = 0; ioutput < mNumOutputs; ++ioutput) {
    // Solve for the spline coefficients for each output dimension.
    Eigen::Matrix<Scalar, DimensionAtCompileTime, 1> solutionVector
      = solver.solve(mB.col(ioutput));

    // Split the coefficients by segment.
    for (Index isegment = 0; isegment < mNumSegments; ++isegment) {
      SolutionMatrix& solutionMatrix = mSolution[isegment];
      solutionMatrix.row(ioutput) = solutionVector.segment(
        isegment * mNumCoefficients, mNumCoefficients);
    }
  }
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
auto SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::createCoefficientMatrix() const -> CoefficientMatrix
{
  CoefficientMatrix coefficients(mNumCoefficients, mNumCoefficients);
  coefficients.setZero();

  if (mNumCoefficients > 0) {
    coefficients.row(0).setOnes();
  }

  for (Index i = 1; i < mNumCoefficients; ++i) {
    for (Index j = i; j < mNumCoefficients; ++j) {
      coefficients(i, j) = (j - i + 1) * coefficients(i - 1, j);
    }
  }
  return coefficients;
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
auto SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::getSegmentIndex(Scalar _t) const -> Index
{
  if (_t <= mTimes[0]) {
    return 0;
  } else if (_t >= mTimes[mNumKnots - 1]) {
    return mNumSegments - 1;
  } else {
    auto it = std::lower_bound(mTimes.data(), mTimes.data() + mTimes.size(), _t);
    return it - mTimes.data() - 1;
  }
}

template <
  class Scalar, class Index,
  Index _NumCoefficients, Index _NumOutputs, Index _NumKnots>
auto SplineProblem<Scalar, Index, _NumCoefficients, _NumOutputs, _NumKnots>
  ::interpolate(Scalar _t, Index _derivative) const -> OutputVector
{
  const CoefficientVector timeVector = createTimeVector(_t, _derivative);
  const CoefficientVector derivativeVector = mCoefficientMatrix.row(_derivative);
  const CoefficientVector evaluationVector = derivativeVector.cwiseProduct(timeVector);
  const Index segmentIndex = getSegmentIndex(_t);
  const SolutionMatrix& solutionMatrix = mSolution[segmentIndex];

  OutputVector output(mNumOutputs);

  for (Index ioutput = 0; ioutput < mNumOutputs; ++ioutput) {
    const CoefficientVector solutionVector = solutionMatrix.row(ioutput);
    output[ioutput] = evaluationVector.dot(solutionVector);
  }

  return output;
}

// ---

int main(int argc, char **argv)
{
  using Eigen::VectorXd;

  using Vector1d = Eigen::Matrix<double, 1, 1>;

  auto Value = [](double x, double y) {
    Eigen::Matrix<double, 2, 1> v;
    v << x, y;
    return v;
  };

  VectorXd times(3);
  times << 0, 1, 3;

  //SplineProblem<double, ptrdiff_t, 4, 2, 3> problem(times, 4, 2);
  SplineProblem<double, ptrdiff_t, 4, 2, 3> problem(times);
  problem.addConstantConstraint(0, 1, Value(0, 0));
  problem.addConstantConstraint(0, 0, Value(5, 7));
  problem.addConstantConstraint(1, 0, Value(6, 8));
  problem.addContinuityConstraint(1, 1);
  problem.addContinuityConstraint(1, 2);
  problem.addConstantConstraint(2, 0, Value(0, 2));
  problem.addConstantConstraint(2, 1, Value(0, 0));
  problem.fit();

  std::cout << "A =\n" << problem.mA << "\n\n";
  std::cout << "b =\n" << problem.mB.transpose() << "\n\n";
  for (int i = 0; i < problem.mSolution.size(); ++i) {
    std::cout << "x =\n" << problem.mSolution[i] << "\n\n";
  }

  std::ofstream csv("/tmp/data.csv", std::ios::binary);
  std::cout << "\n\n";
  for (double t = times[0]; t <= times[times.size() - 1] + 1e-3; t += 0.05) {
    csv << t << '\t' << problem.interpolate(t, 0).transpose() << '\t' << problem.getSegmentIndex(t) << '\n';
  }

  return 0;
}
<|endoftext|>


<commit_before>/**
  \file   main.cc
  \brief  Main file fir the finite element example.
  **/
// disable warnings about problems in dune headers
#include <dune/fem-tools/header/disablewarnings.hh>

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <iostream>
#include <vector>

// dune-common includes
#include <dune/common/exceptions.hh>
#include <dune/common/fmatrix.hh>

// dune-grid includes
#include <dune/grid/utility/gridtype.hh>

// dune-istl includes
#include <dune/istl/bcrsmatrix.hh>
#include <dune/istl/solvers.hh>
#include <dune/istl/bvector.hh>

// dune-fem includes
#include <dune/fem/misc/mpimanager.hh>
//#include <dune/fem/gridpart/gridpart.hh>
//#include <dune/fem/storage/vector.hh>
//#include <dune/fem/function/adaptivefunction/adaptivefunction.hh>
#include <dune/fem/gridpart/adaptiveleafgridpart.hh>

// reenable warnings
#include <dune/fem-tools/header/enablewarnings.hh>

// dune-functionals includes
#include <dune/functionals/discretefunctionspace/finiteelement.hh>
#include <dune/functionals/discretefunctionspace/subspace/linear.hh>
#include <dune/functionals/discretefunctionspace/subspace/affine.hh>
#include <dune/functionals/discreteoperator/local/integration.hh>
//#include <dune/fem/localoperation/interface.hh>
//#include <dune/fem/localoperation/integrator.hh>
//#include <dune/fem/subspace/subspaces.hh>
//#include <dune/fem/operator/linear.hh>
//#include <dune/fem/functional/finiteelement.hh>
//#include <dune/fem/container/factory.hh>
//#include <dune/fem/solver/femassembler.hh>

// dune-fem-tools includes
#include <dune/fem-tools/common/string.hh>
#include <dune/fem-tools/function/runtimefunction.hh>
#include <dune/fem-tools/function/functiontools.hh>
//#include <dune/fem-tools/space/projection.hh>

using namespace Dune::Functionals;

#ifndef POLORDER
const int polOrder = 1;
#else
const int polOrder = POLORDER;
#endif

///**
//  \brief  This represents the operation \f$fv\f$.

//          \f$f\f$ is a given right hand side (in this case 1) and \f$v\f$ may be a local function, i.e. a
//          testfunction.
//  \tparam FunctionSpaceImp
//          Type of the function space, where \f$f\f$ and \f$v\f$ live in.
//  **/
//template< class FunctionSpaceImp >
//class ProductOperation
//  : public Dune::Functionals::LocalOperation::Interface< FunctionSpaceImp >
//{
//public:

//  typedef FunctionSpaceImp
//    FunctionSpaceType;

//  typedef typename FunctionSpaceType::RangeFieldType
//    RangeFieldType;

//  typedef typename FunctionSpaceType::RangeType
//    RangeType;

//  /**
//    \brief      Evaluates \f$f(x)v(x)\f$ for a given local point \f$x\f$.

//    \tparam     LocalTestFunctionType
//                Type of the local function \f$v\f$, i.e. Dune::LocalFunction.
//    \tparam     LocalPointType
//                Type of the local point \f$x\f$, i.e. Dune::FieldVector.
//    \param[in]  localTestFunction
//                The local function \f$v\f$.
//    \param[in]  localPoint
//                The local point \f$x\f$. This point is local in the sense, that this is a point on a reference
//                element.
//    \return     \f$f(x)v(x)\f$
//    **/
//  template< class LocalTestFunctionType, class LocalPointType >
//  RangeFieldType evaluate(  const LocalTestFunctionType& localTestFunction,
//                            const LocalPointType& localPoint ) const
//  {
//    // init return value
//    RangeFieldType ret = 0.0;

//    // evaluate local function
//    RangeType localTestFunctionValue( 0.0 );
//    localTestFunction.evaluate( localPoint, localTestFunctionValue );

//    // 1.0 * v(x)
//    ret = 1.0 * localTestFunctionValue;

//    // return
//    return ret;
//  }

//}; // end class ProductOperation

/**
  \brief  This represents the operation \f$a\nabla u \nabla v\f$.

          \f$a\f$ is a given scalar function (in this case 1) and \f$u\f$ and \f$u\f$ may be local functions, i.e.
          ansatz- and testfunctions.
  \tparam FunctionSpaceImp
          Type of the function space, where \f$f\f$, \f$u\f$ and \f$v\f$ live in.
  **/
template< class FunctionSpaceImp >
class EllipticEvaluation
{
public:

  typedef FunctionSpaceImp
    FunctionSpaceType;

  typedef typename FunctionSpaceType::RangeFieldType
    RangeFieldType;

  typedef typename FunctionSpaceType::RangeType
    RangeType;

  typedef typename FunctionSpaceType::DomainType
    DomainType;

  typedef typename FunctionSpaceType::JacobianRangeType
    JacobianRangeType;

  typedef Dune::FemTools::Function::Runtime< FunctionSpaceType >
    InducingFunctionType;

  //! constructor, takes the inducing function as a runtime parameter
  EllipticEvaluation( const std::string expression = "[1.0;1.0;1.0]" )
    : inducingFunction_( expression )
  {
  }

  //! copy constructor
  EllipticEvaluation( const EllipticEvaluation& other )
    : inducingFunction_( other.inducingFunction() )
  {
  }

  //! returns the inducing function
  const InducingFunctionType& inducingFunction() const
  {
    return inducingFunction_;
  }

  /**
    * \brief      Evaluates \f$a(x)\nabla u(x) \nabla v(x)\f$ for a given local point \f$x\f$.
    *
    * \tparam     LocalAnsatzFunctionType
    *             Type of the local ansatz function \f$u\f$, i.e. Dune::LocalFunction.
    * \tparam     LocalTestFunctionType
    *             Type of the local test function \f$v\f$, i.e. Dune::LocalFunction.
    * \tparam     LocalPointType
    *             Type of the local point \f$x\f$, i.e. Dune::FieldVector.
    * \param[in]  localAnsatzFunction
    *             The local function \f$u\f$.
    * \param[in]  localTestFunction
    *             The local function \f$v\f$.
    * \param[in]  localPoint
    *             The local point \f$x\f$. This point is local in the sense, that this is a point on a reference
    *             element.
    * \return     \f$a(x)\nabla u(x) \nabla v(x)\f$
    **/
  template< class LocalAnsatzFunctionType, class LocalTestFunctionType, class LocalPointType >
  RangeFieldType evaluate(  const LocalAnsatzFunctionType& localAnsatzFunction,
                            const LocalTestFunctionType& localTestFunction,
                            const LocalPointType& localPoint ) const
  {
    // init return value
    RangeFieldType ret = 0.0;

    // get global point
    const DomainType globalPoint = localAnsatzFunction.entity().geometry().gobal( localPoint );

    // evaluate first gradient
    JacobianRangeType gradientLocalAnsatzFunction( 0.0 );
    localAnsatzFunction.jacobian( localPoint, gradientLocalAnsatzFunction );

    // evaluate second gradient
    JacobianRangeType gradientLocalTestFunction( 0.0 );
    localTestFunction.jacobian( localPoint, gradientLocalTestFunction );

    const RangeFieldType gradientProduct = gradientLocalAnsatzFunction[0] * gradientLocalTestFunction[0];

    // evaluate inducing function
    RangeFieldType functionValue( 0.0 );
    inducingFunction_.evaluate( globalPoint, functionValue );

    // a(x) * \gradient u(x) * \gradient v(x)
    ret = functionValue * gradientProduct;

    return ret;
  }

private:

  const InducingFunctionType inducingFunction_;
}; // end class EllipticEvalaution

int main( int argc, char** argv )
{
  try{

    // MPI manager
    Dune::MPIManager::initialize ( argc, argv );

    // grid
    static const unsigned int dimRange = 1;

    typedef Dune::GridSelector::GridType
      GridType;

    typedef Dune::AdaptiveLeafGridPart< GridType >
      GridPartType;

    const std::string dgfFilename = "../macrogrids/unitcube" + Dune::FemTools::String::toString( GRIDDIM ) + ".dgf";

    Dune::GridPtr< GridType > gridPtr( dgfFilename );

    GridPartType gridPart( *gridPtr );

    // function spaces and functions
    typedef Dune::FunctionSpace< double, double, GridType::dimension, dimRange >
      FunctionSpaceType;

    // discrete function space
    typedef DiscreteFunctionSpace::ContinuousFiniteElement< FunctionSpaceType, GridPartType, polOrder >
      DiscreteH1Type;

    const DiscreteH1Type discreteH1( gridPart );

    typedef DiscreteFunctionSpace::Subspace::Linear::DirichletZero< DiscreteH1Type >
      DiscreteH10Type;

    const DiscreteH10Type discreteH10( discreteH1 );

    typedef DiscreteFunctionSpace::Subspace::Affine::Dirichlet< DiscreteH10Type >
      DiscreteH1GType;

    const DiscreteH1GType discreteH1G( discreteH10, "[x+y;y;z]" );

    // local evaluations
//    typedef ProductOperation< FunctionSpaceType >
//      ProductOperationType;

//    ProductOperationType productOperation;

    typedef EllipticEvaluation< FunctionSpaceType >
      EllipticEvaluationType;

    EllipticEvaluationType ellipticEvaluation( "[1.0;1.0;1.0]" );

    // operator and functional
    typedef Dune::Functionals::DiscreteOperator::Local::Codim0Integration< EllipticEvaluationType, DiscreteH1Type, DiscreteH1Type >
      LocalEllipticOperatorType;

    const LocalEllipticOperatorType localEllipticOperator( ellipticEvaluation, discreteH1, discreteH1 );

//    FEMellipticOperatorType femEllipticOperator( ellipticIntegrator, discreteH1 );

//    typedef Functional::FiniteElementLOP< DiscreteH1Type, ProductIntegratorType >
//      FEMrhsFunctionalType;

//    FEMrhsFunctionalType femRhsFunctional( discreteH1, productIntegrator );

//    // matrix, rhs and solution storage
//    typedef Dune::FieldMatrix< double, dimRange, dimRange >
//      FieldMatrixType;

//    typedef Container::MatrixFactory< Dune::BCRSMatrix< FieldMatrixType > >
//      MatrixFactoryType;

//    typedef MatrixFactoryType::ContainerType
//      MatrixContainer;

//    typedef MatrixFactoryType::AutoPtrType
//      MatrixContainerPtr;

//    typedef Container::VectorFactory< Dune::BlockVector< Dune::FieldVector< double, 1 > > >
//      VectorFactoryType;

//    typedef VectorFactoryType::ContainerType
//      VectorContainer;

//    typedef VectorFactoryType::AutoPtrType
//      VectorContainerPtr;

//    MatrixContainerPtr A  = MatrixFactoryType::create( discreteH10 );
//    VectorContainerPtr F  = VectorFactoryType::create( discreteH10 );
//    VectorContainerPtr u0 = VectorFactoryType::create( discreteH10 );

//    // assembler
//    typedef Assembler::FiniteElement< MatrixContainer, VectorContainer >
//      Assembler;

//    Assembler::assembleMatrix( femEllipticOperator, *A );
//    Assembler::applyMatrixConstraints( discreteH10, *A );

//    Assembler::assembleVector( femRhsFunctional, *F );
//    Assembler::applyVectorConstraints( discreteH10, *F );

//    // preconditioner and solver
//    typedef Dune::MatrixAdapter< MatrixContainer, VectorContainer, VectorContainer >
//      MatrixAdapterType;

//    MatrixAdapterType op( *A );

//    typedef Dune::SeqILU0< MatrixContainer, VectorContainer, VectorContainer, 1 >
//      SeqILU0Type;

//    SeqILU0Type prec( *A, 1.0 );

//    typedef Dune::CGSolver< VectorContainer >
//      CG;

//    CG cg( op, prec, 1e-4, 100, 2 );

//    Dune::InverseOperatorResult res;

//    // u_0 = A^(-1) ( F - G )
//    cg.apply( *u0, *F, res );

//    // postprocessing
//    DiscreteFunctionType solution = Dune::FemTools::discreteFunctionFactory< DiscreteFunctionType >( discreteH1, *u0 );
    Dune::FemTools::Function::writeToVTK( discreteH1G.affineShift(), "boundaryData" );

    return 0;
  }
  catch (Dune::Exception &e){
    std::cerr << "Dune reported error: " << e << std::endl;
  }
  catch (...){
    std::cerr << "Unknown exception thrown!" << std::endl;
  }
}
<commit_msg>use of matrix factory<commit_after>/**
  \file   main.cc
  \brief  Main file fir the finite element example.
  **/
// disable warnings about problems in dune headers
#include <dune/fem-tools/header/disablewarnings.hh>

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <iostream>
#include <vector>

// dune-common includes
#include <dune/common/exceptions.hh>
#include <dune/common/fmatrix.hh>

// dune-grid includes
#include <dune/grid/utility/gridtype.hh>

// dune-istl includes
#include <dune/istl/solvers.hh>

// dune-fem includes
#include <dune/fem/misc/mpimanager.hh>
//#include <dune/fem/gridpart/gridpart.hh>
//#include <dune/fem/storage/vector.hh>
//#include <dune/fem/function/adaptivefunction/adaptivefunction.hh>
#include <dune/fem/gridpart/adaptiveleafgridpart.hh>

// reenable warnings
#include <dune/fem-tools/header/enablewarnings.hh>

// dune-functionals includes
#include <dune/functionals/discretefunctionspace/finiteelement.hh>
#include <dune/functionals/discretefunctionspace/subspace/linear.hh>
#include <dune/functionals/discretefunctionspace/subspace/affine.hh>
#include <dune/functionals/discreteoperator/local/integration.hh>
#include <dune/functionals/container/factory.hh>

// dune-fem-tools includes
#include <dune/fem-tools/common/string.hh>
#include <dune/fem-tools/function/runtimefunction.hh>
#include <dune/fem-tools/function/functiontools.hh>
//#include <dune/fem-tools/space/projection.hh>

using namespace Dune::Functionals;

#ifndef POLORDER
const int polOrder = 1;
#else
const int polOrder = POLORDER;
#endif

///**
//  \brief  This represents the operation \f$fv\f$.

//          \f$f\f$ is a given right hand side (in this case 1) and \f$v\f$ may be a local function, i.e. a
//          testfunction.
//  \tparam FunctionSpaceImp
//          Type of the function space, where \f$f\f$ and \f$v\f$ live in.
//  **/
//template< class FunctionSpaceImp >
//class ProductOperation
//  : public Dune::Functionals::LocalOperation::Interface< FunctionSpaceImp >
//{
//public:

//  typedef FunctionSpaceImp
//    FunctionSpaceType;

//  typedef typename FunctionSpaceType::RangeFieldType
//    RangeFieldType;

//  typedef typename FunctionSpaceType::RangeType
//    RangeType;

//  /**
//    \brief      Evaluates \f$f(x)v(x)\f$ for a given local point \f$x\f$.

//    \tparam     LocalTestFunctionType
//                Type of the local function \f$v\f$, i.e. Dune::LocalFunction.
//    \tparam     LocalPointType
//                Type of the local point \f$x\f$, i.e. Dune::FieldVector.
//    \param[in]  localTestFunction
//                The local function \f$v\f$.
//    \param[in]  localPoint
//                The local point \f$x\f$. This point is local in the sense, that this is a point on a reference
//                element.
//    \return     \f$f(x)v(x)\f$
//    **/
//  template< class LocalTestFunctionType, class LocalPointType >
//  RangeFieldType evaluate(  const LocalTestFunctionType& localTestFunction,
//                            const LocalPointType& localPoint ) const
//  {
//    // init return value
//    RangeFieldType ret = 0.0;

//    // evaluate local function
//    RangeType localTestFunctionValue( 0.0 );
//    localTestFunction.evaluate( localPoint, localTestFunctionValue );

//    // 1.0 * v(x)
//    ret = 1.0 * localTestFunctionValue;

//    // return
//    return ret;
//  }

//}; // end class ProductOperation

/**
  \brief  This represents the operation \f$a\nabla u \nabla v\f$.

          \f$a\f$ is a given scalar function (in this case 1) and \f$u\f$ and \f$u\f$ may be local functions, i.e.
          ansatz- and testfunctions.
  \tparam FunctionSpaceImp
          Type of the function space, where \f$f\f$, \f$u\f$ and \f$v\f$ live in.
  **/
template< class FunctionSpaceImp >
class EllipticEvaluation
{
public:

  typedef FunctionSpaceImp
    FunctionSpaceType;

  typedef typename FunctionSpaceType::RangeFieldType
    RangeFieldType;

  typedef typename FunctionSpaceType::RangeType
    RangeType;

  typedef typename FunctionSpaceType::DomainType
    DomainType;

  typedef typename FunctionSpaceType::JacobianRangeType
    JacobianRangeType;

  typedef Dune::FemTools::Function::Runtime< FunctionSpaceType >
    InducingFunctionType;

  //! constructor, takes the inducing function as a runtime parameter
  EllipticEvaluation( const std::string expression = "[1.0;1.0;1.0]" )
    : inducingFunction_( expression )
  {
  }

  //! copy constructor
  EllipticEvaluation( const EllipticEvaluation& other )
    : inducingFunction_( other.inducingFunction() )
  {
  }

  //! returns the inducing function
  const InducingFunctionType& inducingFunction() const
  {
    return inducingFunction_;
  }

  /**
    * \brief      Evaluates \f$a(x)\nabla u(x) \nabla v(x)\f$ for a given local point \f$x\f$.
    *
    * \tparam     LocalAnsatzFunctionType
    *             Type of the local ansatz function \f$u\f$, i.e. Dune::LocalFunction.
    * \tparam     LocalTestFunctionType
    *             Type of the local test function \f$v\f$, i.e. Dune::LocalFunction.
    * \tparam     LocalPointType
    *             Type of the local point \f$x\f$, i.e. Dune::FieldVector.
    * \param[in]  localAnsatzFunction
    *             The local function \f$u\f$.
    * \param[in]  localTestFunction
    *             The local function \f$v\f$.
    * \param[in]  localPoint
    *             The local point \f$x\f$. This point is local in the sense, that this is a point on a reference
    *             element.
    * \return     \f$a(x)\nabla u(x) \nabla v(x)\f$
    **/
  template< class LocalAnsatzFunctionType, class LocalTestFunctionType, class LocalPointType >
  RangeFieldType evaluate(  const LocalAnsatzFunctionType& localAnsatzFunction,
                            const LocalTestFunctionType& localTestFunction,
                            const LocalPointType& localPoint ) const
  {
    // init return value
    RangeFieldType ret = 0.0;

    // get global point
    const DomainType globalPoint = localAnsatzFunction.entity().geometry().gobal( localPoint );

    // evaluate first gradient
    JacobianRangeType gradientLocalAnsatzFunction( 0.0 );
    localAnsatzFunction.jacobian( localPoint, gradientLocalAnsatzFunction );

    // evaluate second gradient
    JacobianRangeType gradientLocalTestFunction( 0.0 );
    localTestFunction.jacobian( localPoint, gradientLocalTestFunction );

    const RangeFieldType gradientProduct = gradientLocalAnsatzFunction[0] * gradientLocalTestFunction[0];

    // evaluate inducing function
    RangeFieldType functionValue( 0.0 );
    inducingFunction_.evaluate( globalPoint, functionValue );

    // a(x) * \gradient u(x) * \gradient v(x)
    ret = functionValue * gradientProduct;

    return ret;
  }

private:

  const InducingFunctionType inducingFunction_;
}; // end class EllipticEvalaution

int main( int argc, char** argv )
{
  try{

    // MPI manager
    Dune::MPIManager::initialize ( argc, argv );

    // grid
    static const unsigned int dimRange = 1;

    typedef Dune::GridSelector::GridType
      GridType;

    typedef Dune::AdaptiveLeafGridPart< GridType >
      GridPartType;

    const std::string dgfFilename = "../macrogrids/unitcube" + Dune::FemTools::String::toString( GRIDDIM ) + ".dgf";

    Dune::GridPtr< GridType > gridPtr( dgfFilename );

    GridPartType gridPart( *gridPtr );

    // function spaces and functions
    typedef Dune::FunctionSpace< double, double, GridType::dimension, dimRange >
      FunctionSpaceType;

    typedef typename FunctionSpaceType::RangeFieldType
      RangeFieldType;

    // discrete function space
    typedef DiscreteFunctionSpace::ContinuousFiniteElement< FunctionSpaceType, GridPartType, polOrder >
      DiscreteH1Type;

    const DiscreteH1Type discreteH1( gridPart );

    typedef DiscreteFunctionSpace::Subspace::Linear::DirichletZero< DiscreteH1Type >
      DiscreteH10Type;

    const DiscreteH10Type discreteH10( discreteH1 );

    typedef DiscreteFunctionSpace::Subspace::Affine::Dirichlet< DiscreteH10Type >
      DiscreteH1GType;

    const DiscreteH1GType discreteH1G( discreteH10, "[x+y;y;z]" );

    // local evaluations
//    typedef ProductOperation< FunctionSpaceType >
//      ProductOperationType;

//    ProductOperationType productOperation;

    typedef EllipticEvaluation< FunctionSpaceType >
      EllipticEvaluationType;

    EllipticEvaluationType ellipticEvaluation( "[1.0;1.0;1.0]" );

    // operator and functional
    typedef Dune::Functionals::DiscreteOperator::Local::Codim0Integration< EllipticEvaluationType, DiscreteH1Type, DiscreteH1Type >
      LocalEllipticOperatorType;

    const LocalEllipticOperatorType localEllipticOperator( ellipticEvaluation, discreteH1, discreteH1 );

//    FEMellipticOperatorType femEllipticOperator( ellipticIntegrator, discreteH1 );

//    typedef Functional::FiniteElementLOP< DiscreteH1Type, ProductIntegratorType >
//      FEMrhsFunctionalType;

//    FEMrhsFunctionalType femRhsFunctional( discreteH1, productIntegrator );

    // matrix, rhs and solution storage
    typedef Dune::Functionals::Container::Matrix::Defaults< RangeFieldType, dimRange, dimRange >::BCRSMatrix
      MatrixFactory;

    typedef typename MatrixFactory::AutoPtrType
      MatrixPtrType;

    MatrixPtrType A = MatrixFactory::create( discreteH10 );

//    typedef Dune::FieldMatrix< double, dimRange, dimRange >
//      FieldMatrixType;

//    typedef Container::MatrixFactory< Dune::BCRSMatrix< FieldMatrixType > >
//      MatrixFactoryType;

//    typedef MatrixFactoryType::ContainerType
//      MatrixContainer;

//    typedef MatrixFactoryType::AutoPtrType
//      MatrixContainerPtr;

//    typedef Container::VectorFactory< Dune::BlockVector< Dune::FieldVector< double, 1 > > >
//      VectorFactoryType;

//    typedef VectorFactoryType::ContainerType
//      VectorContainer;

//    typedef VectorFactoryType::AutoPtrType
//      VectorContainerPtr;

//    MatrixContainerPtr A  = MatrixFactoryType::create( discreteH10 );
//    VectorContainerPtr F  = VectorFactoryType::create( discreteH10 );
//    VectorContainerPtr u0 = VectorFactoryType::create( discreteH10 );

//    // assembler
//    typedef Assembler::FiniteElement< MatrixContainer, VectorContainer >
//      Assembler;

//    Assembler::assembleMatrix( femEllipticOperator, *A );
//    Assembler::applyMatrixConstraints( discreteH10, *A );

//    Assembler::assembleVector( femRhsFunctional, *F );
//    Assembler::applyVectorConstraints( discreteH10, *F );

//    // preconditioner and solver
//    typedef Dune::MatrixAdapter< MatrixContainer, VectorContainer, VectorContainer >
//      MatrixAdapterType;

//    MatrixAdapterType op( *A );

//    typedef Dune::SeqILU0< MatrixContainer, VectorContainer, VectorContainer, 1 >
//      SeqILU0Type;

//    SeqILU0Type prec( *A, 1.0 );

//    typedef Dune::CGSolver< VectorContainer >
//      CG;

//    CG cg( op, prec, 1e-4, 100, 2 );

//    Dune::InverseOperatorResult res;

//    // u_0 = A^(-1) ( F - G )
//    cg.apply( *u0, *F, res );

//    // postprocessing
//    DiscreteFunctionType solution = Dune::FemTools::discreteFunctionFactory< DiscreteFunctionType >( discreteH1, *u0 );
    Dune::FemTools::Function::writeToVTK( discreteH1G.affineShift(), "boundaryData" );

    return 0;
  }
  catch (Dune::Exception &e){
    std::cerr << "Dune reported error: " << e << std::endl;
  }
  catch (...){
    std::cerr << "Unknown exception thrown!" << std::endl;
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_VISIT_HPP
#define TAO_PEGTL_VISIT_HPP

#include <type_traits>

#include "config.hpp"
#include "rule_list.hpp"

namespace TAO_PEGTL_NAMESPACE
{
   namespace internal
   {
      template< typename Type, typename... Types >
      inline constexpr bool contains = ( std::is_same_v< Type, Types > || ... );

      template< typename Rules, typename Todo, typename Done >
      struct filter
      {
         using type = Todo;
      };

      template< typename Rule, typename... Rules, typename... Todo, typename... Done >
      struct filter< rule_list< Rule, Rules... >, rule_list< Todo... >, rule_list< Done... > >
         : filter< rule_list< Rules... >, std::conditional_t< contains< Rule, Todo..., Done... >, rule_list< Todo... >, rule_list< Rule, Todo... > >, rule_list< Done... > >
      {};

      template< typename Rules, typename Todo, typename Done >
      using filter_t = typename filter< Rules, Todo, Done >::type;

      template< typename... >
      struct concat
      {
         using type = rule_list<>;
      };

      template< typename RuleList >
      struct concat< RuleList >
      {
         using type = RuleList;
      };

      template< typename... R0, typename... R1, typename... Tail >
      struct concat< rule_list< R0... >, rule_list< R1... >, Tail... >
         : concat< rule_list< R0..., R1... >, Tail... >
      {};

      template< typename... Ts >
      using concat_t = typename concat< Ts... >::type;

      template< template< typename... > class Func, typename Done, typename... Rules >
      struct visitor
      {
         template< typename... Args >
         static void visit( Args&&... args )
         {
            ( Func< Rules >::visit( args... ), ... );
            using NextDone = concat_t< rule_list< Rules... >, Done >;
            using NextSubs = concat_t< typename Rules::subs_t... >;
            using NextTodo = filter_t< NextSubs, rule_list<>, NextDone >;
            if constexpr( !std::is_same_v< NextTodo, empty_list > ) {
               visit_next< NextDone >( NextTodo(), args... );
            }
         }

      private:
         template< typename NextDone, typename... NextTodo, typename... Args >
         static void visit_next( rule_list< NextTodo... > /*unused*/, Args&&... args )
         {
            visitor< Func, NextDone, NextTodo... >::visit( args... );
         }
      };

   }  // namespace internal

   template< template< typename... > class Func, typename Rule, typename... Args >
   void visit( Args&&... args )
   {
      internal::visitor< Func, rule_list<>, Rule >::visit( args... );
   }

}  // namespace TAO_PEGTL_NAMESPACE

#endif
<commit_msg>Reduce number of instantiations<commit_after>// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_VISIT_HPP
#define TAO_PEGTL_VISIT_HPP

#include <type_traits>

#include "config.hpp"
#include "rule_list.hpp"

namespace TAO_PEGTL_NAMESPACE
{
   namespace internal
   {
      template< typename Type, typename... Types >
      inline constexpr bool contains = ( std::is_same_v< Type, Types > || ... );

      template< typename Rules, typename Todo, typename Done >
      struct filter
      {
         using type = Todo;
      };

      template< typename Rule, typename... Rules, typename... Todo, typename... Done >
      struct filter< rule_list< Rule, Rules... >, rule_list< Todo... >, rule_list< Done... > >
         : filter< rule_list< Rules... >, std::conditional_t< contains< Rule, Todo..., Done... >, rule_list< Todo... >, rule_list< Rule, Todo... > >, rule_list< Done... > >
      {};

      template< typename Rules, typename Todo, typename Done >
      using filter_t = typename filter< Rules, Todo, Done >::type;

      template< typename... >
      struct concat
      {
         using type = empty_list;
      };

      template< typename R >
      struct concat< R >
      {
         using type = R;
      };

      template< typename... R0, typename... R1 >
      struct concat< rule_list< R0... >, rule_list< R1... > >
      {
         using type = rule_list< R0..., R1... >;
      };

      template< typename... Ts >
      using concat_t = typename concat< Ts... >::type;

      template< typename... R0, typename... R1, typename T, typename... Ts >
      struct concat< rule_list< R0... >, rule_list< R1... >, T, Ts... >
         : concat< rule_list< R0..., R1... >, concat_t< T, Ts... > >
      {};

      template< template< typename... > class Func, typename Done, typename... Rules >
      struct visitor
      {
         template< typename... Args >
         static void visit( Args&&... args )
         {
            ( Func< Rules >::visit( args... ), ... );
            using NextDone = concat_t< rule_list< Rules... >, Done >;
            using NextSubs = concat_t< typename Rules::subs_t... >;
            using NextTodo = filter_t< NextSubs, empty_list, NextDone >;
            if constexpr( !std::is_same_v< NextTodo, empty_list > ) {
               visit_next< NextDone >( NextTodo(), args... );
            }
         }

      private:
         template< typename NextDone, typename... NextTodo, typename... Args >
         static void visit_next( rule_list< NextTodo... > /*unused*/, Args&&... args )
         {
            visitor< Func, NextDone, NextTodo... >::visit( args... );
         }
      };

   }  // namespace internal

   template< template< typename... > class Func, typename Rule, typename... Args >
   void visit( Args&&... args )
   {
      internal::visitor< Func, empty_list, Rule >::visit( args... );
   }

}  // namespace TAO_PEGTL_NAMESPACE

#endif
<|endoftext|>


<commit_before>#include "ttestindependentsamplesform.h"
#include "ui_ttestindependentsamplesform.h"

#include "analysisform.h"

TTestIndependentSamplesForm::TTestIndependentSamplesForm(QWidget *parent) :
	AnalysisForm("TTestIndependentSamplesForm", parent),
	ui(new Ui::TTestIndependentSamplesForm)
{
	ui->setupUi(this);

	ui->listAvailableFields->setModel(&_availableVariablesModel);
	ui->listAvailableFields->setDoubleClickTarget(ui->variables);

	TableModelVariablesAssigned *variablesModel = new TableModelVariablesAssigned(this);
	variablesModel->setSource(&_availableVariablesModel);
	variablesModel->setVariableTypesSuggested(Column::ColumnTypeScale);
	variablesModel->setVariableTypesAllowed(Column::ColumnTypeNominal | Column::ColumnTypeOrdinal | Column::ColumnTypeScale);
	ui->variables->setModel(variablesModel);
	ui->variables->setDoubleClickTarget(ui->listAvailableFields);

	TableModelVariablesAssigned *groupingVariableModel = new TableModelVariablesAssigned(this);
	groupingVariableModel->setVariableTypesSuggested(Column::ColumnTypeOrdinal | Column::ColumnTypeNominal);
	groupingVariableModel->setVariableTypesAllowed(Column::ColumnTypeNominal | Column::ColumnTypeOrdinal | Column::ColumnTypeScale);
	groupingVariableModel->setSource(&_availableVariablesModel);
	ui->groupingVariable->setModel(groupingVariableModel);
	ui->groupingVariable->setDoubleClickTarget(ui->listAvailableFields);

	ui->buttonAssignVariables->setSourceAndTarget(ui->listAvailableFields, ui->variables);
	ui->buttonAssignGroupingVariable->setSourceAndTarget(ui->listAvailableFields, ui->groupingVariable);
}

TTestIndependentSamplesForm::~TTestIndependentSamplesForm()
{
	delete ui;
}
<commit_msg>Fix to Independent Samples T-Test<commit_after>#include "ttestindependentsamplesform.h"
#include "ui_ttestindependentsamplesform.h"

#include "analysisform.h"

TTestIndependentSamplesForm::TTestIndependentSamplesForm(QWidget *parent) :
	AnalysisForm("TTestIndependentSamplesForm", parent),
	ui(new Ui::TTestIndependentSamplesForm)
{
	ui->setupUi(this);

	ui->listAvailableFields->setModel(&_availableVariablesModel);
	ui->listAvailableFields->setDoubleClickTarget(ui->variables);

	TableModelVariablesAssigned *variablesModel = new TableModelVariablesAssigned(this);
	variablesModel->setSource(&_availableVariablesModel);
	variablesModel->setVariableTypesSuggested(Column::ColumnTypeScale);
	variablesModel->setVariableTypesAllowed(Column::ColumnTypeNominal | Column::ColumnTypeOrdinal | Column::ColumnTypeScale);
	ui->variables->setModel(variablesModel);
	ui->variables->setDoubleClickTarget(ui->listAvailableFields);

	TableModelVariablesAssigned *groupingVariableModel = new TableModelVariablesAssigned(this);
	groupingVariableModel->setVariableTypesSuggested(Column::ColumnTypeOrdinal | Column::ColumnTypeNominal);
	groupingVariableModel->setSource(&_availableVariablesModel);
	ui->groupingVariable->setModel(groupingVariableModel);
	ui->groupingVariable->setDoubleClickTarget(ui->listAvailableFields);

	ui->buttonAssignVariables->setSourceAndTarget(ui->listAvailableFields, ui->variables);
	ui->buttonAssignGroupingVariable->setSourceAndTarget(ui->listAvailableFields, ui->groupingVariable);
}

TTestIndependentSamplesForm::~TTestIndependentSamplesForm()
{
	delete ui;
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2021.  All rights reserved
 */
#include "../../StroikaPreComp.h"

#include "../../Characters/StringBuilder.h"
#include "../../DataExchange/Variant/JSON/Reader.h"
#include "../../DataExchange/Variant/JSON/Writer.h"

#include "Schema.h"

using std::byte;

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::Characters;
using namespace Stroika::Foundation::Database;
using namespace Stroika::Foundation::DataExchange;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

/*
 ********************************************************************************
 *************************** ORM::Schema::CatchAllField *************************
 ********************************************************************************
 */
ORM::Schema::CatchAllField::CatchAllField ()
{
    fName        = L"_other_fields_"sv;
    fVariantType = VariantValue::Type::eString; // sb BLOB probably
}

VariantValue ORM::Schema::CatchAllField::kDefaultMapper_RawToCombined (const Mapping<String, VariantValue>& fields2Map)
{
    return DataExchange::Variant::JSON::Writer{}.WriteAsString (VariantValue{fields2Map});
}

Mapping<String, VariantValue> ORM::Schema::CatchAllField::kDefaultMapper_CombinedToRaw (const VariantValue& fields2Map)
{
    return DataExchange::Variant::JSON::Reader{}.Read (fields2Map.As<String> ()).As<Mapping<String, VariantValue>> ();
}

/*
 ********************************************************************************
 ****************************** ORM::Schema::Table ******************************
 ********************************************************************************
 */
Mapping<String, VariantValue> ORM::Schema::Table::MapToDB (const VariantValue& vv) const
{
#if USE_NOISY_TRACE_IN_THIS_MODULE_
    TraceContextBumper ctx{"ORM::Schema::Table::MapToDB", Stroika_Foundation_Debug_OptionalizeTraceArgs (L"vv=%s", Characters::ToString(vv).c_str ())};
#endif
    Mapping<String, VariantValue> actualFields = vv.As<Mapping<String, VariantValue>> ();
    Mapping<String, VariantValue> resultFields;
    Set<String>                   usedFields; // must track outside of resultFields.Keys () cuz input key could differ from output
    for (const auto& fi : fNamedFields) {
        String srcKey = Memory::NullCoalesce (fi.fVariantValueFieldName, fi.fName);
        if (auto oFieldVal = actualFields.Lookup (srcKey)) {
            if (fi.fVariantType) {
                resultFields.Add (fi.fName, oFieldVal->ConvertTo (*fi.fVariantType));
            }
            else {
                resultFields.Add (fi.fName, *oFieldVal);
            }
            usedFields += srcKey;
        }
        else if (fi.fRequired) {
            // throw or assert?
            AssertNotReached ();
        }
    }
    // now fold remaining fields into special 'extra' field (for structured non-indexed/non-searchable data)
    Set<String> fields2Accumulate = Set<String>{actualFields.Keys ()} - usedFields;
    if (fSpecialCatchAll.has_value () and not fields2Accumulate.empty ()) {
        Mapping<String, VariantValue> extraFields;
        for (auto i : fields2Accumulate) {
            extraFields.Add (i, *actualFields.Lookup (i));
        }
        // convert to JSON and store as string
        auto mapperFieldsToCombinedField = fSpecialCatchAll->fMapRawFieldsToCombinedField != nullptr ? fSpecialCatchAll->fMapRawFieldsToCombinedField : CatchAllField::kDefaultMapper_RawToCombined;
        resultFields.Add (fSpecialCatchAll->fName, mapperFieldsToCombinedField (extraFields));
    }
    else {
        Require (fields2Accumulate.empty () or fSpecialCatchAll.has_value ());
    }
#if USE_NOISY_TRACE_IN_THIS_MODULE_
    DbgTrace (L"returning: %s", Characters::ToString (vv).c_str ())};
#endif
    return resultFields;
}

Mapping<String, VariantValue> ORM::Schema::Table::MapFromDB (const VariantValue& vv) const
{
    Mapping<String, VariantValue> actualFields = vv.As<Mapping<String, VariantValue>> ();
    Mapping<String, VariantValue> resultFields;
    for (const auto& fi : fNamedFields) {
        if (auto oFieldVal = actualFields.Lookup (fi.fName)) {
            if (fi.fVariantType) {
                resultFields.Add (fi.fName, oFieldVal->ConvertTo (*fi.fVariantType));
            }
            else {
                resultFields.Add (fi.fName, *oFieldVal);
            }
        }
        else if (fi.fRequired) {
            // throw or assert?
        }
    }
    // now fold remaining fields into special 'extra' field (for structured non-indexed/non-searchable data)
    if (fSpecialCatchAll.has_value ()) {
        if (auto o = actualFields.Lookup (fSpecialCatchAll->fName)) {
            auto mapperCombinedToRawFields = fSpecialCatchAll->fMapCombinedFieldToRawFields != nullptr ? fSpecialCatchAll->fMapCombinedFieldToRawFields : CatchAllField::kDefaultMapper_CombinedToRaw;
            resultFields.AddAll (mapperCombinedToRawFields (*o));
        }
    }
    else {
        // @todo maybe check fNamedFields contains all the actual fields??? Maybe OK to not check
    }
    return resultFields;
}

namespace {
    String GetSQLiteFldName_ (const ORM::Schema::Field& f)
    {
        if (f.fVariantType) {
            switch (*f.fVariantType) {
                case VariantValue::eBLOB:
                    return L"BLOB"sv;
                case VariantValue::eDate:
                case VariantValue::eDateTime:
                case VariantValue::eString:
                    return L"TEXT"sv;
                case VariantValue::eBoolean:
                case VariantValue::eInteger:
                case VariantValue::eUnsignedInteger:
                    return L"INT"sv;
                case VariantValue::eFloat:
                    return L"REAL"sv;
            }
        }
        return L"TEXT"sv; // @todo better
    }
}

String ORM::Schema::Table::GetSQLToCreateTable () const
{
    StringBuilder sb;

    /*
     *   CREATE TABLE DEVICES(
     *      ID BLOB PRIMARY KEY DEFAULT(randomblob(16)),
     *      NAME           TEXT    NOT NULL
     *     );
     */
    sb += L"CREATE TABLE " + fName + L" (";
    bool firstField = true;
    auto addField   = [&] (const Field& fi) {
        if (firstField) {
            firstField = false;
        }
        else {
            sb += L", ";
        }
        sb += fi.fName + L" ";
        sb += GetSQLiteFldName_ (fi) + L" ";
        if (fi.fIsKeyField == true) {
            sb += L" PRIMARY KEY";
        }
        if (fi.fDefaultExpression) {
            sb += L" DEFAULT(" + *fi.fDefaultExpression + L")";
        }
        if (fi.fNotNull == true) {
            sb += L" NOT NULL";
        }
    };
    for (const Field& i : fNamedFields) {
        addField (i);
    }
    if (fSpecialCatchAll) {
        addField (*fSpecialCatchAll);
    }
    sb += L");";

    return sb.str ();
}

String ORM::Schema::Table::GetSQLToInsert () const
{
    StringBuilder sb;

    /*
     *   INSERT INTO DEVICES (name) values (:NAME);
     */
    sb += L"INSERT INTO " + fName + L" (";
    bool firstField   = true;
    auto addFieldName = [&] (const Field& fi) {
        if (firstField) {
            firstField = false;
        }
        else {
            sb += L", ";
        }
        sb += fi.fName;
    };
    for (const Field& i : fNamedFields) {
        addFieldName (i);
    }
    if (fSpecialCatchAll) {
        addFieldName (*fSpecialCatchAll);
    }
    sb += L") VALUES (";
    firstField                     = true;
    auto addFieldValueVariableName = [&] (const Field& fi) {
        if (firstField) {
            firstField = false;
        }
        else {
            sb += L", ";
        }
        sb += L":" + fi.fName;
    };
    for (const Field& i : fNamedFields) {
        addFieldValueVariableName (i);
    }
    if (fSpecialCatchAll) {
        addFieldValueVariableName (*fSpecialCatchAll);
    }
    sb += L");";
    return sb.str ();
}
<commit_msg>cosmetic<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2021.  All rights reserved
 */
#include "../../StroikaPreComp.h"

#include "../../Characters/StringBuilder.h"
#include "../../DataExchange/Variant/JSON/Reader.h"
#include "../../DataExchange/Variant/JSON/Writer.h"

#include "Schema.h"

using std::byte;

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::Characters;
using namespace Stroika::Foundation::Database;
using namespace Stroika::Foundation::DataExchange;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

/*
 ********************************************************************************
 *************************** ORM::Schema::CatchAllField *************************
 ********************************************************************************
 */
ORM::Schema::CatchAllField::CatchAllField ()
{
    fName        = L"_other_fields_"sv;
    fVariantType = VariantValue::Type::eString; // sb BLOB probably
}

VariantValue ORM::Schema::CatchAllField::kDefaultMapper_RawToCombined (const Mapping<String, VariantValue>& fields2Map)
{
    return DataExchange::Variant::JSON::Writer{}.WriteAsString (VariantValue{fields2Map});
}

Mapping<String, VariantValue> ORM::Schema::CatchAllField::kDefaultMapper_CombinedToRaw (const VariantValue& fields2Map)
{
    return DataExchange::Variant::JSON::Reader{}.Read (fields2Map.As<String> ()).As<Mapping<String, VariantValue>> ();
}

/*
 ********************************************************************************
 ****************************** ORM::Schema::Table ******************************
 ********************************************************************************
 */
Mapping<String, VariantValue> ORM::Schema::Table::MapToDB (const VariantValue& vv) const
{
#if USE_NOISY_TRACE_IN_THIS_MODULE_
    TraceContextBumper ctx{"ORM::Schema::Table::MapToDB", Stroika_Foundation_Debug_OptionalizeTraceArgs (L"vv=%s", Characters::ToString (vv).c_str ())};
#endif
    Mapping<String, VariantValue> actualFields = vv.As<Mapping<String, VariantValue>> ();
    Mapping<String, VariantValue> resultFields;
    Set<String>                   usedFields; // must track outside of resultFields.Keys () cuz input key could differ from output
    for (const auto& fi : fNamedFields) {
        String srcKey = Memory::NullCoalesce (fi.fVariantValueFieldName, fi.fName);
        if (auto oFieldVal = actualFields.Lookup (srcKey)) {
            if (fi.fVariantType) {
                resultFields.Add (fi.fName, oFieldVal->ConvertTo (*fi.fVariantType));
            }
            else {
                resultFields.Add (fi.fName, *oFieldVal);
            }
            usedFields += srcKey;
        }
        else if (fi.fRequired) {
            // throw or assert?
            AssertNotReached ();
        }
    }
    // now fold remaining fields into special 'extra' field (for structured non-indexed/non-searchable data)
    Set<String> fields2Accumulate = Set<String>{actualFields.Keys ()} - usedFields;
    if (fSpecialCatchAll.has_value () and not fields2Accumulate.empty ()) {
        Mapping<String, VariantValue> extraFields;
        for (auto i : fields2Accumulate) {
            extraFields.Add (i, *actualFields.Lookup (i));
        }
        // convert to JSON and store as string
        auto mapperFieldsToCombinedField = fSpecialCatchAll->fMapRawFieldsToCombinedField != nullptr ? fSpecialCatchAll->fMapRawFieldsToCombinedField : CatchAllField::kDefaultMapper_RawToCombined;
        resultFields.Add (fSpecialCatchAll->fName, mapperFieldsToCombinedField (extraFields));
    }
    else {
        Require (fields2Accumulate.empty () or fSpecialCatchAll.has_value ());
    }
#if USE_NOISY_TRACE_IN_THIS_MODULE_
    DbgTrace (L"returning: %s", Characters::ToString (vv).c_str ());
#endif
    return resultFields;
}

Mapping<String, VariantValue> ORM::Schema::Table::MapFromDB (const VariantValue& vv) const
{
    Mapping<String, VariantValue> actualFields = vv.As<Mapping<String, VariantValue>> ();
    Mapping<String, VariantValue> resultFields;
    for (const auto& fi : fNamedFields) {
        if (auto oFieldVal = actualFields.Lookup (fi.fName)) {
            if (fi.fVariantType) {
                resultFields.Add (fi.fName, oFieldVal->ConvertTo (*fi.fVariantType));
            }
            else {
                resultFields.Add (fi.fName, *oFieldVal);
            }
        }
        else if (fi.fRequired) {
            // throw or assert?
        }
    }
    // now fold remaining fields into special 'extra' field (for structured non-indexed/non-searchable data)
    if (fSpecialCatchAll.has_value ()) {
        if (auto o = actualFields.Lookup (fSpecialCatchAll->fName)) {
            auto mapperCombinedToRawFields = fSpecialCatchAll->fMapCombinedFieldToRawFields != nullptr ? fSpecialCatchAll->fMapCombinedFieldToRawFields : CatchAllField::kDefaultMapper_CombinedToRaw;
            resultFields.AddAll (mapperCombinedToRawFields (*o));
        }
    }
    else {
        // @todo maybe check fNamedFields contains all the actual fields??? Maybe OK to not check
    }
    return resultFields;
}

namespace {
    String GetSQLiteFldName_ (const ORM::Schema::Field& f)
    {
        if (f.fVariantType) {
            switch (*f.fVariantType) {
                case VariantValue::eBLOB:
                    return L"BLOB"sv;
                case VariantValue::eDate:
                case VariantValue::eDateTime:
                case VariantValue::eString:
                    return L"TEXT"sv;
                case VariantValue::eBoolean:
                case VariantValue::eInteger:
                case VariantValue::eUnsignedInteger:
                    return L"INT"sv;
                case VariantValue::eFloat:
                    return L"REAL"sv;
            }
        }
        return L"TEXT"sv; // @todo better
    }
}

String ORM::Schema::Table::GetSQLToCreateTable () const
{
    StringBuilder sb;

    /*
     *   CREATE TABLE DEVICES(
     *      ID BLOB PRIMARY KEY DEFAULT(randomblob(16)),
     *      NAME           TEXT    NOT NULL
     *     );
     */
    sb += L"CREATE TABLE " + fName + L" (";
    bool firstField = true;
    auto addField   = [&] (const Field& fi) {
        if (firstField) {
            firstField = false;
        }
        else {
            sb += L", ";
        }
        sb += fi.fName + L" ";
        sb += GetSQLiteFldName_ (fi) + L" ";
        if (fi.fIsKeyField == true) {
            sb += L" PRIMARY KEY";
        }
        if (fi.fDefaultExpression) {
            sb += L" DEFAULT(" + *fi.fDefaultExpression + L")";
        }
        if (fi.fNotNull == true) {
            sb += L" NOT NULL";
        }
    };
    for (const Field& i : fNamedFields) {
        addField (i);
    }
    if (fSpecialCatchAll) {
        addField (*fSpecialCatchAll);
    }
    sb += L");";

    return sb.str ();
}

String ORM::Schema::Table::GetSQLToInsert () const
{
    StringBuilder sb;

    /*
     *   INSERT INTO DEVICES (name) values (:NAME);
     */
    sb += L"INSERT INTO " + fName + L" (";
    bool firstField   = true;
    auto addFieldName = [&] (const Field& fi) {
        if (firstField) {
            firstField = false;
        }
        else {
            sb += L", ";
        }
        sb += fi.fName;
    };
    for (const Field& i : fNamedFields) {
        addFieldName (i);
    }
    if (fSpecialCatchAll) {
        addFieldName (*fSpecialCatchAll);
    }
    sb += L") VALUES (";
    firstField                     = true;
    auto addFieldValueVariableName = [&] (const Field& fi) {
        if (firstField) {
            firstField = false;
        }
        else {
            sb += L", ";
        }
        sb += L":" + fi.fName;
    };
    for (const Field& i : fNamedFields) {
        addFieldValueVariableName (i);
    }
    if (fSpecialCatchAll) {
        addFieldValueVariableName (*fSpecialCatchAll);
    }
    sb += L");";
    return sb.str ();
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2007 <SWGEmu>

This File is part of Core3.

This program is free software; you can redistribute
it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software
Foundation; either version 2 of the License,
or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for
more details.

You should have received a copy of the GNU Lesser General
Public License along with this program; if not, write to
the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

Linking Engine3 statically or dynamically with other modules
is making a combined work based on Engine3.
Thus, the terms and conditions of the GNU Lesser General Public License
cover the whole combination.

In addition, as a special exception, the copyright holders of Engine3
give you permission to combine Engine3 program with free software
programs or libraries that are released under the GNU LGPL and with
code included in the standard release of Core3 under the GNU LGPL
license (or modified versions of such code, with unchanged license).
You may copy and distribute such a system following the terms of the
GNU LGPL for Engine3 and the licenses of the other code concerned,
provided that you include the source code of that other code when
and as the GNU LGPL requires distribution of source code.

Note that people who make modified versions of Engine3 are not obligated
to grant this special exception for their modified versions;
it is their choice whether to do so. The GNU Lesser General Public License
gives permission to release a modified version without this exception;
this exception also makes it possible to release a modified version
which carries forward this exception.
*/

#include "ChatRoom.h"

#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "server/zone/ZoneServer.h"

#include "server/zone/packets/chat/ChatRoomList.h"
#include "server/zone/packets/chat/ChatOnDestroyRoom.h"
#include "server/zone/packets/chat/ChatOnLeaveRoom.h"
#include "server/zone/packets/chat/ChatOnEnteredRoom.h"
#include "server/zone/managers/objectcontroller/ObjectController.h"

void ChatRoomImplementation::sendTo(CreatureObject* player) {
	ChatRoomList* crl = new ChatRoomList();
	crl->addChannel(_this.get());

	crl->insertChannelListCount();
	player->sendMessage(crl);
}

void ChatRoomImplementation::sendDestroyTo(CreatureObject* player) {
	ChatOnDestroyRoom* msg = new ChatOnDestroyRoom("SWG", server->getGalaxyName(), roomID);
	player->sendMessage(msg);
}

void ChatRoomImplementation::addPlayer(CreatureObject* player, bool doLock) {
	Locker locker(_this.get());

	if (playerList.put(player->getFirstName(), player) == -1) {
		//return;
	}

	ChatOnEnteredRoom* coer = new ChatOnEnteredRoom(server->getGalaxyName(), player->getFirstName(), roomID);
	player->sendMessage(coer);

	locker.release();

	Locker locker2(player);

	PlayerObject* ghost = player->getPlayerObject();

	ghost->addChatRoom(_this.get());

	/*ChatOnReceiveRoomInvitation* corri = new ChatOnReceiveRoomInvitation(name);
	player->sendMessage(corri);*/

}

void ChatRoomImplementation::removePlayer(CreatureObject* player, bool doLock) {
	Locker locker(player);

	PlayerObject* ghost = player->getPlayerObject();

	ghost->removeChatRoom(_this.get());

	locker.release();

	Locker locker2(_this.get());

	playerList.drop(player->getFirstName());

	ChatOnLeaveRoom* msg = new ChatOnLeaveRoom(_this.get(), player);
	player->sendMessage(msg);
}

void ChatRoomImplementation::removePlayer(const String& player) {
	// Pre: player unlocked
	Locker locker(_this.get());

	CreatureObject* play = playerList.get(player);
	playerList.drop(player);

	locker.release();

	if (play == NULL)
		return;

	Locker locker2(play);

	PlayerObject* ghost = play->getPlayerObject();

	ghost->removeChatRoom(_this.get());

	ChatOnLeaveRoom* msg = new ChatOnLeaveRoom(_this.get(), play);
	play->sendMessage(msg);
}

void ChatRoomImplementation::broadcastMessage(BaseMessage* msg) {
	for (int i = 0; i < playerList.size(); ++i) {
		CreatureObject* player = playerList.get(i);
		player->sendMessage(msg->clone());
	}

	delete msg;
}

void ChatRoomImplementation::removeAllPlayers() {
	Locker locker(_this.get());

	for (int i = 0; i < playerList.size(); i++) {
		CreatureObject* player = playerList.get(i);

		Locker clocker(player, _this.get());

		PlayerObject* ghost = player->getPlayerObject();

		ghost->removeChatRoom(_this.get());
	}

	playerList.removeAll();
}

String ChatRoomImplementation::getGalaxyName() {
	return server->getGalaxyName();
}
<commit_msg>[fixed] stability issue<commit_after>/*
Copyright (C) 2007 <SWGEmu>

This File is part of Core3.

This program is free software; you can redistribute
it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software
Foundation; either version 2 of the License,
or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for
more details.

You should have received a copy of the GNU Lesser General
Public License along with this program; if not, write to
the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

Linking Engine3 statically or dynamically with other modules
is making a combined work based on Engine3.
Thus, the terms and conditions of the GNU Lesser General Public License
cover the whole combination.

In addition, as a special exception, the copyright holders of Engine3
give you permission to combine Engine3 program with free software
programs or libraries that are released under the GNU LGPL and with
code included in the standard release of Core3 under the GNU LGPL
license (or modified versions of such code, with unchanged license).
You may copy and distribute such a system following the terms of the
GNU LGPL for Engine3 and the licenses of the other code concerned,
provided that you include the source code of that other code when
and as the GNU LGPL requires distribution of source code.

Note that people who make modified versions of Engine3 are not obligated
to grant this special exception for their modified versions;
it is their choice whether to do so. The GNU Lesser General Public License
gives permission to release a modified version without this exception;
this exception also makes it possible to release a modified version
which carries forward this exception.
*/

#include "ChatRoom.h"

#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "server/zone/ZoneServer.h"

#include "server/zone/packets/chat/ChatRoomList.h"
#include "server/zone/packets/chat/ChatOnDestroyRoom.h"
#include "server/zone/packets/chat/ChatOnLeaveRoom.h"
#include "server/zone/packets/chat/ChatOnEnteredRoom.h"
#include "server/zone/managers/objectcontroller/ObjectController.h"

void ChatRoomImplementation::sendTo(CreatureObject* player) {
	ChatRoomList* crl = new ChatRoomList();
	crl->addChannel(_this.get());

	crl->insertChannelListCount();
	player->sendMessage(crl);
}

void ChatRoomImplementation::sendDestroyTo(CreatureObject* player) {
	ChatOnDestroyRoom* msg = new ChatOnDestroyRoom("SWG", server->getGalaxyName(), roomID);
	player->sendMessage(msg);
}

void ChatRoomImplementation::addPlayer(CreatureObject* player, bool doLock) {
	Locker locker(_this.get());

	if (playerList.put(player->getFirstName(), player) == -1) {
		//return;
	}

	ChatOnEnteredRoom* coer = new ChatOnEnteredRoom(server->getGalaxyName(), player->getFirstName(), roomID);
	player->sendMessage(coer);

	locker.release();

	Locker locker2(player);

	PlayerObject* ghost = player->getPlayerObject();

	ghost->addChatRoom(_this.get());

	/*ChatOnReceiveRoomInvitation* corri = new ChatOnReceiveRoomInvitation(name);
	player->sendMessage(corri);*/

}

void ChatRoomImplementation::removePlayer(CreatureObject* player, bool doLock) {
	Locker locker(player);

	PlayerObject* ghost = player->getPlayerObject();

	ghost->removeChatRoom(_this.get());

	locker.release();

	Locker locker2(_this.get());

	playerList.drop(player->getFirstName());

	ChatOnLeaveRoom* msg = new ChatOnLeaveRoom(_this.get(), player);
	player->sendMessage(msg);
}

void ChatRoomImplementation::removePlayer(const String& player) {
	// Pre: player unlocked
	Locker locker(_this.get());

	ManagedReference<CreatureObject*> play = playerList.get(player);
	playerList.drop(player);

	locker.release();

	if (play == NULL)
		return;

	Locker locker2(play);

	PlayerObject* ghost = play->getPlayerObject();

	ghost->removeChatRoom(_this.get());

	ChatOnLeaveRoom* msg = new ChatOnLeaveRoom(_this.get(), play);
	play->sendMessage(msg);
}

void ChatRoomImplementation::broadcastMessage(BaseMessage* msg) {
	Locker locker(_this.get());

	for (int i = 0; i < playerList.size(); ++i) {
		ManagedReference<CreatureObject*> player = playerList.get(i);

		if (player)
			player->sendMessage(msg->clone());
	}

	delete msg;
}

void ChatRoomImplementation::removeAllPlayers() {
	Locker locker(_this.get());

	for (int i = 0; i < playerList.size(); i++) {
		ManagedReference<CreatureObject*> player = playerList.get(i);

		Locker clocker(player, _this.get());

		PlayerObject* ghost = player->getPlayerObject();

		ghost->removeChatRoom(_this.get());
	}

	playerList.removeAll();
}

String ChatRoomImplementation::getGalaxyName() {
	return server->getGalaxyName();
}
<|endoftext|>