#include <LRModel.h>
#include <Utils.h>
#include <MlUtils.h>
#include <Eigen/Dense>
#include <Checksum.h>
#include <algorithm>

namespace cirrus {

LRModel::LRModel(uint64_t d) {
    weights_.resize(d);
}

LRModel::LRModel(const FEATURE_TYPE* w, uint64_t d) {
    weights_.resize(d);
    std::copy(w, w + d, weights_.begin());
}

uint64_t LRModel::size() const {
  return weights_.size();
}

/**
  * Serialization / deserialization routines
  */

/** FORMAT
  * weights
  */
std::unique_ptr<CirrusModel> LRModel::deserialize(void* data, uint64_t size) const {
    uint64_t d = size / sizeof(FEATURE_TYPE);
    std::unique_ptr<LRModel> model = std::make_unique<LRModel>(
            reinterpret_cast<FEATURE_TYPE*>(data), d);
    return model;
}

std::pair<std::unique_ptr<char[]>, uint64_t>
LRModel::serialize() const {
    std::pair<std::unique_ptr<char[]>, uint64_t> res;
    uint64_t size = getSerializedSize();
    res.first.reset(new char[size]);

    res.second = size;
    std::memcpy(res.first.get(), weights_.data(), getSerializedSize());

    return res;
}

void LRModel::serializeTo(void* mem) const {
    std::memcpy(mem, weights_.data(), getSerializedSize());
}

uint64_t LRModel::getSerializedSize() const {
    return size() * sizeof(FEATURE_TYPE);
}

void LRModel::loadSerialized(const void* data) {
    const FEATURE_TYPE* v = reinterpret_cast<const FEATURE_TYPE*>(data);
    std::copy(v, v + size(), weights_.begin());
}

/***
   *
   */

void LRModel::randomize() {
    for (auto& w : weights_) {
        w = 0.001 + get_rand_between_0_1();
    }
}

std::unique_ptr<CirrusModel> LRModel::copy() const {
    std::unique_ptr<LRModel> new_model =
        std::make_unique<LRModel>(weights_.data(), size());
    return new_model;
}

void LRModel::sgd_update(double learning_rate,
        const ModelGradient* gradient) {
    const LRGradient* grad = dynamic_cast<const LRGradient*>(gradient);

    if (grad == nullptr) {
        throw std::runtime_error("Error in dynamic cast");
    }

    for (uint64_t i = 0; i < size(); ++i) {
       weights_[i] += learning_rate * grad->weights[i];
    }
}

std::unique_ptr<ModelGradient> LRModel::minibatch_grad(
        const Matrix& dataset,
        FEATURE_TYPE* labels,
        uint64_t labels_size,
        double epsilon) const {
    auto w = weights_;
#ifdef DEBUG
    dataset.check();
#endif

    if (dataset.cols != size() || labels_size != dataset.rows) {
      throw std::runtime_error("Sizes don't match");
    }

    const FEATURE_TYPE* dataset_data = dataset.data.get();
    // create Matrix for dataset
    Eigen::Map<Eigen::Matrix<FEATURE_TYPE, Eigen::Dynamic,
        Eigen::Dynamic, Eigen::RowMajor>>
          ds(const_cast<FEATURE_TYPE*>(dataset_data), dataset.rows, dataset.cols);

    // create weight vector
    Eigen::Map<Eigen::Matrix<FEATURE_TYPE, -1, 1>> tmp_weights(w.data(), size());

    // create vector with labels
    Eigen::Map<Eigen::Matrix<FEATURE_TYPE, -1, 1>> lab(labels, labels_size);

    // apply logistic function to matrix multiplication
    // between dataset and weights
    auto part1_1 = (ds * tmp_weights);
    auto part1 = part1_1.unaryExpr(std::ptr_fun(s_1_float)); // XXX fix this

    Eigen::Map<Eigen::Matrix<FEATURE_TYPE, -1, 1>> lbs(labels, labels_size);

    // compute difference between labels and logistic probability
    auto part2 = lbs - part1;
    auto part3 = ds.transpose() * part2;
    auto part4 = tmp_weights * 2 * epsilon;
    auto res = part4 + part3;

    std::vector<FEATURE_TYPE> vec_res;
    vec_res.resize(res.size());
    Eigen::Matrix<FEATURE_TYPE, -1, 1>::Map(vec_res.data(), res.size()) = res;

    std::unique_ptr<LRGradient> ret = std::make_unique<LRGradient>(vec_res);

#ifdef DEBUG
    ret->check_values();
#endif

    return ret;
}

std::pair<double, double> LRModel::calc_loss(Dataset& dataset) const {
  double total_loss = 0;
  auto w = weights_;

#ifdef DEBUG
  dataset.check();
#endif

  const FEATURE_TYPE* ds_data =
    reinterpret_cast<const FEATURE_TYPE*>(dataset.samples_.data.get());

  Eigen::Map<Eigen::Matrix<FEATURE_TYPE, Eigen::Dynamic,
    Eigen::Dynamic, Eigen::RowMajor>>
      ds(const_cast<FEATURE_TYPE*>(ds_data),
          dataset.samples_.rows, dataset.samples_.cols);

  Eigen::Map<Eigen::Matrix<FEATURE_TYPE, -1, 1>> weights_eig(w.data(), size());

  // count how many samples are wrongly classified
  uint64_t wrong_count = 0;
  for (uint64_t i = 0; i < dataset.num_samples(); ++i) {
    // get labeled class for the ith sample
    FEATURE_TYPE class_i =
      reinterpret_cast<const FEATURE_TYPE*>(dataset.labels_.get())[i];

    assert(is_integer(class_i));

    int predicted_class = 0;

    auto r1 = ds.row(i) *  weights_eig;
    if (s_1((FEATURE_TYPE)r1) > 0.5) {
      predicted_class = 1;
    }
    if (predicted_class != class_i) {
      wrong_count++;
    }

    FEATURE_TYPE v1 = log_aux(1 - s_1((FEATURE_TYPE)(ds.row(i) * weights_eig)));
    FEATURE_TYPE v2 = log_aux(s_1((FEATURE_TYPE)(ds.row(i) *  weights_eig)));

    FEATURE_TYPE value = class_i * v2 + (1 - class_i) * v1;

    // XXX not sure this check is necessary
    if (value > 0 && value < 1e-6)
      value = 0;

    if (value > 0) {
      std::cout << "ds row: " << std::endl << ds.row(i) << std::endl;
      std::cout << "weights: " << std::endl << weights_eig << std::endl;
      std::cout << "Class: " << class_i << " " << v1 << " " << v2
        << std::endl;
      throw std::runtime_error("Error: logistic loss is > 0");
    }

    total_loss -= value;
  }

  if (total_loss < 0) {
    throw std::runtime_error("total_loss < 0");
  }

  FEATURE_TYPE accuracy = (1.0 - (1.0 * wrong_count / dataset.num_samples()));
  if (std::isnan(total_loss) || std::isinf(total_loss))
    throw std::runtime_error("calc_log_loss generated nan/inf");

  return std::make_pair(total_loss, accuracy);
}

uint64_t LRModel::getSerializedGradientSize() const {
    return size() * sizeof(FEATURE_TYPE);
}

std::unique_ptr<ModelGradient> LRModel::loadGradient(void* mem) const {
    auto grad = std::make_unique<LRGradient>(size());

    for (uint64_t i = 0; i < size(); ++i) {
        grad->weights[i] = reinterpret_cast<FEATURE_TYPE*>(mem)[i];
    }

    return grad;
}

bool LRModel::is_integer(FEATURE_TYPE n) const {
    return floor(n) == n;
}

double LRModel::checksum() const {
    return crc32(weights_.data(), weights_.size() * sizeof(FEATURE_TYPE));
}

void LRModel::print() const {
    std::cout << "MODEL: ";
    for (const auto& w : weights_) {
        std::cout << " " << w;
    }
    std::cout << std::endl;
}

} // namespace cirrus


//==============================================================================
//         Copyright 2003 - 2011 LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011 LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef BOOST_SIMD_OPERATOR_FUNCTIONS_SIMD_SSE_SSE2_IS_GREATER_HPP_INCLUDED
#define BOOST_SIMD_OPERATOR_FUNCTIONS_SIMD_SSE_SSE2_IS_GREATER_HPP_INCLUDED
#ifdef BOOST_SIMD_HAS_SSE2_SUPPORT
#include <boost/simd/operator/functions/is_greater.hpp>
#include <boost/simd/include/functions/simd/is_equal.hpp>
#include <boost/simd/include/functions/simd/logical_or.hpp>
#include <boost/simd/include/functions/simd/logical_and.hpp>
#include <boost/simd/sdk/simd/logical.hpp>
#include <boost/dispatch/meta/downgrade.hpp>
#include <boost/dispatch/meta/as_integer.hpp>
#include <boost/simd/swar/functions/details/shuffle.hpp>

namespace boost { namespace simd { namespace ext
{
  BOOST_SIMD_FUNCTOR_IMPLEMENTATION( boost::simd::tag::is_greater_, boost::simd::tag::sse2_
                            , (A0)
                            , ((simd_<double_<A0>,boost::simd::tag::sse_>))
                              ((simd_<double_<A0>,boost::simd::tag::sse_>))
                            )
  {
    typedef typename meta::as_logical<A0>::type result_type;
    BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      return _mm_cmpgt_pd(a0,a1);
    }
  };

  BOOST_SIMD_FUNCTOR_IMPLEMENTATION( boost::simd::tag::is_greater_, boost::simd::tag::sse2_
                            , (A0)
                            , ((simd_<single_<A0>,boost::simd::tag::sse_>))
                              ((simd_<single_<A0>,boost::simd::tag::sse_>))
                            )
  {
    typedef typename meta::as_logical<A0>::type result_type;

    BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      return _mm_cmpgt_ps(a0,a1);
    }
  };

  BOOST_SIMD_FUNCTOR_IMPLEMENTATION( boost::simd::tag::is_greater_, boost::simd::tag::sse2_
                            , (A0)
                            , ((simd_<unsigned_<A0>,boost::simd::tag::sse_>))
                              ((simd_<unsigned_<A0>,boost::simd::tag::sse_>))
                            )
  {
    typedef typename meta::as_logical<A0>::type result_type;

    BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      typedef typename dispatch::meta::as_integer<A0, signed>::type stype;
      return  bitwise_cast<result_type>
              ( boost::simd::gt ( bitwise_cast<stype>(a0) - Signmask<stype>()
                        , bitwise_cast<stype>(a1) - Signmask<stype>()
                        )
              );
    }
  };

  BOOST_SIMD_FUNCTOR_IMPLEMENTATION( boost::simd::tag::is_greater_, boost::simd::tag::sse2_
                            , (A0)
                            , ((simd_<int8_<A0>,boost::simd::tag::sse_>))
                              ((simd_<int8_<A0>,boost::simd::tag::sse_>))
                            )
  {
    typedef typename meta::as_logical<A0>::type result_type;

    BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      return _mm_cmpgt_epi8(a0,a1);
    }
  };

  BOOST_SIMD_FUNCTOR_IMPLEMENTATION( boost::simd::tag::is_greater_, boost::simd::tag::sse2_
                            , (A0)
                            , ((simd_<int16_<A0>,boost::simd::tag::sse_>))
                              ((simd_<int16_<A0>,boost::simd::tag::sse_>))
                            )
  {
    typedef typename meta::as_logical<A0>::type result_type;

    BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      return _mm_cmpgt_epi16(a0,a1);
    }
  };

  BOOST_SIMD_FUNCTOR_IMPLEMENTATION( boost::simd::tag::is_greater_, boost::simd::tag::sse2_
                            , (A0)
                            , ((simd_<int32_<A0>,boost::simd::tag::sse_>))
                              ((simd_<int32_<A0>,boost::simd::tag::sse_>))
                            )
  {
    typedef typename meta::as_logical<A0>::type result_type;

    BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      return _mm_cmpgt_epi32(a0,a1);
    }
  };

  BOOST_SIMD_FUNCTOR_IMPLEMENTATION( boost::simd::tag::is_greater_, boost::simd::tag::sse2_
                            , (A0)
                            , ((simd_<int64_<A0>,boost::simd::tag::sse_>))
                              ((simd_<int64_<A0>,boost::simd::tag::sse_>))
                            )
  {
    typedef typename meta::as_logical<A0>::type result_type;

    BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      typedef typename dispatch::meta::downgrade<A0, signed>::type type;
      typedef typename dispatch::meta::downgrade<A0, unsigned>::type utype;
      utype al = details::shuffle<0,0,2,2>(a0);
      utype bl = details::shuffle<0,0,2,2>(a1);
      type ah  = details::shuffle<1,1,3,3>(a0);
      type bh  = details::shuffle<1,1,3,3>(a1);

      return bitwise_cast<result_type>( l_or(boost::simd::gt(ah,bh), l_and(boost::simd::eq(ah,bh), boost::simd::gt(al,bl))) );
    }
  };
} } }

#endif
#endif


#ifndef HOPS_DIKINELLIPSOIDCALCULATOR_HPP
#define HOPS_DIKINELLIPSOIDCALCULATOR_HPP

#include <Eigen/Cholesky>
#include <Eigen/Core>
#include <Eigen/Dense>
#include "../../FileWriter/CsvWriter.hpp"

namespace hops {
    template<typename MatrixType, typename VectorType>
    class DikinEllipsoidCalculator {
    public:
        DikinEllipsoidCalculator(MatrixType A, VectorType b);

        std::pair<bool, Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic>>
        computeCholeskyFactorOfDikinEllipsoid(const VectorType &x);

        Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic>
        computeDikinEllipsoid(const VectorType &x);

    private:
        MatrixType A;
        VectorType b;
    };

    template<typename MatrixType, typename VectorType>
    DikinEllipsoidCalculator<MatrixType, VectorType>::DikinEllipsoidCalculator(MatrixType A, VectorType b) :
            A(std::move(A)), b(std::move(b)) {}

    template<typename MatrixType, typename VectorType>
    std::pair<bool, Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic>>
    DikinEllipsoidCalculator<MatrixType, VectorType>::computeCholeskyFactorOfDikinEllipsoid(const VectorType &x) {
        Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic> dikinEllipsoid =
                computeDikinEllipsoid(x);

        Eigen::LLT<Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic>> solver(dikinEllipsoid);
        bool successful = solver.info() == Eigen::Success;
        return std::make_pair(successful, solver.matrixL());
    }

    template<typename MatrixType, typename VectorType>
    Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic>
    DikinEllipsoidCalculator<MatrixType, VectorType>::computeDikinEllipsoid(const VectorType &x) {
        Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, 1> inv_slack = (this->b -
                                                                                this->A * x).cwiseInverse();

        Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic> halfDikin =
                inv_slack.asDiagonal() * this->A;
        Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic> dikin =
                halfDikin.transpose() * halfDikin;
        return dikin;
    }
}

#endif //HOPS_DIKINELLIPSOIDCALCULATOR_HPP


#ifndef LIVEODR_DETECTORS_MMOD_FACE_DETECTOR_HPP
#define LIVEODR_DETECTORS_MMOD_FACE_DETECTOR_HPP

#include "detector.hpp"
#include "../utils.hpp"

#include <dlib/dnn.h>
#include <dlib/opencv.h>

#include <string_view>
#include <string>
#include <vector>

namespace liveodr {
    class MMODFaceDetector : virtual public IDetector {
    public:
        MMODFaceDetector() {
            load("data/mmod_human_face_detector.dat");
        }

        MMODFaceDetector(std::string_view model) {
            load(model);
        }

        void load(std::string_view model) {
            dlib::deserialize(std::string(model)) >> detector;
        }

        const std::vector<cv::Rect> process(cv::Mat input) override {
            cv::Mat input_rgb;
            cv::cvtColor(input, input_rgb, cv::COLOR_BGR2RGB);

            dlib::matrix<dlib::rgb_pixel> converted_input;
            dlib::assign_image(converted_input, dlib::cv_image<dlib::rgb_pixel>(input_rgb));

            std::vector<cv::Rect> rects;
            for(auto&& r : detector(converted_input))
                if(r.detection_confidence  > 0.8)
                    rects.push_back(liveodr::utils::dlib_to_opencv_rect(r.rect));
            return rects;
        };

    private:
        template <long num_filters, typename SUBNET> using con5d = dlib::con<num_filters,5,5,2,2,SUBNET>;
        template <long num_filters, typename SUBNET> using con5  = dlib::con<num_filters,5,5,1,1,SUBNET>;

        template <typename SUBNET> using downsampler  = dlib::relu<dlib::affine<con5d<32, dlib::relu<dlib::affine<con5d<32, dlib::relu<dlib::affine<con5d<16,SUBNET>>>>>>>>>;
        template <typename SUBNET> using rcon5  = dlib::relu<dlib::affine<con5<45,SUBNET>>>;

        using net_type = dlib::loss_mmod<dlib::con<1,9,9,1,1,rcon5<rcon5<rcon5<downsampler<dlib::input_rgb_image_pyramid<dlib::pyramid_down<6>>>>>>>>;

        net_type detector;
    };
}

#endif /* ifndef LIVEODR_DETECTORS_MMOD_FACE_DETECTOR_HPP */


/*
 Copyright (C) 2021 Quaternion Risk Management Ltd
 All rights reserved.

 This file is part of ORE, a free-software/open-source library
 for transparent pricing and risk analysis - http://opensourcerisk.org

 ORE is free software: you can redistribute it and/or modify it
 under the terms of the Modified BSD License.  You should have received a
 copy of the license along with this program.
 The license is also available online at <http://opensourcerisk.org>

 This program is distributed on the basis that it will form a useful
 contribution to risk analytics and model standardisation, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
*/

#include <ored/portfolio/builders/capflooredaverageonindexedcouponleg.hpp>
#include <ored/utilities/log.hpp>

#include <qle/cashflows/blackovernightindexedcouponpricer.hpp>

#include <boost/make_shared.hpp>

namespace ore {
namespace data {

boost::shared_ptr<FloatingRateCouponPricer>
CapFlooredAverageONIndexedCouponLegEngineBuilder::engineImpl(const Currency& ccy) {

    // Check if we already have a pricer for this ccy
    const string& ccyCode = ccy.code();
    if (engines_.find(ccyCode) == engines_.end()) {
        Handle<YieldTermStructure> yts = market_->discountCurve(ccyCode, configuration(MarketContext::pricing));
        QL_REQUIRE(!yts.empty(), "engineFactory error: yield term structure not found for currency " << ccyCode);
        Handle<OptionletVolatilityStructure> ovs = market_->capFloorVol(ccyCode, configuration(MarketContext::pricing));
        boost::shared_ptr<FloatingRateCouponPricer> pricer =
            boost::make_shared<QuantExt::BlackAverageONIndexedCouponPricer>(ovs);
        engines_[ccyCode] = pricer;
    }

    // Return the cached pricer
    return engines_[ccyCode];
}
} // namespace data
} // namespace ore


//==================================================================================================
/**
  Copyright 2016 NumScale SAS

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

#include <boost/simd/detail/overload.hpp>
#include <boost/simd/constant/one.hpp>
#include <boost/simd/constant/valmax.hpp>
#include <boost/simd/constant/zero.hpp>
#include <boost/simd/function/abs.hpp>
#include <boost/simd/function/raw.hpp>
#include <boost/simd/function/sign.hpp>

namespace boost { namespace simd { namespace ext
{
  namespace bd = boost::dispatch;
  namespace bs = boost::simd;

#ifdef BOOST_MSVC
  #pragma warning(push)
  #pragma warning(disable: 4723) // potential divide by 0
#endif

  BOOST_DISPATCH_OVERLOAD ( rec_
                          , (typename A0)
                          , bd::cpu_
                          , bd::scalar_< bd::floating_<A0> >
                          )
  {
    BOOST_FORCEINLINE A0 operator() ( A0 a0) const BOOST_NOEXCEPT
    {
      return One<A0>()/a0;
    }
  };

  BOOST_DISPATCH_OVERLOAD ( rec_
                          , (typename A0)
                          , bd::cpu_
                          , bd::scalar_< bd::arithmetic_<A0> >
                          )
  {
    BOOST_FORCEINLINE A0 operator() ( A0 a0) const BOOST_NOEXCEPT
    {
      return (a0 ? ((bs::abs(a0) == One<A0>()) ? sign(a0) : Zero<A0>()) : Valmax<A0>());
    }
  };

  BOOST_DISPATCH_OVERLOAD ( rec_
                          , (typename T)
                          , bd::cpu_
                          , bs::raw_tag
                          , bd::scalar_<bd::unspecified_<T>>
                          )
  {
    BOOST_FORCEINLINE T operator()(const raw_tag &, T a) const BOOST_NOEXCEPT
    {
      return rec(a);
    }
  };
} } }

#ifdef BOOST_MSVC
  #pragma warning(pop)
#endif

#endif


// ======================================================================
/*!
 * \file NFmiRect.cpp
 * \brief Implementation of class NFmiRect
 */
// ======================================================================
/*!
 * \class NFmiRect
 *
 * Undocumented
 *
 */
// ======================================================================

#include "NFmiRect.h"
#include <boost/functional/hash.hpp>
#include <macgyver/Exception.h>
#include <algorithm>
#include <fstream>

// ----------------------------------------------------------------------
/*!
 * Constructor
 *
 * \param firstCorner Undocumented
 * \param oppositeCorner Undocumented
 */
// ----------------------------------------------------------------------

NFmiRect::NFmiRect(const NFmiPoint &firstCorner, const NFmiPoint &oppositeCorner)
    : itsPlace(std::min(firstCorner.X(), oppositeCorner.X()),
               std::min(firstCorner.Y(), oppositeCorner.Y())),
      itsSize(NFmiPoint(std::max(firstCorner.X(), oppositeCorner.X()),
                        std::max(firstCorner.Y(), oppositeCorner.Y())) -
              itsPlace)
{
}

// ----------------------------------------------------------------------
/*!
 * Constructor
 *
 * \param left Undocumented
 * \param top Undocumented
 * \param right Undocumented
 * \param bottom Undocumented
 */
// ----------------------------------------------------------------------

NFmiRect::NFmiRect(double left, double top, double right, double bottom)
    : itsPlace(std::min(left, right), std::min(top, bottom)),
      itsSize(NFmiPoint(std::max(left, right), std::max(top, bottom)) - itsPlace)
{
}

// ----------------------------------------------------------------------
/*!
 * \param theValue Undocumented
 */
// ----------------------------------------------------------------------

void NFmiRect::Inflate(double theValue)
{
  try
  {
    itsSize += NFmiPoint(2 * theValue, 2 * theValue);
    itsPlace -= NFmiPoint(theValue, theValue);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \param theXValue Undocumented
 * \param theYValue Undocumented
 */
// ----------------------------------------------------------------------

void NFmiRect::Inflate(double theXValue, double theYValue)
{
  try
  {
    itsSize += NFmiPoint(2 * theXValue, 2 * theYValue);
    itsPlace -= NFmiPoint(theXValue, theYValue);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \param theValue Undocumented
 */
// ----------------------------------------------------------------------

void NFmiRect::Inflate(const NFmiPoint &theValue)
{
  try
  {
    NFmiPoint theSizingValue(theValue);
    theSizingValue += theValue;
    itsSize += theSizingValue;
    itsPlace -= theValue;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \param thePoint Undocumented
 * \return Undocumented
 */
// ----------------------------------------------------------------------

const NFmiPoint NFmiRect::NearestCorner(const NFmiPoint &thePoint) const
{
  try
  {
    double dLeftTop = TopLeft().Distance(thePoint);
    double dRightTop = TopRight().Distance(thePoint);
    double dLeftBottom = BottomLeft().Distance(thePoint);
    double dRightBottom = BottomRight().Distance(thePoint);

    if (dLeftTop <= dRightTop)
    {
      if (dLeftTop <= dLeftBottom)
        return TopLeft();
      else
        return BottomLeft();
    }
    else
    {
      if (dRightTop <= dRightBottom)
        return TopRight();
      else
        return BottomRight();
    }
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \param theRatioXperY Undocumented
 * \param fKeepX Undocumented
 * \param theDirection Undocumented
 * \return Undocumented
 */
// ----------------------------------------------------------------------

// Säätää rectin aspect ration halutuksi. fKeepX ollessa tosi ei muuteta
// x:n arvoja. Korjaukset tehdään halutun nurkan ('theDirection') suhteen
// eli valittu nurkka "pysyy paikallaan". Jos muutos on mahdoton (esim.
// aspectratio=0), palauttaa funktio false:n muuten true:n.

bool NFmiRect::AdjustAspectRatio(double theRatioXperY, bool fKeepX, FmiDirection theDirection)
{
  try
  {
    if (theRatioXperY == 0.)
      return false;

    NFmiRect originalRect(itsPlace, itsPlace + itsSize);  // 9.9.99/EL

    if (fKeepX)
      Size(NFmiPoint(Width(), Width() / theRatioXperY));
    else
      Size(NFmiPoint(theRatioXperY * Height(), Height()));

    double newWidth = Width();
    double newHeight = Height();

    // Origona on nurkka 'kTopLeft' missä (X,Y) = TopLeft()
    // X kasvaa "vasemmalta oikealle"
    // Y kasvaa "ylhäältä alas"

    switch (theDirection)
    {
      case kTopLeft:
        return true;  // Nurkka on origossa - Place() pysyy paikallaan

      case kTopRight:
        Place(NFmiPoint(originalRect.TopRight().X() - newWidth, TopRight().Y()));
        return true;

      case kBottomLeft:
        Place(NFmiPoint(originalRect.BottomLeft().X(), originalRect.BottomLeft().Y() - newHeight));
        return true;

      case kBottomRight:
        Place(NFmiPoint(originalRect.BottomRight().X() - newWidth,
                        originalRect.BottomRight().Y() - newHeight));
        return true;

      case kCenter:
        Center(originalRect.Center());
        return true;

      default:
        return false;
    }
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * Projisoi annetun maailma koordinaatin siten että jos piste on rectin
 * sisällä, palautettu rect saa arvon 0,0 - 1,1 sen mukaan miten se rectin
 * sisään osui. Origo on top-left ja 1,1 on bottom-right kulma. Jos se on
 * ruudun ulkona, tulee mukaan mahdolliset negatiiviset ja 1:stä suuremmat arvot.
 *
 * \param thePoint The relative world point that is projected to rect dimensions.
 * \return The given point in rect's world coordinates.
 */
// ----------------------------------------------------------------------
const NFmiPoint NFmiRect::Project(const NFmiPoint &thePlace) const
{
  try
  {
    NFmiPoint newPoint = thePlace - TopLeft();
    return NFmiPoint(newPoint.X() / Width(), newPoint.Y() / Height());
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * Assignment operator
 *
 * \param thePoint The other object being assigned
 * \return The assigned object
 */
// ----------------------------------------------------------------------

NFmiRect &NFmiRect::operator+=(const NFmiPoint &thePoint)
{
  try
  {
    itsPlace += thePoint;
    return *this;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * Substraction operator
 *
 * \param thePoint The coordinates being substracted
 * \return The resulting rectangle
 */
// ----------------------------------------------------------------------

NFmiRect &NFmiRect::operator-=(const NFmiPoint &thePoint)
{
  try
  {
    itsPlace -= thePoint;
    return *this;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * Addition operator
 *
 * \param theRect The rectangle being added
 * \return The resulting rectangle
 */
// ----------------------------------------------------------------------

NFmiRect &NFmiRect::operator+=(const NFmiRect &theRect)
{
  try
  {
    itsPlace = NFmiPoint(Left() < theRect.Left() ? Left() : theRect.Left(),
                         Top() < theRect.Top() ? Top() : theRect.Top());

    itsSize = NFmiPoint(Right() > theRect.Right() ? Right() : theRect.Right(),
                        Bottom() > theRect.Bottom() ? Bottom() : theRect.Bottom()) -
              itsPlace;
    return *this;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * Substraction operator
 *
 * \param theRect The rectangle being substracted
 * \result The resulting rectangle
 */
// ----------------------------------------------------------------------

NFmiRect &NFmiRect::operator-=(const NFmiRect &theRect)
{
  try
  {
    itsPlace = NFmiPoint(Left() > theRect.Left() ? Left() : theRect.Left(),
                         Top() > theRect.Top() ? Top() : theRect.Top());

    itsSize = NFmiPoint(Right() < theRect.Right() ? Right() : theRect.Right(),
                        Bottom() < theRect.Bottom() ? Bottom() : theRect.Bottom()) -
              itsPlace;
    return *this;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \param newCenter Undocumented
 */
// ----------------------------------------------------------------------

void NFmiRect::Center(const NFmiPoint &newCenter)
{
  try
  {
    Place(NFmiPoint(newCenter.X() - (Width() / 2.), newCenter.Y() - (Height() / 2.)));
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * Palauttaa kahta rectiä ympäröivän rectin.
 * \param theRect Undocumented
 * \result Undocumented
 */
// ----------------------------------------------------------------------

const NFmiRect NFmiRect::SmallestEnclosing(const NFmiRect &theRect) const
{
  try
  {
    double left = Left() < theRect.Left() ? Left() : theRect.Left();
    double top = Top() < theRect.Top() ? Top() : theRect.Top();
    double right = Right() > theRect.Right() ? Right() : theRect.Right();
    double bottom = Bottom() > theRect.Bottom() ? Bottom() : theRect.Bottom();
    return NFmiRect(left, top, right, bottom);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * Palauttaa pienimmän rect:in, mikä pitää sisällään this-rect:in ja
 * parametrina annetun rect:in eli leikkaus.
 * \param theRect Undocumented
 * \result Undocumented
 */
// ----------------------------------------------------------------------

const NFmiRect NFmiRect::Intersection(const NFmiRect &theRect) const
{
  try
  {
    double left = Left() > theRect.Left() ? Left() : theRect.Left();
    double top = Top() > theRect.Top() ? Top() : theRect.Top();
    double right = Right() < theRect.Right() ? Right() : theRect.Right();
    double bottom = Bottom() < theRect.Bottom() ? Bottom() : theRect.Bottom();
    return NFmiRect(left, top, right, bottom);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * Write the rectangle to the given output stream
 *
 * \param file The output stream to write to
 * \result The output stream written to
 */
// ----------------------------------------------------------------------

std::ostream &NFmiRect::Write(std::ostream &file) const
{
  try
  {
    file << itsPlace;
    file << itsSize;
    return file;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * Read new rectangle definition from the given input stream
 *
 * \param file The input stream to read from
 * \return The input stream read from
 */
// ----------------------------------------------------------------------

std::istream &NFmiRect::Read(std::istream &file)
{
  try
  {
    file >> itsPlace;
    file >> itsSize;
    return file;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * Addition of a point and a rectangle
 *
 * \param leftPoint Undocumented
 * \param rightRect Undocumented
 * \return Undocumemted
 */
// ----------------------------------------------------------------------

NFmiRect operator+(const NFmiPoint &leftPoint, const NFmiRect &rightRect)
{
  try
  {
    return NFmiRect(
        NFmiPoint(leftPoint.X() + rightRect.Left(), leftPoint.Y() + rightRect.Top()),
        NFmiPoint(leftPoint.X() + rightRect.Right(), leftPoint.Y() + rightRect.Bottom()));
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * Substraction of a point and a rectangle
 *
 * \param leftPoint Undocumented
 * \param rightRect Undocumented
 * \return Undocumemted
 */
// ----------------------------------------------------------------------

NFmiRect operator-(const NFmiPoint &leftPoint, const NFmiRect &rightRect)
{
  try
  {
    return NFmiRect(
        NFmiPoint(leftPoint.X() - rightRect.Left(), leftPoint.Y() - rightRect.Top()),
        NFmiPoint(leftPoint.X() - rightRect.Right(), leftPoint.Y() - rightRect.Bottom()));
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * Addition of a point and a rectangle
 *
 * \param leftRect Undocumented
 * \param rightPoint Undocumented
 * \result Undocumented
 */
// ----------------------------------------------------------------------

NFmiRect operator+(const NFmiRect &leftRect, const NFmiPoint &rightPoint)
{
  try
  {
    return NFmiRect(
        NFmiPoint(rightPoint.X() + leftRect.Left(), rightPoint.Y() + leftRect.Top()),
        NFmiPoint(rightPoint.X() + leftRect.Right(), rightPoint.Y() + leftRect.Bottom()));
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * Substraction of a rectangle and a point
 *
 * \param leftRect Undocumented
 * \param rightPoint Undocumented
 * \result Undocumented
 */
// ----------------------------------------------------------------------

NFmiRect operator-(const NFmiRect &leftRect, const NFmiPoint &rightPoint)
{
  try
  {
    return NFmiRect(
        NFmiPoint(rightPoint.X() - leftRect.Left(), rightPoint.Y() - leftRect.Top()),
        NFmiPoint(rightPoint.X() - leftRect.Right(), rightPoint.Y() - leftRect.Bottom()));
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

bool NFmiRect::Intersect(const NFmiRect &theRect) const
{
  try
  {
    if (this->Left() < theRect.Right() && this->Right() > theRect.Left() &&
        this->Top() < theRect.Bottom() && this->Bottom() > theRect.Top())
      return true;
    else
      return false;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Return hash value for the rectangle
 */
// ----------------------------------------------------------------------

std::size_t NFmiRect::HashValue() const
{
  try
  {
    std::size_t hash = itsPlace.HashValue();
    boost::hash_combine(hash, itsSize.HashValue());
    return hash;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

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


/* Copyright (c) 2016 - 2020, the adamantine authors.
 *
 * This file is subject to the Modified BSD License and may not be distributed
 * without copyright and license information. Please refer to the file LICENSE
 * for the text and further information on this license.
 */

#define BOOST_TEST_MODULE PostProcessor

#include <Geometry.hh>
#include <MaterialProperty.hh>
#include <PostProcessor.hh>
#include <ThermalOperator.hh>

#include <deal.II/fe/fe_q.h>

#include <boost/filesystem.hpp>

#include "main.cc"

BOOST_AUTO_TEST_CASE(post_processor)
{
  MPI_Comm communicator = MPI_COMM_WORLD;

  // Create the Geometry
  boost::property_tree::ptree geometry_database;
  geometry_database.put("length", 12);
  geometry_database.put("length_divisions", 4);
  geometry_database.put("height", 6);
  geometry_database.put("height_divisions", 5);
  adamantine::Geometry<2> geometry(communicator, geometry_database);
  // Create the DoFHandler
  dealii::FE_Q<2> fe(2);
  dealii::DoFHandler<2> dof_handler(geometry.get_triangulation());
  dof_handler.distribute_dofs(fe);
  dealii::AffineConstraints<double> affine_constraints;
  affine_constraints.close();
  dealii::QGauss<1> quad(3);

  // Create the MaterialProperty
  boost::property_tree::ptree mat_prop_database;
  mat_prop_database.put("property_format", "polynomial");
  mat_prop_database.put("n_materials", 1);
  mat_prop_database.put("material_0.solid.density", 1.);
  mat_prop_database.put("material_0.powder.density", 1.);
  mat_prop_database.put("material_0.liquid.density", 1.);
  mat_prop_database.put("material_0.solid.specific_heat", 1.);
  mat_prop_database.put("material_0.powder.specific_heat", 1.);
  mat_prop_database.put("material_0.liquid.specific_heat", 1.);
  mat_prop_database.put("material_0.solid.thermal_conductivity", 10.);
  mat_prop_database.put("material_0.powder.thermal_conductivity", 10.);
  mat_prop_database.put("material_0.liquid.thermal_conductivity", 10.);
  std::shared_ptr<adamantine::MaterialProperty<2>> mat_properties(
      new adamantine::MaterialProperty<2>(
          communicator, geometry.get_triangulation(), mat_prop_database));

  // Initialize the ThermalOperator
  adamantine::ThermalOperator<2, 2, dealii::MemorySpace::Host> thermal_operator(
      communicator, mat_properties);
  thermal_operator.reinit(dof_handler, affine_constraints, quad);
  thermal_operator.compute_inverse_mass_matrix(dof_handler, affine_constraints);

  // Create the PostProcessor
  boost::property_tree::ptree post_processor_database;
  post_processor_database.put("file_name", "test");
  adamantine::PostProcessor<2> post_processor(
      communicator, post_processor_database, dof_handler, mat_properties);
  dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host> src;
  dealii::MatrixFree<2, double> const &matrix_free =
      thermal_operator.get_matrix_free();
  matrix_free.initialize_dof_vector(src);
  for (unsigned int i = 0; i < src.size(); ++i)
    src[i] = 1.;

  post_processor.output_pvtu(1, 0, 0., src);
  post_processor.output_pvtu(1, 1, 0.1, src);
  post_processor.output_pvtu(1, 2, 0.2, src);
  post_processor.output_pvd();

  // Check that the files exist
  BOOST_CHECK(boost::filesystem::exists("test.pvd"));
  BOOST_CHECK(boost::filesystem::exists("test.01.000000.pvtu"));
  BOOST_CHECK(boost::filesystem::exists("test.01.000001.pvtu"));
  BOOST_CHECK(boost::filesystem::exists("test.01.000002.pvtu"));
  BOOST_CHECK(boost::filesystem::exists("test.01.000000.000000.vtu"));
  BOOST_CHECK(boost::filesystem::exists("test.01.000001.000000.vtu"));
  BOOST_CHECK(boost::filesystem::exists("test.01.000002.000000.vtu"));

  // Delete the files
  std::remove("test.pvd");
  std::remove("test.01.000000.pvtu");
  std::remove("test.01.000001.pvtu");
  std::remove("test.01.000002.pvtu");
  std::remove("test.01.000000.000000.vtu");
  std::remove("test.01.000001.000000.vtu");
  std::remove("test.01.000002.000000.vtu");
}


/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2004 StatPro Italia srl
 Copyright (C) 2004 Walter Penschke

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <quantlib-dev@lists.sf.net>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 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 license for more details.
*/

#ifndef quantlib_test_rng_traits_hpp
#define quantlib_test_rng_traits_hpp

#include <boost/test/unit_test.hpp>

/* remember to document new and/or updated tests in the Doxygen
   comment block of the corresponding class */

class RngTraitsTest {
  public:
    static void testGaussian();
    static void testDefaultPoisson();
    static void testCustomPoisson();
    static boost::unit_test_framework::test_suite* suite();
};

/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2004 StatPro Italia srl
 Copyright (C) 2004 Walter Penschke

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <quantlib-dev@lists.sf.net>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 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 license for more details.
*/

#include "utilities.hpp"
#include <ql/math/comparison.hpp>
#include <ql/math/randomnumbers/rngtraits.hpp>

using namespace QuantLib;
using namespace boost::unit_test_framework;

void RngTraitsTest::testGaussian() {

    BOOST_TEST_MESSAGE("Testing Gaussian pseudo-random number generation...");

    PseudoRandom::rsg_type rsg =
        PseudoRandom::make_sequence_generator(100, 1234);

    const std::vector<Real>& values = rsg.nextSequence().value;
    Real sum = 0.0;
    for (Size i=0; i<values.size(); i++)
        sum += values[i];

    Real stored = 4.09916;
    Real tolerance = 1.0e-5;
    if (std::fabs(sum - stored) > tolerance)
        BOOST_FAIL("the sum of the samples does not match the stored value\n"
                   << "    calculated: " << sum << "\n"
                   << "    expected:   " << stored);
}

void RngTraitsTest::testDefaultPoisson() {

    BOOST_TEST_MESSAGE("Testing Poisson pseudo-random number generation...");

    PoissonPseudoRandom::icInstance =
        boost::shared_ptr<InverseCumulativePoisson>();
    PoissonPseudoRandom::rsg_type rsg =
        PoissonPseudoRandom::make_sequence_generator(100, 1234);

    const std::vector<Real>& values = rsg.nextSequence().value;
    Real sum = 0.0;
    for (Size i=0; i<values.size(); i++)
        sum += values[i];

    Real stored = 108.0;
    if (!close(sum, stored))
        BOOST_FAIL("the sum of the samples does not match the stored value\n"
                   << "    calculated: " << sum << "\n"
                   << "    expected:   " << stored);
}

void RngTraitsTest::testCustomPoisson() {

    BOOST_TEST_MESSAGE("Testing custom Poisson pseudo-random number generation...");

    PoissonPseudoRandom::icInstance =
        boost::shared_ptr<InverseCumulativePoisson>(
                                           new InverseCumulativePoisson(4.0));
    PoissonPseudoRandom::rsg_type rsg =
        PoissonPseudoRandom::make_sequence_generator(100, 1234);

    const std::vector<Real>& values = rsg.nextSequence().value;
    Real sum = 0.0;
    for (Size i=0; i<values.size(); i++)
        sum += values[i];

    Real stored = 409.0;
    if (!close(sum, stored))
        BOOST_FAIL("the sum of the samples does not match the stored value\n"
                   << "    calculated: " << sum << "\n"
                   << "    expected:   " << stored);
}

test_suite* RngTraitsTest::suite() {
    test_suite* suite = BOOST_TEST_SUITE("RNG traits tests");
    suite->add(QUANTLIB_TEST_CASE(&RngTraitsTest::testGaussian));
    suite->add(QUANTLIB_TEST_CASE(&RngTraitsTest::testDefaultPoisson));
    suite->add(QUANTLIB_TEST_CASE(&RngTraitsTest::testCustomPoisson));
    return suite;
}

#endif


// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_SPACES_CG_INTERFACE_HH
#define DUNE_GDT_SPACES_CG_INTERFACE_HH

#include <boost/numeric/conversion/cast.hpp>

#include <dune/common/dynvector.hh>
#include <dune/common/version.hh>
#include <dune/common/typetraits.hh>

#if DUNE_VERSION_NEWER(DUNE_COMMON,2,3)
# include <dune/geometry/referenceelements.hh>
#else
# include <dune/geometry/genericreferenceelements.hh>
#endif

#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/common/type_utils.hh>

#include "../interface.hh"

namespace Dune {
namespace GDT {
namespace Spaces {

static constexpr ChooseSpaceBackend default_cg_backend = default_space_backend;

template< class ImpTraits, size_t domainDim, size_t rangeDim, size_t rangeDimCols = 1 >
class CGInterface
  : public SpaceInterface< ImpTraits, domainDim, rangeDim, rangeDimCols >
{
  typedef SpaceInterface< ImpTraits, domainDim, rangeDim, rangeDimCols > BaseType;
  typedef CGInterface< ImpTraits, domainDim, rangeDim, rangeDimCols > ThisType;
public:
  typedef ImpTraits Traits;

  using BaseType::polOrder;

  using typename BaseType::DomainFieldType;
  using BaseType::dimDomain;
  using typename BaseType::DomainType;

  using typename BaseType::RangeFieldType;
  using BaseType::dimRange;
  using BaseType::dimRangeCols;

  using typename BaseType::EntityType;
  using typename BaseType::IntersectionType;
  using typename BaseType::BoundaryInfoType;
  using typename BaseType::PatternType;
private:
  static const constexpr RangeFieldType compare_tolerance_ = 1e-13;
public:

  /**
   * \defgroup interface ´´These methods have to be implemented!''
   * @{
   **/
  std::vector< DomainType > lagrange_points(const EntityType& entity) const
  {
    CHECK_CRTP(this->as_imp().lagrange_points(entity));
    return this->as_imp().lagrange_points(entity);
  } // ... lagrange_points(...)

  std::set< size_t > local_dirichlet_DoFs(const EntityType& entity,
                                          const BoundaryInfoType& boundaryInfo) const
  {
    CHECK_CRTP(this->as_imp().local_dirichlet_DoFs(entity, boundaryInfo));
    return this->as_imp().local_dirichlet_DoFs(entity, boundaryInfo);
  } // ... local_dirichlet_DoFs(...)
  /** @} */

  /**
   * \defgroup provided ´´These methods are provided by the interface for convenience.''
   * @{
   **/
  std::vector< DomainType > lagrange_points_order_1(const EntityType& entity) const
  {
    // check
    static_assert(polOrder == 1, "Not tested for higher polynomial orders!");
    if (dimRange != 1) DUNE_THROW(NotImplemented, "Does not work for higher dimensions");
    assert(this->grid_view().indexSet().contains(entity));
    // get the basis and reference element
    const auto basis = this->base_function_set(entity);
    typedef typename BaseType::BaseFunctionSetType::RangeType RangeType;
    std::vector< RangeType > tmp_basis_values(basis.size(), RangeType(0));
    const auto& reference_element = ReferenceElements< DomainFieldType, dimDomain >::general(entity.type());
    const auto num_vertices = reference_element.size(dimDomain);
    assert(num_vertices >= 0);
    assert(boost::numeric_cast< size_t >(num_vertices) == basis.size() && "This should not happen with polOrder 1!");
    // prepare return vector
    std::vector< DomainType > local_vertices(num_vertices, DomainType(0));
    // loop over all vertices
    for (auto ii : DSC::valueRange(num_vertices)) {
      // get the local coordinate of the iith vertex
      const auto local_vertex = reference_element.position(ii, dimDomain);
      // evaluate the basefunctionset
      basis.evaluate(local_vertex, tmp_basis_values);
      // find the basis function that evaluates to one here (has to be only one!)
      size_t ones = 0;
      size_t zeros = 0;
      size_t failures = 0;
      for (size_t jj = 0; jj < basis.size(); ++jj) {
        if (std::abs((tmp_basis_values)[jj][0] - RangeFieldType(1)) < compare_tolerance_) {
          local_vertices[jj] = local_vertex;
          ++ones;
        } else if (std::abs((tmp_basis_values)[jj][0]) < compare_tolerance_)
          ++zeros;
        else
          ++failures;
      }
      assert(ones == 1 && zeros == (basis.size() - 1) && failures == 0 && "This must not happen for polOrder 1!");
    }
    return local_vertices;
  } // ... lagrange_points_order_1(...)

  std::set< size_t > local_dirichlet_DoFs_order_1(const EntityType& entity,
                                                  const BoundaryInfoType& boundaryInfo) const
  {
    static_assert(polOrder == 1, "Not tested for higher polynomial orders!");
    if (dimRange != 1) DUNE_THROW(NotImplemented, "Does not work for higher dimensions");
    // check
    assert(this->grid_view().indexSet().contains(entity));
    // prepare
    std::set< size_t > localDirichletDofs;
    std::vector< DomainType > dirichlet_vertices;
    // get all dirichlet vertices of this entity, therefore
    // * loop over all intersections
    const auto intersection_it_end = this->grid_view().iend(entity);
    for (auto intersection_it = this->grid_view().ibegin(entity);
         intersection_it != intersection_it_end;
         ++intersection_it) {
      // only work on dirichlet ones
      const auto& intersection = *intersection_it;
      // actual dirichlet intersections + process boundaries for parallel runs
      if (boundaryInfo.dirichlet(intersection) || (!intersection.neighbor() && !intersection.boundary())) {
        // and get the vertices of the intersection
        const auto geometry = intersection.geometry();
        for (auto cc : DSC::valueRange(geometry.corners()))
          dirichlet_vertices.emplace_back(entity.geometry().local(geometry.corner(cc)));
      } // only work on dirichlet ones
    } // loop over all intersections
    // find the corresponding basis functions
    const auto basis = this->base_function_set(entity);
    typedef typename BaseType::BaseFunctionSetType::RangeType RangeType;
    std::vector< RangeType > tmp_basis_values(basis.size(), RangeType(0));
    for (size_t cc = 0; cc < dirichlet_vertices.size(); ++cc) {
      // find the basis function that evaluates to one here (has to be only one!)
      basis.evaluate(dirichlet_vertices[cc], tmp_basis_values);
      size_t ones = 0;
      size_t zeros = 0;
      size_t failures = 0;
      for (size_t jj = 0; jj < basis.size(); ++jj) {
        if (std::abs(tmp_basis_values[jj][0] - RangeFieldType(1)) < compare_tolerance_) {
          localDirichletDofs.insert(jj);
          ++ones;
        } else if (std::abs(tmp_basis_values[jj][0]) < compare_tolerance_)
          ++zeros;
        else
          ++failures;
      }
      assert(ones == 1 && zeros == (basis.size() - 1) && failures == 0 && "This must not happen for polOrder 1!");
    }
    return localDirichletDofs;
  } // ... local_dirichlet_DoFs_order_1(...)

  using BaseType::compute_pattern;

  template< class G, class S, size_t d, size_t r, size_t rC >
  PatternType compute_pattern(const GridView< G >& local_grid_view, const SpaceInterface< S, d, r, rC >& ansatz_space) const
  {
    return BaseType::compute_volume_pattern(local_grid_view, ansatz_space);
  }

  using BaseType::local_constraints;

  template< class S, size_t d, size_t r, size_t rC, class ConstraintsType >
  void local_constraints(const SpaceInterface< S, d, r, rC >& /*other*/,
                         const EntityType& /*entity*/,
                         ConstraintsType& /*ret*/) const
  {
    static_assert(AlwaysFalse< S >::value, "Not implemented for these constraints!");
  }

  template< class S, size_t d, size_t r, size_t rC >
  void local_constraints(const SpaceInterface< S, d, r, rC >& /*other*/,
                         const EntityType& entity,
                         DirichletConstraints< IntersectionType >& ret) const
  {
    const auto local_DoFs = this->local_dirichlet_DoFs(entity, ret.boundary_info());
    if (local_DoFs.size() > 0) {
      const auto global_indices = this->mapper().globalIndices(entity);
      for (const auto& local_DoF : local_DoFs) {
        ret.insert(global_indices[local_DoF]);
      }
    }
  } // ... local_constraints(..., Constraints::Dirichlet< ... > ...)
  /** @} */
}; // class CGInterface

} // namespace Spaces
namespace internal {

template< class S >
struct is_cg_space_helper
{
  DSC_has_typedef_initialize_once(Traits)
  DSC_has_static_member_initialize_once(dimDomain)
  DSC_has_static_member_initialize_once(dimRange)
  DSC_has_static_member_initialize_once(dimRangeCols)

  static const bool is_candidate = DSC_has_typedef(Traits)< S >::value
                                   && DSC_has_static_member(dimDomain)< S >::value
                                   && DSC_has_static_member(dimRange)< S >::value
                                   && DSC_has_static_member(dimRangeCols)< S >::value;
}; // class is_cg_space_helper

} // namespace internal

template< class S, bool candidate = internal::is_cg_space_helper< S >::is_candidate >
struct is_cg_space
  : public std::is_base_of< Spaces::CGInterface< typename S::Traits, S::dimDomain, S::dimRange, S::dimRangeCols >
                          , S >
{};

template< class S >
struct is_cg_space< S, false >
  : public std::false_type
{};

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_CG_INTERFACE_HH


//==============================================================================
//         Copyright 2003 - 2012 LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012 LRI    UMR 8623 CNRS/Univ Paris Sud XI
//         Copyright 2012 - 2013 MetaScale SAS
//         Copyright 2012        Domagoj Saric, Little Endian Ltd.
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#include <nt2/sdk/unit/config.hpp>
#include <nt2/sdk/unit/details/prng.hpp>
#include <boost/simd/sdk/config/type_lists.hpp>

#include <boost/simd/sdk/config/types.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/foreach.hpp>

// \note std::rand() does not produce portably reproducible numbers so we
// resort to Boost.Random.
//                                           (24.10.2012.) (Domagoj Saric)
// \note NT2Bench configuration has exceptions disabled and Boost.Random
// fails to compile then because it uses naked throw statements.
// https://svn.boost.org/trac/boost/ticket/7497
//                                           (12.10.2012.) (Domagoj Saric)
#include <boost/random/linear_congruential.hpp>
#include <boost/random/uniform_real_distribution.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/range/iterator_range_core.hpp>
#include <complex>

namespace nt2
{
  namespace details
  {
    static boost::random::rand48 prng_singleton;

    template <typename T, typename D> BOOST_DISPATCH_NOTHROW
    void prng_fill_step ( boost::iterator_range<T*> const data, D& dist )
    {
      BOOST_FOREACH( T & scalar, data )
        scalar = dist( prng_singleton );
    }

    template <typename T, typename D> BOOST_DISPATCH_NOTHROW
    void prng_fill_step ( boost::iterator_range<std::complex<T>*> const data, D& distr, D& disti )
    {
      BOOST_FOREACH( std::complex<T> & scalar, data )
      {
        scalar = std::complex<T>( distr( prng_singleton ), disti( prng_singleton ) );
      }
    }

    template<typename T>
    NT2_TEST_UNIT_DECL BOOST_DISPATCH_NOTHROW
    void prng_fill_impl( boost::iterator_range<std::complex<T>*> data , std::complex<T> mn, std::complex<T> mx)
    {
      boost::random::uniform_real_distribution<T> distr(mn.real(), mx.real());
      boost::random::uniform_real_distribution<T> disti(mn.imag(), mx.imag());
      prng_fill_step(data,distr,disti);
    }

    template<typename T>
    NT2_TEST_UNIT_DECL BOOST_DISPATCH_NOTHROW
    void prng_fill_impl( boost::iterator_range<T*> data , T mn, T mx)
    {
      boost::random::uniform_real_distribution<T> dist(mn, mx);
      prng_fill_step(data,dist);
    }

    #define M0(r,d,elem)                                                       \
    template<> NT2_TEST_UNIT_DECL BOOST_DISPATCH_NOTHROW                       \
    void prng_fill_impl ( boost::iterator_range<elem*> const data              \
                        , elem mn, elem mx                                     \
                        )                                                      \
    {                                                                          \
      boost::random::uniform_int_distribution<elem> const g(mn, mx);           \
      prng_fill_step(data,g);                                                  \
    }                                                                          \
    /**/

    BOOST_PP_SEQ_FOR_EACH(M0,~,BOOST_SIMD_INTEGRAL_TYPES)

    #undef M0

    template NT2_TEST_UNIT_DECL BOOST_DISPATCH_NOTHROW
    void prng_fill_impl( boost::iterator_range<float*>, float, float);

    template NT2_TEST_UNIT_DECL BOOST_DISPATCH_NOTHROW
    void prng_fill_impl( boost::iterator_range<double*>, double, double);

    template NT2_TEST_UNIT_DECL BOOST_DISPATCH_NOTHROW
    void prng_fill_impl( boost::iterator_range<std::complex<float>*>, std::complex<float>, std::complex<float>);

    template NT2_TEST_UNIT_DECL BOOST_DISPATCH_NOTHROW
    void prng_fill_impl( boost::iterator_range<std::complex<double>*>, std::complex<double>, std::complex<double>);
  }

  NT2_TEST_UNIT_DECL BOOST_DISPATCH_NOTHROW void prng_reset()
  {
    details::prng_singleton.seed( 42 );
  }
}


/* eigen_require.hpp
 *
 *  Created on: 27 Jun 2019
 *      Author: Fabian Meyer
 */

#ifndef ADCPP_EIGEN_REQUIRE_HPP_
#define ADCPP_EIGEN_REQUIRE_HPP_

#include <Eigen/Geometry>
#include <catch2/catch.hpp>

#define REQUIRE_MATRIX_APPROX(a, b, eps) do {                                 \
        REQUIRE(a.cols() == b.cols());                                        \
        REQUIRE(a.rows() == b.rows());                                        \
        for(long int _c = 0; _c < a.cols(); ++_c)                                \
            for(long int _r = 0; _r < a.rows(); ++_r)                            \
                REQUIRE(Approx(a(_r, _c)).margin(eps) == b(_r, _c));          \
    } while(0)

#define REQUIRE_MATRIX(a, b) do {                                             \
        REQUIRE(a.cols() == b.cols());                                        \
        REQUIRE(a.rows() == b.rows());                                        \
        for(long int _c = 0; _c < a.cols(); ++_c)                                \
            for(long int _r = 0; _r < a.rows(); ++_r)                            \
                REQUIRE(a(_r, _c) == b(_r, _c));                              \
    } while(0)

#endif


/*
 * Copyright (C) 2022 LEIDOS.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
#include <boost/date_time/posix_time/posix_time.hpp>
#include <lanelet2_extension/time/TimeConversion.h>

namespace lanelet
{

namespace time {

double toSec(const boost::posix_time::time_duration& duration) {
  if (duration.is_special()) {
    throw std::invalid_argument("Cannot convert special duration to seconds");
  }
  return duration.total_microseconds() / 1000000.0;
}

double toSec(const boost::posix_time::ptime& time) {
  return toSec(time - boost::posix_time::from_time_t(0));
}

boost::posix_time::ptime timeFromSec(double sec) {
  return boost::posix_time::from_time_t(0) + boost::posix_time::microseconds(static_cast<long>(sec * 1000000L));
}

boost::posix_time::time_duration durationFromSec(double sec) {
  return boost::posix_time::microseconds(static_cast<long>(sec * 1000000L));
}

} // namespace time

}  // namespace lanelet


// Copyright 2015-2019 Hans Dembinski and Henry Schreiner
//
// Distributed under the Boost Software License, version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Based on boost/histogram/accumulators/weighted_mean.hpp
//
// Changes:
//  * Internal values are public for access from Python
//  * A special constructor added for construction from Python

#pragma once

#include <boost/core/nvp.hpp>
#include <boost/histogram/weight.hpp>

namespace accumulators {

/// Holds sum of weights and its variance estimate
template <class ValueType>
struct weighted_sum {
    using value_type      = ValueType;
    using const_reference = const value_type&;

    weighted_sum() = default;

    /// Initialize sum to value and allow implicit conversion
    weighted_sum(const_reference value) noexcept
        : weighted_sum(value, value) {}

    /// Allow implicit conversion from sum<T>
    template <class T>
    weighted_sum(const weighted_sum<T>& s) noexcept
        : weighted_sum(s.value(), s.variance()) {}

    /// Initialize sum to value and variance
    weighted_sum(const_reference value, const_reference variance) noexcept
        : value(value)
        , variance(variance) {}

    /// Increment by one.
    weighted_sum& operator++() {
        value += 1;
        variance += 1;
        return *this;
    }

    /// Increment by weight.
    template <typename T>
    weighted_sum& operator+=(const bh::weight_type<T>& w) {
        value += w.value;
        variance += w.value * w.value;
        return *this;
    }

    /// Added another weighted sum.
    weighted_sum& operator+=(const weighted_sum& rhs) {
        value += rhs.value;
        variance += rhs.variance;
        return *this;
    }

    /// Scale by value.
    weighted_sum& operator*=(const value_type& x) {
        value *= x;
        variance *= x * x;
        return *this;
    }

    bool operator==(const value_type& rhs) const noexcept {
        return value == rhs && variance == rhs;
    }

    template <typename T>
    bool operator==(const weighted_sum<T>& rhs) const noexcept {
        return value == rhs.value && variance == rhs.variance;
    }

    template <typename T>
    bool operator!=(const T& rhs) const noexcept {
        return !operator==(rhs);
    }

    // lossy conversion must be explicit
    explicit operator const_reference() const { return value; }

    template <class Archive>
    void serialize(Archive& ar, unsigned /* version */) {
        ar& boost::make_nvp("value", value);
        ar& boost::make_nvp("variance", variance);
    }

    value_type value{};
    value_type variance{};
};

} // namespace accumulators


//          Copyright Oliver Kowalke 2014.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include <cstdlib>
#include <iostream>
#include <memory>

#include <boost/context/execution_context.hpp>

int main() {
    int n=35;
    boost::context::execution_context sink( boost::context::execution_context::current() );
    boost::context::execution_context source(
        [n,&sink](void*)mutable{
            int a=0;
            int b=1;
            while(n-->0){
                sink(&a);
                auto next=a+b;
                a=b;
                b=next;
            }
        });
    for(int i=0;i<10;++i){
        std::cout<<*(int*)source()<<" ";
    }
    std::cout << "\nmain: done" << std::endl;
    return EXIT_SUCCESS;
}


// SlicePlot.cpp
// created by Kuangdai on 26-Nov-2016
// plot a slice

#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <sstream>
#include <fstream>

#include "SlicePlot.h"

#include "Geodesy.h"
#include "XMPI.h"
#include "Mesh.h"
#include "Parameters.h"
#include "ExodusModel.h"
#include "Quad.h"
#include "Domain.h"
#include "Element.h"

SlicePlot::SlicePlot(const std::string &params, const Mesh *mesh):
mMesh(mesh) {
    std::string mstr = params;
    std::vector<std::string> strs;
    boost::trim_if(mstr, boost::is_any_of("\t "));
    boost::split(strs, mstr, boost::is_any_of("$"), boost::token_compress_on);
    mParName = strs[0];
    int narg = numArgs(mParName);
    if (strs.size() < narg) throw std::runtime_error("SlicePlot::SlicePlot || "
        "Not enough arguments following ParSeries " + mParName + ".");
    try {
        if (narg >= 2) {
            // sample type
            if (boost::iequals(strs[1], "center")) {
                mSampleType = SampleTypes::Center;
            } else if (boost::iequals(strs[1], "vertex")) {
                mSampleType = SampleTypes::Vertex;
            } else if (boost::iequals(strs[1], "gllpnt")) {
                mSampleType = SampleTypes::GLLPnt;
            } else throw std::runtime_error("");
        }

        if (narg >= 4) {
            // phi
            mLat = boost::lexical_cast<double>(strs[2]);
            mLon = boost::lexical_cast<double>(strs[3]);
            RDCol3 rtpG;
            rtpG(0) = 1.;
            rtpG(1) = Geodesy::lat2Theta_d(mLat, 0.);
            rtpG(2) = Geodesy::lon2Phi(mLon);
            const RDCol3 &rtpS = Geodesy::rotateGlob2Src(rtpG, mMesh->mSrcLat, mMesh->mSrcLon, mMesh->mSrcDep);
            mPhi = rtpS(2);
        }

        if (narg >= 5) {
            // property type
            if (boost::iequals(strs[4], "1D")) {
                mRefType = PropertyRefTypes::Property1D;
            } else if (boost::iequals(strs[4], "3D")) {
                mRefType = PropertyRefTypes::Property3D;
            } else if (boost::iequals(strs[4], "perturb")) {
                mRefType = PropertyRefTypes::PropertyPerturb;
            } else throw std::runtime_error("");
        }

    } catch (std::exception) {
        throw std::runtime_error("SlicePlot::SlicePlot || "
            "Invalid parameter following ParSeries " + mParName + ".");
    }
}

void SlicePlot::buildInparam(std::vector<SlicePlot *> &splots,
    const Parameters &par, const Mesh *mesh, int verbose) {
    // clear
    for (const auto &sp: splots) delete sp;
    splots.clear();
    // check size
    int nplots = par.getValue<int>("MODEL_PLOT_SLICES_NUM");
    int nsize = par.getSize("MODEL_PLOT_SLICES_LIST");
    if (nplots > nsize) throw std::runtime_error("SlicePlot::buildInparam || "
        "Not enough ParSeries provided in MODEL_PLOT_SLICES_LIST ||"
        "MODEL_PLOT_SLICES_NUM = " + par.getValue<std::string>("MODEL_PLOT_SLICES_NUM") + ".");
    // add to vector
    for (int i = 0; i < nplots; i++) {
        SlicePlot *sp = new SlicePlot(par.getValue<std::string>("MODEL_PLOT_SLICES_LIST", i), mesh);
        splots.push_back(sp);
    }

    // verbose
    if (verbose && nplots > 0) {
        std::stringstream ss;
        ss << "\n======================== Slice Plots =======================" << XMPI::endl;
        ss << "  Number of Plots   =   " << nplots << XMPI::endl;
        ss << "  List of Plots (PAR SAMPLE LAT LON PHI REF):" << XMPI::endl;
        for (int i = 0; i < nplots; i++) ss << "    * " << splots[i]->verbose() << XMPI::endl;
        ss << "======================== Slice Plots =======================\n" << XMPI::endl;
        XMPI::cout << ss.str();
    }
}

void SlicePlot::plotUnweighted() const {
    plotPhysicalProperties();
    plotNu();
    plotRank(false);
}

void SlicePlot::plotWeighted() const {
    plotRank(true);
}

void SlicePlot::plotPhysicalProperties() const {
    if (!isPhysical(mParName)) return;

    // data size
    int ncol = 1;
    if (mSampleType == SampleTypes::Vertex) ncol = 4;
    if (mSampleType == SampleTypes::GLLPnt) ncol = nPntElem;
    int nrow = mMesh->mExModel->getNumQuads();
    RDMatXX data = RDMatXX::Zero(nrow, ncol);

    // gather local data
    for (int i = 0; i < mMesh->getNumQuads(); i++) {
        RDRowN quadData;
        if (boost::iequals(mParName, "undulation")) {
            quadData = mMesh->mQuads[i]->getUndulationOnSlice(mPhi);
        } else {
            quadData = mMesh->mQuads[i]->getMaterialOnSlice(mParName, mRefType, mPhi);
        }
        int row = mMesh->mQuads[i]->getQuadTag();
        if (mSampleType == SampleTypes::Center) {
            data(row, 0) = quadData(nPol / 2 * nPntEdge + nPol / 2);
        } else if (mSampleType == SampleTypes::Vertex) {
            data(row, 0) = quadData(0);
            data(row, 1) = quadData(nPol * nPntEdge);
            data(row, 2) = quadData(nPol * nPntEdge + nPol);
            data(row, 3) = quadData(nPol);
        } else {
            data.row(row) = quadData;
        }
    }

    // sum MPI
    XMPI::sumEigenDouble(data);

    // dump to file
    if (XMPI::root()) {
        std::string fname = Parameters::sOutputDirectory + "/plots/" + verbose('_') + ".txt";
        std::fstream fs(fname, std::fstream::out);
        fs << data << std::endl;
        fs.close();
    }
}

void SlicePlot::plotNu() const {
    if (!boost::iequals(mParName, "nu")) return;

    // data size
    int ncol = 1;
    if (mSampleType == SampleTypes::Vertex) ncol = 4;
    if (mSampleType == SampleTypes::GLLPnt) ncol = nPntElem;
    int nrow = mMesh->mExModel->getNumQuads();
    Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> data(nrow, ncol);
    data.setZero();

    // gather local data
    for (int i = 0; i < mMesh->getNumQuads(); i++) {
        int row = mMesh->mQuads[i]->getQuadTag();
        if (mSampleType == SampleTypes::Center) {
            data(row, 0) = mMesh->mQuads[i]->getNu(); // use max
        } else if (mSampleType == SampleTypes::Vertex) {
            data(row, 0) = mMesh->mQuads[i]->getPointNr(0, 0);
            data(row, 1) = mMesh->mQuads[i]->getPointNr(nPol, 0);
            data(row, 2) = mMesh->mQuads[i]->getPointNr(nPol, nPol);
            data(row, 3) = mMesh->mQuads[i]->getPointNr(0, nPol);
        } else {
            for (int ipol = 0; ipol <= nPol; ipol++) {
                for (int jpol = 0; jpol <= nPol; jpol++) {
                    int ipnt = ipol * nPntEdge + jpol;
                    data(row, ipnt) = mMesh->mQuads[i]->getPointNr(ipol, jpol);
                }
            }
        }
    }

    // sum MPI
    XMPI::sumEigenInt(data);

    // dump to file
    if (XMPI::root()) {
        std::string fname = Parameters::sOutputDirectory + "/plots/" + verbose('_') + ".txt";
        std::fstream fs(fname, std::fstream::out);
        fs << data << std::endl;
        fs.close();
    }
}

void SlicePlot::plotRank(bool weighted) const {
    bool plot = boost::iequals(mParName, "weighted") && weighted;
    plot = plot || (boost::iequals(mParName, "unweighted") && (!weighted));
    if (!plot) return;

    // data size
    int nrow = mMesh->mExModel->getNumQuads();
    IColX data = IColX::Zero(nrow);

    // gather local data
    for (int i = 0; i < mMesh->getNumQuads(); i++) {
        int row = mMesh->mQuads[i]->getQuadTag();
        data(row) = XMPI::rank();
    }

    // sum MPI
    XMPI::sumEigenInt(data);

    // dump to file
    if (XMPI::root()) {
        std::string fname = Parameters::sOutputDirectory + "/plots/" + verbose('_') + ".txt";
        std::fstream fs(fname, std::fstream::out);
        fs << data << std::endl;
        fs.close();
    }
}

void SlicePlot::plotEleType(const Domain &domain) const {
    if (!boost::iequals(mParName, "eleType")) return;

    // data size
    int nrow = mMesh->mExModel->getNumQuads();
    std::vector<std::string> data(nrow, "");
    std::vector<std::string> etype;
    std::vector<int> etag;

    // gather local data
    for (int iloc = 0; iloc < mMesh->getNumQuads(); iloc++) {
        int elemTag = mMesh->mQuads[iloc]->getElementTag();
        int quadTag = mMesh->mQuads[iloc]->getQuadTag();
        Element *elem = domain.getElement(elemTag);
        etype.push_back(elem->verbose());
        etag.push_back(quadTag);
    }

    // sum MPI
    std::vector<std::vector<std::string>> all_etype;
    XMPI::gather(etype, all_etype, false);
    std::vector<std::vector<int>> all_etag;
    XMPI::gather(etag, all_etag, MPI_INT, false);

    // dump to file
    if (XMPI::root()) {
        for (int i = 0; i < all_etype.size(); i++) {
            for (int j = 0; j < all_etype[i].size(); j++) {
                data[all_etag[i][j]] = all_etype[i][j];
            }
        }
        std::string fname = Parameters::sOutputDirectory + "/plots/" + verbose('_') + ".txt";
        std::fstream fs(fname, std::fstream::out);
        for (int i = 0; i < nrow; i++) fs << data[i] << std::endl;
        fs.close();
    }
}

void SlicePlot::plotMeasured(const RDColX &cost) const {
    if (!boost::iequals(mParName, "eleCost")) return;
    // dump to file
    if (XMPI::root()) {
        std::string fname = Parameters::sOutputDirectory + "/plots/" + verbose('_') + ".txt";
        std::fstream fs(fname, std::fstream::out);
        fs << cost << std::endl;
        fs.close();
    }
}

int SlicePlot::numArgs(const std::string &parName) const {
    if (boost::iequals(parName, "vp")) return 5;
    if (boost::iequals(parName, "vpv")) return 5;
    if (boost::iequals(parName, "vph")) return 5;
    if (boost::iequals(parName, "vs")) return 5;
    if (boost::iequals(parName, "vsv")) return 5;
    if (boost::iequals(parName, "vsh")) return 5;
    if (boost::iequals(parName, "rho")) return 5;
    if (boost::iequals(parName, "eta")) return 5;
    if (boost::iequals(parName, "Qmu")) return 5;
    if (boost::iequals(parName, "Qkappa")) return 5;
    if (boost::iequals(parName, "undulation")) return 4;
    if (boost::iequals(parName, "nu")) return 2;
    if (boost::iequals(parName, "eleType")) return 1;
    if (boost::iequals(parName, "eleCost")) return 1;
    if (boost::iequals(parName, "unweighted")) return 1;
    if (boost::iequals(parName, "weighted")) return 1;
    throw std::runtime_error("SlicePlot::numArgs || Unknown parameter name: " + parName + ".");
}

bool SlicePlot::isPhysical(const std::string &parName) const {
    if (boost::iequals(parName, "vp")) return true;
    if (boost::iequals(parName, "vpv")) return true;
    if (boost::iequals(parName, "vph")) return true;
    if (boost::iequals(parName, "vs")) return true;
    if (boost::iequals(parName, "vsv")) return true;
    if (boost::iequals(parName, "vsh")) return true;
    if (boost::iequals(parName, "rho")) return true;
    if (boost::iequals(parName, "eta")) return true;
    if (boost::iequals(parName, "Qmu")) return true;
    if (boost::iequals(parName, "Qkappa")) return true;
    if (boost::iequals(parName, "undulation")) return true;
    if (boost::iequals(parName, "nu")) return false;
    if (boost::iequals(parName, "eleType")) return false;
    if (boost::iequals(parName, "eleCost")) return false;
    if (boost::iequals(parName, "unweighted")) return false;
    if (boost::iequals(parName, "weighted")) return false;
    throw std::runtime_error("SlicePlot::onSlice || Unknown parameter name: " + parName + ".");
}

std::string SlicePlot::verbose(char sp) const {
    std::stringstream ss;
    ss << mParName;
    int narg = numArgs(mParName);
    if (narg >= 2) {
        if (mSampleType == SampleTypes::Center) ss << sp << "center";
        if (mSampleType == SampleTypes::Vertex) ss << sp << "vertex";
        if (mSampleType == SampleTypes::GLLPnt) ss << sp << "gllpnt";
    }
    if (narg >= 4) ss << sp << mLat << sp << mLon << sp << mPhi / degree;
    if (narg >= 5) {
        if (mRefType == PropertyRefTypes::Property1D) ss << sp << "1D";
        if (mRefType == PropertyRefTypes::Property3D) ss << sp << "3D";
        if (mRefType == PropertyRefTypes::PropertyPerturb) ss << sp << "perturb";
    }
    return ss.str();
}


//==============================================================================
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//         Copyright 2011 - 2012   MetaScale SAS
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef NT2_CORE_FUNCTIONS_DETAILS_COLON_HPP_INCLUDED
#define NT2_CORE_FUNCTIONS_DETAILS_COLON_HPP_INCLUDED

#include <nt2/core/container/dsl/forward.hpp>
#include <nt2/include/functions/simd/fma.hpp>
#include <nt2/include/functions/simd/splat.hpp>
#include <nt2/include/functions/simd/enumerate.hpp>
#include <nt2/include/functions/simd/plus.hpp>
#include <nt2/core/functions/table/details/is_vectorizable_indexer.hpp>
#include <nt2/core/container/extremum/extremum.hpp>
#include <nt2/core/utility/of_size.hpp>
#include <nt2/sdk/meta/as_signed.hpp>
#include <nt2/sdk/meta/is_signed.hpp>
#include <nt2/sdk/meta/constant_adaptor.hpp>
#include <nt2/sdk/meta/as.hpp>
#include <boost/mpl/bool.hpp>

namespace nt2 { namespace tag
{
  struct table_;
  struct colon_;
  struct unity_colon_;
  struct terminal_;
} }

namespace nt2 { namespace details
{
  /// INTERNAL ONLY
  /// Factorized code for colon size evaluation
  template<class L, class S, class U>
  BOOST_FORCEINLINE std::size_t
  colon_size(L const& l, S const& s, U const& u)
  {
    typedef typename meta::as_signed<L>::type ltype;
    typedef typename meta::as_signed<U>::type utype;
    return s ? ( ((u>l)==(s>0)) ? (utype(u)-ltype(l)+s)/s : (u == l)) : u;
  }

  /// INTERNAL ONLY
  /// Factorized code for colon evaluation
  template<class L, class S, class Pos, class Target>
  BOOST_FORCEINLINE typename Target::type
  colon_value(L const& l, S const& s, Pos const& p, Target const&)
  {
    typedef typename Target::type type;
    return nt2::fma ( nt2::enumerate<type>(p)
                    , nt2::splat<type>(s), nt2::splat<type>(l)
                    );
  }

  /// INTERNAL ONLY
  /// Same sign helper unity_colon_size
  template<class L, class U, bool B> BOOST_FORCEINLINE std::size_t
  unity_helper( L const& l, U const& u
              , boost::mpl::bool_<B> const&
              , boost::mpl::bool_<B> const&
              )
  {
    return (u >= l) ? static_cast<std::size_t>(u-l+1) : 0u;
  }

  /// INTERNAL ONLY
  /// signed/unsigned helper unity_colon_size
  template<class L, class U> BOOST_FORCEINLINE std::size_t
  unity_helper( L const& l, U const& u
              , const boost::mpl::true_&
              , const boost::integral_constant<bool, false>&
              )
  {
    return (l <= 0) ? static_cast<std::size_t>(u-l+1)
                    : ( u >= static_cast<U>(l)  ? static_cast<std::size_t>(u-l+1)
                                                : 0u
                      );
  }

  /// INTERNAL ONLY
  /// unsigned/signed helper unity_colon_size
  template<class L, class U> BOOST_FORCEINLINE std::size_t
  unity_helper( L const& l, U const& u
              , const boost::integral_constant<bool, false>&
              , const boost::integral_constant<bool, true>&
              )
  {
    return (u <= 0) ? 0u
                    : ( static_cast<L>(u) >= l  ? static_cast<std::size_t>(u-l+1)
                                                : 0u
                      );
  }

  /// INTERNAL ONLY
  /// Factorized code for unity colon size evaluation
  template<class L, class U>
  BOOST_FORCEINLINE std::size_t unity_colon_size(L const& l, U const& u)
  {
    return unity_helper ( l , u
                        , typename nt2::meta::is_signed<L>::type()
                        , typename nt2::meta::is_signed<U>::type()
                        );
  }

  /// INTERNAL ONLY
  /// Factorized code for unity colon evaluation
  template<class T, class Pos, class Target>
  BOOST_FORCEINLINE typename Target::type
  unity_colon_value(T const& l, Pos const& p, Target const&)
  {
    typedef typename Target::type type;
    return  nt2::enumerate<type>(p)+nt2::splat<type>(l);
  }

  /// INTERNAL ONLY
  /// Storage for relative colon info
  template<class Begin, class End> struct relative_colon
  {
    typedef typename meta::is_extremum<Begin>::type is_begin_t;
    typedef typename meta::is_extremum<End>::type   is_end_t;

    Begin begin_;
    End   end_;

    // Computations of lower & upper have to take care of all
    // begin/end or end/begin combinations
    template<class B, class S> std::ptrdiff_t lower(B const& b, S const& s) const
    {
      return lower(b,s,is_begin_t());
    }

    template<class B, class S> std::ptrdiff_t upper(B const& b, S const& s) const
    {
      return upper(b,s,is_end_t());
    }

    private:
    // lower/upper computations for scalar extremum
    template<class B, class S>
    std::ptrdiff_t lower(B const&, S const&, boost::mpl::false_ const&) const
    {
      return begin_;
    }

    template<class B, class S>
    std::ptrdiff_t upper(B const&, S const&, boost::mpl::false_ const&) const
    {
      return end_;
    }

    // lower/upper computations for begin_/end_
    template<class B, class S>
    std::ptrdiff_t lower(B const& b, S const& s, boost::mpl::true_ const&) const
    {
      return begin_.index(b,s);
    }

    template<class B, class S>
    std::ptrdiff_t upper(B const& b, S const& s, boost::mpl::true_ const&) const
    {
      return end_.index(b,s);
    }
  };
} }

namespace nt2 { namespace ext
{
  // _(a, b)
  template<std::size_t N, std::size_t Cardinal>
  struct is_multiple_of
    : boost::mpl::bool_< !(N % Cardinal) >
  {
  };

  template<std::size_t N>
  struct is_multiple_of<N, 0>
       : boost::mpl::false_
  {
  };

  template<class T, std::ptrdiff_t N, class Cardinal>
  struct is_vectorizable_indexer<
    nt2::container::expression<
      boost::proto::basic_expr<
          nt2::tag::colon_
        , boost::proto::list3<
              nt2::container::expression<
                  boost::proto::basic_expr<
                      nt2::tag::terminal_
                    , boost::proto::term<
                          nt2::of_size_<1l, N, 1l, 1l>
                      >
                    , 0l
                  >
                , nt2::of_size_<1l, N, 1l, 1l>
              >
            , nt2::container::expression<
                  boost::proto::basic_expr<
                      nt2::tag::terminal_
                    , boost::proto::term<
                          nt2::meta::constant_<nt2::tag::unity_colon_, T>
                      >
                    , 0l
                  >
                , nt2::meta::constant_<nt2::tag::unity_colon_, T>
              >
            , nt2::container::expression<
                  boost::proto::basic_expr<
                      nt2::tag::terminal_
                    , boost::proto::term<
                          boost::dispatch::meta::as_<T>
                      >
                    , 0l
                  >
                , boost::dispatch::meta::as_<T>
              >
          >
        , 3l
      >
    , nt2::memory::container<
          tag::table_
        , T
        , nt2::settings(
            nt2::of_size_<
                1l
              , N
              , 1l
              , 1l
            >
          )
      >
    >
  , Cardinal
  >
    : is_multiple_of<std::size_t(N < 0 ? -N : N), Cardinal::value>
  {
  };
} }

namespace nt2 { namespace meta
{
  /// INTERNAL ONLY
  /// colon actual functor : precompute step and just iterate over
  template<class Base> struct constant_<nt2::tag::colon_, Base>
  {
    typedef Base  base_type;

    constant_() {}
    constant_( Base const& l, Base const& s) : lower_(l), step_(s) {}

    template<class Pos, class Size,class Target>
    BOOST_FORCEINLINE typename Target::type
    operator()(Pos const& p, Size const&, Target const& t) const
    {
      return details::colon_value(lower_,step_,p,t);
    }

    private:
    Base lower_, step_;
  };

  /// INTERNAL ONLY
  /// unity_colon actual functor : just forward form lower bound
  template<class Base> struct constant_<nt2::tag::unity_colon_, Base>
  {
    typedef Base  base_type;

    constant_() {}
    constant_( Base const& l ) : lower_(l) {}

    template<class Pos, class Size,class Target>
    BOOST_FORCEINLINE typename Target::type
    operator()(Pos const& p, Size const&, Target const& t) const
    {
      return details::unity_colon_value(lower_,p,t);
    }

    private:
    Base lower_;
  };
} }

#endif


#include "lokid_key.h"
#include "utils.hpp"
extern "C" {
#include "sodium/private/ed25519_ref10.h"
}

#include <boost/filesystem.hpp>
#include <boost/format.hpp>

#include <sodium.h>

#include <exception>
#include <fstream>
#include <iterator>

namespace fs = boost::filesystem;

namespace loki {

private_key_t lokidKeyFromHex(const std::string& private_key_hex) {
    if (private_key_hex.size() != KEY_LENGTH * 2)
        throw std::runtime_error(
                "Lokid key data is invalid: expected " + std::to_string(KEY_LENGTH) + " bytes not " +
                std::to_string(private_key_hex.size()) + " bytes");

    const auto bytes = util::hex_to_bytes(private_key_hex);
    private_key_t private_key;
    std::copy(bytes.begin(), bytes.end(), private_key.begin());

    return private_key;
}

private_key_ed25519_t
private_key_ed25519_t::from_hex(const std::string& sc_hex) {
    if (sc_hex.size() != private_key_ed25519_t::LENGTH * 2)
        throw std::runtime_error("Lokid key data is invalid: expected " +
                                 std::to_string(private_key_ed25519_t::LENGTH) +
                                 " bytes not " + std::to_string(sc_hex.size()) +
                                 " bytes");

    private_key_ed25519_t key;

    const auto bytes = util::hex_to_bytes(sc_hex);
    std::copy(bytes.begin(), bytes.end(), key.data.begin());

    return key;
}

public_key_t derive_pubkey_legacy(const private_key_t& private_key) {
    ge25519_p3 A;
    ge25519_scalarmult_base(&A, private_key.data());
    public_key_t publicKey;
    ge25519_p3_tobytes(publicKey.data(), &A);

    return publicKey;
}

public_key_t derive_pubkey_x25519(const private_key_t& seckey) {

    public_key_t pubkey;
    crypto_scalarmult_curve25519_base(pubkey.data(), seckey.data());

    return pubkey;
}

public_key_t derive_pubkey_ed25519(const private_key_ed25519_t& seckey) {

    public_key_t pubkey;
    crypto_sign_ed25519_sk_to_pk(pubkey.data(), seckey.data.data());

    return pubkey;
}

} // namespace loki


/**
 * Copyright Soramitsu Co., Ltd. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

#include "utils/amount_utils.hpp"
#include <boost/format.hpp>

namespace shared_model {
  namespace detail {
    const boost::multiprecision::uint256_t ten = 10;

    boost::multiprecision::uint256_t increaseValuePrecision(
        const boost::multiprecision::uint256_t &value, int degree) {
      return value * pow(ten, degree);
    }

    /**
     * Sums up two amounts.
     * Result is returned
     * @param a left term
     * @param b right term
     */
    iroha::expected::PolymorphicResult<shared_model::interface::Amount,
                                       std::string>
    operator+(const shared_model::interface::Amount &a,
              const shared_model::interface::Amount &b) {
      auto max_precision = std::max(a.precision(), b.precision());
      auto val_a =
          increaseValuePrecision(a.intValue(), max_precision - a.precision());
      auto val_b =
          increaseValuePrecision(b.intValue(), max_precision - b.precision());
      if (val_a < a.intValue() || val_b < b.intValue() || val_a + val_b < val_a
          || val_a + val_b < val_b) {
        return iroha::expected::makeError(std::make_shared<std::string>(
            (boost::format("addition overflows (%s + %s)") % a.intValue().str()
             % b.intValue().str())
                .str()));
      }
      std::string val = (val_a + val_b).str();
      if (max_precision != 0) {
        val.insert((val.rbegin() + max_precision).base(), '.');
      }
      return iroha::expected::makeValue(
          std::make_shared<shared_model::interface::Amount>(std::move(val)));
    }

    /**
     * Subtracts two amounts.
     * Result is returned
     * @param a left term
     * @param b right term
     */
    iroha::expected::PolymorphicResult<shared_model::interface::Amount,
                                       std::string>
    operator-(const shared_model::interface::Amount &a,
              const shared_model::interface::Amount &b) {
      auto max_precision = std::max(a.precision(), b.precision());
      auto val_a =
          increaseValuePrecision(a.intValue(), max_precision - a.precision());
      auto val_b =
          increaseValuePrecision(b.intValue(), max_precision - b.precision());
      if (val_a < a.intValue() || val_b < b.intValue()) {
        return iroha::expected::makeError(
            std::make_shared<std::string>("new precision overflows number"));
      }
      auto diff = val_a - val_b;
      std::string val = diff.str();
      if (max_precision != 0 && val.size() > max_precision + 1) {
        auto ptr = val.rbegin() + max_precision;
        val.insert(ptr.base(), '.');
      }
      return iroha::expected::makeValue(
          std::make_shared<shared_model::interface::Amount>(std::move(val)));
    }

    /**
     * Make amount with bigger precision
     * Result is returned
     * @param a amount
     * @param b right term
     */
    iroha::expected::PolymorphicResult<shared_model::interface::Amount,
                                       std::string>
    makeAmountWithPrecision(const shared_model::interface::Amount &amount,
                            const int new_precision) {
      if (amount.precision() > new_precision) {
        return iroha::expected::makeError(std::make_shared<std::string>(
            (boost::format("new precision is smaller than current (%d < %d)")
             % new_precision % amount.precision())
                .str()));
      }
      auto val_amount = increaseValuePrecision(
          amount.intValue(), new_precision - amount.precision());
      if (val_amount < amount.intValue()) {
        return iroha::expected::makeError(
            std::make_shared<std::string>("operation overflows number"));
      }
      std::string val = val_amount.str();
      if (new_precision != 0) {
        val.insert((val.rbegin() + new_precision).base(), '.');
      }
      return iroha::expected::makeValue(
          std::make_shared<shared_model::interface::Amount>(std::move(val)));
    }

    int compareAmount(const shared_model::interface::Amount &a,
                      const shared_model::interface::Amount &b) {
      if (a.precision() == b.precision()) {
        return (a.intValue() < b.intValue())
            ? -1
            : (a.intValue() > b.intValue()) ? 1 : 0;
      }
      // when different precisions transform to have the same scale
      auto max_precision = std::max(a.precision(), b.precision());

      auto val1 =
          increaseValuePrecision(a.intValue(), max_precision - a.precision());
      auto val2 =
          increaseValuePrecision(b.intValue(), max_precision - b.precision());
      return (val1 < val2) ? -1 : (val1 > val2) ? 1 : 0;
    }
  }  // namespace detail
}  // namespace shared_model


// Boost.Geometry

// Copyright (c) 2021, Oracle and/or its affiliates.

// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle

// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html

#ifndef BOOST_GEOMETRY_STRATEGIES_DENSIFY_GEOGRAPHIC_HPP
#define BOOST_GEOMETRY_STRATEGIES_DENSIFY_GEOGRAPHIC_HPP

#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/densify/services.hpp>

#include <boost/geometry/strategies/geographic/densify.hpp>

namespace boost { namespace geometry
{

namespace strategies { namespace densify
{

template
<
    typename FormulaPolicy = strategy::andoyer,
    typename Spheroid = srs::spheroid<double>,
    typename CalculationType = void
>
class geographic
    : public strategies::detail::geographic_base<Spheroid>
{
    using base_t = strategies::detail::geographic_base<Spheroid>;

public:
    geographic() = default;

    explicit geographic(Spheroid const& spheroid)
        : base_t(spheroid)
    {}

    template <typename Geometry>
    auto densify(Geometry const&) const
    {
        return strategy::densify::geographic
                <
                    FormulaPolicy, Spheroid, CalculationType
                >(base_t::m_spheroid);
    }
};

namespace services
{

template <typename Geometry>
struct default_strategy<Geometry, geographic_tag>
{
    using type = strategies::densify::geographic<>;
};

template <typename FP, typename S, typename CT>
struct strategy_converter<strategy::densify::geographic<FP, S, CT> >
{
    static auto get(strategy::densify::geographic<FP, S, CT> const& s)
    {
        return strategies::densify::geographic<FP, S, CT>(s.model());
    }
};

} // namespace services

}} // namespace strategies::densify

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_STRATEGIES_DENSIFY_GEOGRAPHIC_HPP