#include <cstdint>
#include <iostream>
#include <memory>
#include <algorithm>
#include <boost/regex.hpp>

#include <osmium/area/assembler.hpp>
#include <osmium/area/multipolygon_collector.hpp>

#include <osmium/index/map/dummy.hpp>
#include <osmium/index/map/sparse_mem_array.hpp>

#include <osmium/handler/node_locations_for_ways.hpp>

#include <osmium/io/any_input.hpp>
#include <osmium/handler.hpp>
#include <osmium/visitor.hpp>
#include <proj_api.h>
//#include "earcut.hxx"
#include "ObjWriter.hxx"
#include "elevation.hxx"

using namespace std;
using namespace boost;
using namespace osmwave;

typedef osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location> index_type;
typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type;

projPJ wgs84 = pj_init_plus("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
const double METERS_PER_LEVEL = 3.0;

class ObjHandler : public osmium::handler::Handler {
    projPJ proj;
    ObjWriter writer;
    vector<double> wayCoords;
    Elevation& elevation;
    double defaultBuildingHeight;

public:
    ObjHandler(projPJ p, ObjWriter writer, Elevation& elevation, double defaultBuildingHeight = 8) :
        proj(p), writer(writer), elevation(elevation), defaultBuildingHeight(defaultBuildingHeight) {}

    void area(osmium::Area& area) {
        const osmium::TagList& tags = area.tags();
        const char* building = tags.get_value_by_key("building");
        const char* buildingPart = tags.get_value_by_key("building:part");
        const char* highway = tags.get_value_by_key("highway");

        if (!building && !buildingPart /*&& !highway*/) {
            return;
        }

        double height = getBuildingHeight(tags, defaultBuildingHeight, "height", "building:levels");
        double baseHeight = getBuildingHeight(tags, 0, "min_height", "building:min_level");

        for (auto oit = area.cbegin<osmium::OuterRing>(); oit != area.cend<osmium::OuterRing>(); ++oit) {
            const osmium::NodeRefList& nodes = *oit;
            int nNodes = nodes.size();

            if (wayCoords.capacity() < nNodes) {
                wayCoords.reserve(nNodes * 2);
            }

            double minElevation = numeric_limits<double>::max();
            for (auto& nr : nodes) {
                double lon = nr.lon();
                double lat = nr.lat();
                wayCoords.push_back(lon * DEG_TO_RAD);
                wayCoords.push_back(lat * DEG_TO_RAD);
                minElevation = min(minElevation, elevation.elevation(lat, lon));
            }

            pj_transform(wgs84, proj, nodes.size(), 2, wayCoords.data(), wayCoords.data() + 1, nullptr);

            ringWalls(wayCoords, minElevation + baseHeight, height - baseHeight);
            flatRoof(nNodes);

            wayCoords.clear();
        }
    }

private:
    void ringWalls(vector<double> wayCoords, double elevation, double height) {
        int nVerts = wayCoords.size() / 2;
        int vertexCount = 0;
        writer.checkpoint();
        for (vector<double>::iterator i = wayCoords.begin(); i != wayCoords.end(); i += 2) {
            writer.vertex(*(i + 1), elevation, *i);
            writer.vertex(*(i + 1), elevation + height, *i);

            if (vertexCount) {
                writer.beginFace();
                writer << (vertexCount - 2) << (vertexCount) << (vertexCount + 1) << (vertexCount - 1);
                writer.endFace();
            }

            vertexCount += 2;
        }
    }

    void flatRoof(int nVerts) {
        writer.beginFace();
        for (int i = 0; i < nVerts; i++) {
            writer << (i * 2 + 1);
        }
        writer.endFace();
    }

    double getBuildingHeight(const osmium::TagList& tags, double defaultHeight, const char* heightTagName, const char* levelTagName) {
        regex heightexpr("^\\s*([0-9\\.]+)\\s*(\\S*)\\s*$");
        const char* heightTag = tags[heightTagName];
        double height = defaultHeight;

        if (heightTag) {
            string heightStr(heightTag);
            auto match_begin =
                sregex_iterator(heightStr.begin(), heightStr.end(), heightexpr);
            auto match_end = sregex_iterator();

            if (match_begin != match_end) {
                smatch match = *match_begin;
                height = stod(match[1]);
            }
        } else {
            const char* levelsTag = tags[levelTagName];
            if (levelsTag) {
                string levelsStr(levelsTag);
                try {
                    double levels = stod(levelsStr);
                    height = levels * METERS_PER_LEVEL;
                } catch (const invalid_argument& ia) {
                    cerr << "Unparseable value for \"building:levels\" tag: \"" << levelsStr << "\"" << endl;
                }
            }
        }

        return height;
    }
};

string* get_proj(osmium::io::Header& header) {
    auto& box = header.boxes()[0];
    float clat = (box.bottom_left().lat() + box.top_right().lat()) / 2;
    float clon = (box.bottom_left().lon() + box.top_right().lon()) / 2;

    ostringstream stream;
    stream << "+proj=tmerc +lat_0=" << clat << " +lon_0=" << clon << " +k=1.000000 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs";
    return new string(stream.str());
}

namespace osmwave {
    void write_obj_header(ObjWriter& objWriter, const string& osmFile, const osmium::Location& sw, const osmium::Location& ne, projPJ proj) {
        ostringstream c;
        c.precision(7);

        objWriter.comment("Created with OSMWAVE");
        objWriter.comment("");

        c << "Input file: " << osmFile;
        objWriter.comment(c.str());
        cerr << c.str() << endl;

        c.str("");
        c << "Lat/lng bounds: (" << sw.lat() << ", " << sw.lon() << ") - (" << ne.lat() << ", " << ne.lon() << ")";
        objWriter.comment(c.str());
        cerr << c.str() << endl;

        c.str("");
        c << "Projection: " << pj_get_def(proj, 0);
        objWriter.comment(c.str());
        cerr << c.str() << endl;

        double coord[2];
        c.str("");
        c << "Projected bounds: (";
        coord[0] = sw.lon() * DEG_TO_RAD;
        coord[1] = sw.lat() * DEG_TO_RAD;
        pj_transform(wgs84, proj, 1, 2, coord, coord + 1, nullptr);
        c << coord[0] << ", " << coord[1];
        c << ") - (";
        coord[0] = ne.lon() * DEG_TO_RAD;
        coord[1] = ne.lat() * DEG_TO_RAD;
        pj_transform(wgs84, proj, 1, 2, coord, coord + 1, nullptr);
        c << coord[0] << ", " << coord[1];
        c << ")";
        objWriter.comment(c.str());
        cerr << c.str() << endl;
    }

    void osm_to_obj(const std::string& osmFile, const std::string& elevationPath, const std::string* projDef) {
        ObjWriter objWriter(cout);

        osmium::io::File infile(osmFile);
        osmium::area::Assembler::config_type assembler_config;
        osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config);

        osmium::io::Reader reader1(infile, osmium::osm_entity_bits::relation);
        collector.read_relations(reader1);
        reader1.close();

        osmium::io::Reader reader2(osmFile);
        osmium::io::Header header = reader2.header();
        projPJ proj;

        auto& box = header.boxes()[0];
        auto& sw = box.bottom_left();
        auto& ne = box.top_right();
        float clat = (box.bottom_left().lat() + box.top_right().lat()) / 2;
        float clon = (box.bottom_left().lon() + box.top_right().lon()) / 2;
        if (!projDef) {
            projDef = get_proj(header);
            proj = pj_init_plus(projDef->c_str());
            delete projDef;
        } else {
            proj = pj_init_plus(projDef->c_str());
        }

        write_obj_header(objWriter, osmFile, sw, ne, proj);

        const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance();
        unique_ptr<index_type> index = map_factory.create_map("sparse_mem_array");
        location_handler_type location_handler(*index);
        location_handler.ignore_errors();

        Elevation elevation((int)floor(sw.lat()), (int)floor(sw.lon()), (int)floor(ne.lat()), (int)floor(ne.lon()), elevationPath);
        ObjHandler handler(proj, objWriter, elevation);
        osmium::apply(reader2, location_handler, collector.handler([&handler](osmium::memory::Buffer&& buffer) {
            osmium::apply(buffer, handler);
        }));
        reader2.close();
    }
}


//==================================================================================================
/*!
  @file
    @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_FUNCTION_SIGNGAM_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_SIGNGAM_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

  /*!
    @ingroup group-euler
    This function object computes the sign of gamma function without explicitly computing
    the costly gamma function.

    @see gamma, gammaln

    @par Header <boost/simd/function/signgam.hpp>

    @par Example:

      @snippet stirling.cpp stirling

    @par Possible output:

      @snippet stirling.txt stirling
  **/
  IEEEValue signgam(IEEEValue const& x);
} }
#endif

#include <boost/simd/function/scalar/signgam.hpp>
#include <boost/simd/function/simd/signgam.hpp>

#endif


///////////////////////////////////////////////////////////////////////////////
//  Copyright 2012 John Maddock. 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)

#ifdef _MSC_VER
#pragma warning(disable:4244)
#endif

#include <boost/polygon/detail/voronoi_predicates.hpp>
#include <boost/polygon/detail/voronoi_structures.hpp>
#include <boost/polygon/detail/skeleton_predicates.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <vector>
#include <map>
#include <boost/chrono.hpp>
#include <boost/multiprecision/cpp_int.hpp>

#ifdef TEST_GMP
#include <boost/multiprecision/gmp.hpp>
#endif
#ifdef TEST_TOMMATH
#include <boost/multiprecision/tommath.hpp>
#endif

#include "arithmetic_backend.hpp"

typedef boost::polygon::detail::point_2d<boost::int32_t> i_point;

template <class Clock>
struct stopwatch
{
   typedef typename Clock::duration duration;
   stopwatch()
   {
      m_start = Clock::now();
   }
   duration elapsed()
   {
      return Clock::now() - m_start;
   }
   void reset()
   {
      m_start = Clock::now();
   }

private:
   typename Clock::time_point m_start;
};

std::vector<i_point> points;
boost::random::mt19937 gen;

template <class Big>
struct cpp_int_voronoi_traits
{
  typedef boost::int32_t int_type;
  typedef boost::int64_t int_x2_type;
  typedef boost::uint64_t uint_x2_type;
  typedef Big big_int_type;
  typedef double fpt_type;
  typedef boost::polygon::detail::extended_exponent_fpt<fpt_type> efpt_type;
  typedef boost::polygon::detail::ulp_comparison<fpt_type> ulp_cmp_type;
  struct to_fpt_converter_type
  {
     template <class B, boost::multiprecision::expression_template_option ET>
     double operator ()(const boost::multiprecision::number<B, ET>& val)
     {
        return val.template convert_to<double>();
     }
     double operator ()(double val)
     {
        return val;
     }
     double operator()(const efpt_type& that) const
     {
        return that.d();
     }
     template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
     double operator()(const boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
     {
        typedef typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type r_t;
        r_t r(e);
        return r.template convert_to<double>();
     }
  };
  struct to_efpt_converter_type
  {
     template <class B, boost::multiprecision::expression_template_option ET>
     efpt_type operator ()(const boost::multiprecision::number<B, ET>& val)
     {
        return efpt_type(val.template convert_to<double>(), 0);
     }
     efpt_type operator ()(double val)
     {
        return efpt_type(val, 0);
     }
     template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
     double operator()(const boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
     {
        typedef typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type r_t;
        r_t r(e);
        return efpt_type(r.template convert_to<double>(), 0);
     }
  };
};

template <class Big>
struct native_int_voronoi_traits
{
  typedef boost::int32_t int_type;
  typedef boost::int64_t int_x2_type;
  typedef boost::uint64_t uint_x2_type;
  typedef Big big_int_type;
  typedef double fpt_type;
  typedef boost::polygon::detail::extended_exponent_fpt<fpt_type> efpt_type;
  typedef boost::polygon::detail::ulp_comparison<fpt_type> ulp_cmp_type;
  struct to_fpt_converter_type
  {
     template <class T>
     double operator ()(const T& val)const
     {
        return val;
     }
     double operator()(const efpt_type& that) const
     {
        return that.d();
     }
  };
  struct to_efpt_converter_type
  {
     template <class T>
     efpt_type operator ()(const T& val)const
     {
        return efpt_type(val, 0);
     }
  };
};

std::map<std::string, double> results;
double min_time = (std::numeric_limits<double>::max)();

template <class Traits>
double test(const char* name)
{
   typedef boost::polygon::detail::voronoi_predicates<Traits> preds;
   typedef boost::polygon::detail::circle_event<boost::int32_t> circle_event;
   typedef boost::polygon::detail::site_event<boost::int32_t> site_event;
   typedef typename preds::template mp_circle_formation_functor<site_event, circle_event> circle_pred;

   boost::random::uniform_int_distribution<> dist(0, points.size() - 1);
   circle_pred pc;
   circle_event event;

   stopwatch<boost::chrono::high_resolution_clock> w;

   for(unsigned i = 0; i < 10000; ++i)
   {
      site_event s1(points[dist(gen)]);
      site_event s2(points[dist(gen)]);
      site_event s3(points[dist(gen)]);
      pc.ppp(s1, s2, s3, event);
      pc.pps(s1, s2, s3, 0, event);
      pc.pss(s1, s2, s3, 0, event);
      pc.sss(s1, s2, s3, event);
   }
   double d = boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
   if(d < min_time)
      min_time = d;
   results[name] = d;
   std::cout << "Time for " << std::setw(30) << std::left << name << " = " << d << std::endl;
   return d;
}

void generate_quickbook()
{
   std::cout << "[table\n[[Integer Type][Relative Performance (Actual time in parenthesis)]]\n";

   std::map<std::string, double>::const_iterator i(results.begin()), j(results.end());

   while(i != j)
   {
      double rel = i->second / min_time;
      std::cout << "[[" << i->first << "][" << rel << "(" << i->second << "s)]]\n";
      ++i;
   }

   std::cout << "]\n";
}

int main()
{
   boost::random::uniform_int_distribution<> dist((std::numeric_limits<boost::int32_t>::min)() / 2, (std::numeric_limits<boost::int32_t>::max)() / 2);

   for(unsigned i = 0; i < 100; ++i)
   {
      points.push_back(i_point(dist(gen), dist(gen)));
   }

   test<boost::polygon::detail::voronoi_ctype_traits<boost::int32_t> >("extended_int");

   test<cpp_int_voronoi_traits<boost::multiprecision::int256_t> >("int256_t");
   test<cpp_int_voronoi_traits<boost::multiprecision::int512_t> >("int512_t");
   test<cpp_int_voronoi_traits<boost::multiprecision::int1024_t> >("int1024_t");

   test<cpp_int_voronoi_traits<boost::multiprecision::checked_int256_t> >("checked_int256_t");
   test<cpp_int_voronoi_traits<boost::multiprecision::checked_int512_t> >("checked_int512_t");
   test<cpp_int_voronoi_traits<boost::multiprecision::checked_int1024_t> >("checked_int1024_t");

   test<cpp_int_voronoi_traits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>, boost::multiprecision::et_off> > >("cpp_int");

#ifdef TEST_GMP
   test<cpp_int_voronoi_traits<boost::multiprecision::number<boost::multiprecision::gmp_int, boost::multiprecision::et_off> > >("mpz_int");
#endif
#ifdef TEST_TOMMATH
   test<cpp_int_voronoi_traits<boost::multiprecision::number<boost::multiprecision::tommath_int, boost::multiprecision::et_off> > >("tom_int");
#endif

   generate_quickbook();

   test<native_int_voronoi_traits<boost::int64_t> >("int64_t");
   test<cpp_int_voronoi_traits<boost::multiprecision::number<boost::multiprecision::arithmetic_backend<boost::int64_t>, boost::multiprecision::et_off> > >("number<arithmetic_backend<boost::int64_t>, et_off>");
   //test<cpp_int_voronoi_traits<boost::multiprecision::number<boost::multiprecision::arithmetic_backend<boost::int64_t>, boost::multiprecision::et_on> > >("number<arithmetic_backend<boost::int64_t>, et_on>");

   return 0;
}


/******************************************************************************
 *
 * AMDiS - Adaptive multidimensional simulations
 *
 * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved.
 * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis
 *
 * Authors:
 * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 *
 * This file is part of AMDiS
 *
 * See also license.opensource.txt in the distribution.
 *
 ******************************************************************************/

#include <boost/numeric/mtl/mtl.hpp>
#include "CompositeFEMOperator.h"
#include "SubElementAssembler.h"
#include "SubElInfo.h"
#include "SubPolytope.h"

namespace compositeFEM
{

  using namespace std;
  using namespace AMDiS;

  void CompositeFEMOperator::getElementMatrix(const ElInfo* elInfo,
      ElementMatrix& userMat,
      double factor)
  {
    FUNCNAME("CompositeFEMOperator::getElementMatrix");

    VectorOfFixVecs<DimVec<double>>* intersecPoints = NULL;
    SubPolytope* subPolytope = NULL;
    double levelSetSubPolytope;
    DimVec<double> subElVertexBarCoords(elInfo->getMesh()->getDim());

    /**
     * Get element status. Does element lie completely inside the integration
     * domain, completely outside of the integration domain or is it
     * intersected by the boundary ?
     */
    elStatus = elLS->createElementLevelSet(elInfo);

    /**
     * element status == completely inside or outside
     *                                       --->  take the "normal"
     *                                             integration routine
     *                                             Operator::getElementMatrix
     * element status == lies on boundary  ---> integration on subpolytopes and
     *                                          subelements
     */
    if (elStatus == ElementLevelSet::LEVEL_SET_INTERIOR  ||
        elStatus == ElementLevelSet::LEVEL_SET_EXTERIOR)
    {

      elLS->setLevelSetDomain(elStatus);
      Operator::getElementMatrix(elInfo, userMat, factor);
      return;
    }

    /***************************************************************************
     * Integration on intersected element.
     *
     * The integral is calculated as the sum of integrals on the two
     * subpolytopes given by the intersection.
     * We only calculate the integral on one of the subpolytopes. The
     * integral on the second subpolytope then is the difference between the
     * integral on the complete element and the integral on the first
     * subpolytope.
     */

    if(!subElementAssembler)
    {
      subElementAssembler = new SubElementAssembler(this,
          rowFeSpace,
          colFeSpace);
    }

    // Get intersection points.
    intersecPoints = elLS->getElIntersecPoints();
    subPolytope = new SubPolytope(elInfo,
                                  intersecPoints,
                                  elLS->getNumElIntersecPoints());

    /**
     * Calculate integral on element.
     *
     * Whether a subpolytope lies inside or outside the integration domain is
     * decided using the level set of the first vertex in the first subelement
     * of the subpolytope. (The subelements of a subpolytope are created in
     * such a way that this vertex always is a vertex of the element
     * and not an intersection point. Thus the level set of this vertex really
     * is unequal to zero.)
     */

    /**
     * Integration on subPolytope.
     */
    subElVertexBarCoords = subPolytope->getSubElement(0)->getLambda(0);
    levelSetSubPolytope = elLS->getVertexPos(
                            (const DimVec<double>) subElVertexBarCoords);

    if (levelSetSubPolytope < 0)
    {
      elLS->setLevelSetDomain(ElementLevelSet::LEVEL_SET_INTERIOR);
    }
    else if (levelSetSubPolytope > 0)
    {
      elLS->setLevelSetDomain(ElementLevelSet::LEVEL_SET_EXTERIOR);
    }
    else
    {
      ERROR_EXIT("cannot get position of subpolytope\n");
    }

    ElementMatrix subPolMat1(subElementAssembler->getNRow(),
                             subElementAssembler->getNCol());
    set_to_zero(subPolMat1);
    subElementAssembler->getSubPolytopeMatrix(subPolytope,
        subElementAssembler,
        elInfo,
        subPolMat1);

    /**
     * Integration on second subpolytope produced by the intersection.
     */
    ElementMatrix elMat(subElementAssembler->getNRow(),
                        subElementAssembler->getNCol());
    set_to_zero(elMat);
    ElementMatrix subPolMat2(subElementAssembler->getNRow(),
                             subElementAssembler->getNCol());
    set_to_zero(subPolMat2);

    if (!assembler.get())
    {
      Assembler* aptr = new StandardAssembler(this, NULL, NULL, NULL, NULL, rowFeSpace, colFeSpace);
      assembler.set(aptr);
    }

    if (elLS->getLevelSetDomain() ==
        ElementLevelSet::LEVEL_SET_INTERIOR)
    {
      elLS->setLevelSetDomain(ElementLevelSet::LEVEL_SET_EXTERIOR);
    }
    else
    {
      elLS->setLevelSetDomain(ElementLevelSet::LEVEL_SET_INTERIOR);
    }

    assembler.get()->calculateElementMatrix(elInfo, elMat, 1.0);
    subElementAssembler->getSubPolytopeMatrix(subPolytope,
        subElementAssembler,
        elInfo,
        subPolMat2);

    elMat -= subPolMat2;

    // Get integral on element as sum of the two integrals on subpolytopes.
    elMat += subPolMat1;

    // Add integral to userMat.
    userMat += factor * elMat;

    // Free data
    delete subPolytope;
  }

  void CompositeFEMOperator::getElementVector(const ElInfo* elInfo,
      DenseVector<double>& userVec,
      double factor)
  {
    FUNCNAME("CompositeFEMOperator::getElementVector");

    VectorOfFixVecs<DimVec<double>>* intersecPoints = NULL;
    SubPolytope* subPolytope = NULL;
    double levelSetSubPolytope;
    DimVec<double> subElVertexBarCoords(elInfo->getMesh()->getDim());

    /**
     * Get element status. Does element lie completely inside the integration
     * domain, completely outside of the integration domain or is it
     * intersected by the boundary ?
     */
    elStatus = elLS->createElementLevelSet(elInfo);

    /**
     * element status == completely inside or outside
     *                                        --->  take the "normal"
     *                                              integration routine
     *                                              Operator::getElementVector
     * element status == lies on boundary  ---> integration on subpolytopes and
     *                                          subelements
     */
    if (elStatus == ElementLevelSet::LEVEL_SET_INTERIOR  ||
        elStatus == ElementLevelSet::LEVEL_SET_EXTERIOR)
    {

      elLS->setLevelSetDomain(elStatus);
      Operator::getElementVector(elInfo, userVec, factor);
      return;
    }

    /*********************************************************************************
     * Integration on intersected element.
     *
     * The integral is calculated as the sum of integrals on the two
     * subpolytopes given by the intersection.
     * We only calculate the integral on one of the subpolytopes. The integral
     * on the second subpolytope then is the difference between the integral on
     * the complete element and the integral on the first subpolytope.
     */

    if(!subElementAssembler)
    {
      subElementAssembler = new SubElementAssembler(this,
          rowFeSpace,
          colFeSpace);
    }

    /**
     * Get intersection points.
     */
    intersecPoints = elLS->getElIntersecPoints();
    subPolytope = new SubPolytope(elInfo,
                                  intersecPoints,
                                  elLS->getNumElIntersecPoints());

    /**
     * Calculate integral on element.
     *
     * Whether a subpolytope lies inside or outside the integration domain is
     * decided using the level set of the first vertex in the first subelement
     * of the subpolytope. (The subelements of a subpolytope are created in
     * such a way that this vertex is always a vertex of the element and not
     * an intersection point. Thus the level set of this vertex really is
     * unequal to zero.)
     */

    /**
     * Integration on ubPolytope.
     */
    subElVertexBarCoords = subPolytope->getSubElement(0)->getLambda(0);
    levelSetSubPolytope = elLS->getVertexPos(
                            (const DimVec<double>) subElVertexBarCoords);

    if (levelSetSubPolytope < 0)
    {
      elLS->setLevelSetDomain(ElementLevelSet::LEVEL_SET_INTERIOR);
    }
    else if (levelSetSubPolytope > 0)
    {
      elLS->setLevelSetDomain(ElementLevelSet::LEVEL_SET_EXTERIOR);
    }
    else
    {
      ERROR_EXIT("cannot get position of subpolytope\n");
    }

    DenseVector<double> subPolVec1(subElementAssembler->getNRow());
    set_to_zero(subPolVec1);
    subElementAssembler->getSubPolytopeVector(subPolytope,
        subElementAssembler,
        elInfo,
        subPolVec1);

    // Integration on second subpolytope produced by the intersection.
    DenseVector<double> elVec(subElementAssembler->getNRow());
    set_to_zero(elVec);
    DenseVector<double> subPolVec2(subElementAssembler->getNRow());
    set_to_zero(subPolVec2);

    if (!assembler.get())
    {
      Assembler* aptr = new StandardAssembler(this, NULL, NULL, NULL, NULL, rowFeSpace, colFeSpace);
      assembler.set(aptr);
    }

    if (elLS->getLevelSetDomain() ==
        ElementLevelSet::LEVEL_SET_INTERIOR)
    {
      elLS->setLevelSetDomain(ElementLevelSet::LEVEL_SET_EXTERIOR);
    }
    else
    {
      elLS->setLevelSetDomain(ElementLevelSet::LEVEL_SET_INTERIOR);
    }

    assembler.get()->calculateElementVector(elInfo, elVec, 1.0);
    subElementAssembler->getSubPolytopeVector(subPolytope,
        subElementAssembler,
        elInfo,
        subPolVec2);

    elVec -= subPolVec2;

    // Get integral on element as sum of the two integrals on subpolytopes.
    elVec += subPolVec1;

    // Add integral to userVec.
    userVec += factor * elVec;

    // Free data
    delete subPolytope;
  }

}


#include "LocalWeightedArapParametrizer.h"

#include "eigen_stl_utils.h"

#include "igl/arap.h"
#include "igl/cat.h"
#include "igl/doublearea.h"
#include "igl/grad.h"
#include "igl/local_basis.h"
#include "igl/min_quad_with_fixed.h"
#include "igl/Timer.h"

#include <Eigen/IterativeLinearSolvers>
#include <Eigen/Sparse>
#include <Eigen/SparseQR>

#include "tbb/tbb.h"

#ifdef USE_PARDISO
LocalWeightedArapParametrizer::LocalWeightedArapParametrizer(Param_State* state, bool remeshing) :
                                  m_state(state),m_solver(ai,aj,K) {
    // empty
}
#else
LocalWeightedArapParametrizer::LocalWeightedArapParametrizer(Param_State* state, bool remeshing) :
                                  m_state(state) {
    // empty
}
#endif

void LocalWeightedArapParametrizer::parametrize( const Eigen::MatrixXd& V, const Eigen::MatrixXi& F,
              Eigen::VectorXi& b, Eigen::MatrixXd& bc, Eigen::MatrixXd& uv) {

  update_weights_and_closest_rotations(V,F,uv);
  solve_weighted_arap(V,F,uv,b,bc);
}

void LocalWeightedArapParametrizer::compute_jacobians(const Eigen::MatrixXd& uv) {
  // Ji=[D1*u,D2*u,D1*v,D2*v];
  int k_idx = 0;
  for (int i = 0; i < f_n; i++) {
    const int col1 = dxj[k_idx]-1; const int col2 = dxj[k_idx+1]-1; const int col3 = dxj[k_idx+2]-1;

    const double a_x_k = a_x(k_idx); const double a_x_k_1 = a_x(k_idx+1); const double a_x_k_2 = a_x(k_idx+2);

    Ji(i,0) = a_x_k * uv(col1,0) +  a_x_k_1 * uv(col2,0) +  a_x_k_2* uv(col3,0); // Dx*u
    Ji(i,2) = a_x_k * uv(col1,1) +  a_x_k_1 * uv(col2,1) + a_x_k_2 * uv(col3,1); // Dx*v

    const double a_y_k = a_y(k_idx); const double a_y_k_1 = a_y(k_idx+1); const double a_y_k_2 = a_y(k_idx+2);
    Ji(i,1) = a_y_k * uv(col1,0) + a_y_k_1 * uv(col2,0) + a_y_k_2 * uv(col3,0); // Dy*u
    Ji(i,3) = a_y_k * uv(col1,1) + a_y_k_1 * uv(col2,1) + a_y_k_2 * uv(col3,1); // Dy*v

    k_idx +=3;
  }

  //cout << "Got jacobians: " << m_state->timer.getElapsedTime() << endl;
}

class WeightUpdater {
    Param_State* m_state;
    const Eigen::MatrixXd& Ji; Eigen::MatrixXd& Ri;
    Eigen::VectorXd& W_11; Eigen::VectorXd& W_12; Eigen::VectorXd& W_21; Eigen::VectorXd& W_22;
public:

    void operator()( const tbb::blocked_range<size_t>& r ) const {
        const double eps = 1e-8;
        double exp_factor = m_state->exp_factor;
        for( size_t i=r.begin(); i!=r.end(); ++i ) {
           typedef Eigen::Matrix<double,2,2> Mat2;
          typedef Eigen::Matrix<double,2,1> Vec2;
          Mat2 ji,ri,ti,ui,vi; Vec2 sing; Vec2 closest_sing_vec;Mat2 mat_W;
          Mat2 fGrad; Vec2 m_sing_new;
          double s1,s2;

          ji(0,0) = Ji(i,0); ji(0,1) = Ji(i,1);
          ji(1,0) = Ji(i,2); ji(1,1) = Ji(i,3);

          igl::polar_svd(ji,ri,ti,ui,sing,vi);

          s1 = sing(0); s2 = sing(1);

          // Update Weights (currently supports only symmetric dirichlet)
          double s1_g = 2* (s1-pow(s1,-3));
          double s2_g = 2 * (s2-pow(s2,-3));
          m_sing_new << sqrt(s1_g/(2*(s1-1))), sqrt(s2_g/(2*(s2-1)));

          if (abs(s1-1) < eps) m_sing_new(0) = 1; if (abs(s2-1) < eps) m_sing_new(1) = 1;
          mat_W = ui*m_sing_new.asDiagonal()*ui.transpose();

          W_11(i) = mat_W(0,0);
          W_12(i) = mat_W(0,1);
          W_21(i) = mat_W(1,0);
          W_22(i) = mat_W(1,1);

          // 2) Update closest rotations (not rotations in case of conformal energy)
          Ri(i,0) = ri(0,0); Ri(i,1) = ri(1,0); Ri(i,2) = ri(0,1); Ri(i,3) = ri(1,1);
         }
    }
    WeightUpdater( Param_State* m_state, const Eigen::MatrixXd& Ji, Eigen::MatrixXd& Ri,
    Eigen::VectorXd& W_11, Eigen::VectorXd& W_12, Eigen::VectorXd& W_21, Eigen::VectorXd& W_22 ) :
        m_state(m_state),Ji(Ji),Ri(Ri),W_11(W_11),W_12(W_12),W_21(W_21),W_22(W_22)
    {}
};

void LocalWeightedArapParametrizer::update_weights_and_closest_rotations(const Eigen::MatrixXd& V,
       const Eigen::MatrixXi& F, Eigen::MatrixXd& uv) {
  //cout << "updating weights: " << m_state->timer.getElapsedTime() << endl;
  compute_jacobians(uv);

  static tbb::affinity_partitioner ap;
  parallel_for(tbb::blocked_range<size_t>(0,f_n), WeightUpdater(m_state, Ji,Ri,W_11,W_12,W_21,W_22),
    ap);
  //cout << "updated weights: " << m_state->timer.getElapsedTime() << endl;
}

void LocalWeightedArapParametrizer::solve_weighted_arap(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F,
        Eigen::MatrixXd& uv, Eigen::VectorXi& soft_b_p, Eigen::MatrixXd& soft_bc_p) {
  using namespace Eigen;

  /*b = [W11*R11 + W12*R21;
         W11*R12 + W12*R22;
         W21*R11 + W22*R21;
         W21*R12 + W22*R22];*/
  double h = m_state->proximal_p;

  get_At_AtMA_fast();

  #ifdef USE_PARDISO
    if (first_solve) {
      m_solver.set_pattern();
      m_solver.analyze_pattern();
      first_solve = false;
    }

    m_solver.factorize();
    Eigen::VectorXd res(rhs.rows());
    m_solver.solve(rhs,res);
    m_solver.free_numerical_factorization_memory();
    //cout << "Solved: " << m_state->timer.getElapsedTime() << endl;

    uv.col(0) = res.block(0,0,v_n,1);
    uv.col(1) = res.block(v_n,0,v_n,1);
  #else
    cout << "********Warning: The version is not optimized. Solving without Pardiso!************" << endl;
    // move to zero based
    for (int i = 0; i < aj.rows(); i++) {
      aj(i)--;
    }
    for (int i = 0; i < ai.rows(); i++) {
      ai(i)--;
    }

    igl::min_quad_with_fixed_data<double> solver_data;
    int nnz = aj.rows();
    SparseMatrix<double,RowMajor> mat = MappedSparseMatrix<double,Eigen::RowMajor>(2*v_n, 2*v_n, nnz, ai.data(), aj.data(), K.data());
    Eigen::SparseMatrix<double> Q(2*v_n,2*v_n);
    Q = mat.selfadjointView<Eigen::Upper>();

    bool ret_x = min_quad_with_fixed_precompute(
      Q,Eigen::VectorXi(),Eigen::SparseMatrix<double>(),false,solver_data);
    Eigen::VectorXd Uc,Beq;
    Eigen::VectorXd negRhs = -rhs;
    igl::min_quad_with_fixed_solve(
            solver_data,
            negRhs,Eigen::VectorXd(),Beq,
            Uc);

    uv.col(0) = Uc.block(0,0,v_n,1);
    uv.col(1) = Uc.block(v_n,0,v_n,1);

    // back to 1-based for Pardiso
    for (int i = 0; i < aj.rows(); i++) {
      aj(i)++;
    }
    for (int i = 0; i < ai.rows(); i++) {
      ai(i)++;
    }

  #endif
}

void LocalWeightedArapParametrizer::pre_calc() {
  if (!has_pre_calc) {
    f_n = m_state->F.rows(); v_n = m_state->V.rows();
    W_11.resize(f_n); W_12.resize(f_n); W_21.resize(f_n); W_22.resize(f_n);
    Ri.resize(f_n, 4); Ji.resize(f_n, 4);
    Eigen::MatrixXd F1,F2,F3;

    igl::local_basis(m_state->V,m_state->F,F1,F2,F3);
    Eigen::SparseMatrix<double> Dx,Dy;
    compute_surface_gradient_matrix(m_state->V,m_state->F,F1,F2,Dx,Dy);

    #ifdef USE_PARDISO
      m_solver.set_type(2); // 2 is PSD, -2 is symmetric indefinite Real symmetric matrix
    #endif
    first_solve = true;

    symmd_p = new SymmetricDirichlet(m_state);

    cout << "Building data structures" << endl;
    //cout << "building dx k maps" << endl;

    build_dx_k_maps(v_n, m_state->F, ai,aj, inst1, inst2, inst4, inst1_idx,inst2_idx,inst4_idx);
    //cout << "Built maps at: " << m_state->timer.getElapsedTime() << endl;

    K.resize(aj.rows());
    Eigen::VectorXi ai_t; Eigen::VectorXi aj_t;
    //cout << "Calling dx to csr: " << m_state->timer.getElapsedTime() << endl;
    dx_to_csr(Dx, dxi, dxj, a_x); dx_to_csr(Dy, ai_t, aj_t, a_y);

    int ax_size = a_x.rows();
    w11Dx.resize(ax_size); w12Dx.resize(ax_size); w11Dy.resize(ax_size); w12Dy.resize(ax_size);
    w21Dx.resize(ax_size); w22Dx.resize(ax_size); w21Dy.resize(ax_size); w22Dy.resize(ax_size);

    rhs.resize(2*v_n);

    has_pre_calc = true;
  }
}

void LocalWeightedArapParametrizer::get_At_AtMA_fast() {
  using namespace Eigen;

  //cout << "get_At_AtMA_fast " << m_state->timer.getElapsedTime() << endl;

  rhs.setZero();
  int A_idx = 0;
  for (int i = 0; i < f_n; i++) {
    int nnz_in_line = dxi[i+1] - dxi[i];
    for (int j = 0; j < nnz_in_line; j++) {
      double f1_i = m_state->M(i) * (W_11(i) * Ri(i,0) + W_12(i)*Ri(i,1));
      double f2_i = m_state->M(i) * (W_11(i) * Ri(i,2) + W_12(i)*Ri(i,3));
      double f3_i = m_state->M(i) * (W_21(i) * Ri(i,0) + W_22(i)*Ri(i,1));
      double f4_i = m_state->M(i) * (W_21(i) * Ri(i,2) + W_22(i)*Ri(i,3));

      int dest_k = dxj[A_idx]-1;
      rhs(dest_k) += a_x(A_idx) * W_11(i) * f1_i + a_y(A_idx) * W_11(i) * f2_i  + a_x(A_idx) * W_21(i) * f3_i + a_y(A_idx) * W_21(i) * f4_i;
      rhs(dest_k+v_n) += a_x(A_idx) * W_21(i) * f1_i + a_y(A_idx) * W_21(i) * f2_i  + a_x(A_idx) * W_22(i) * f3_i + a_y(A_idx) * W_22(i) * f4_i;

      A_idx++;
    }
  }

  for (int i = 0; i < f_n; i++) {
      W_11(i)*=sqrt(m_state->M(i));
      W_12(i)*=sqrt(m_state->M(i));
      W_21(i)*=sqrt(m_state->M(i));
      W_22(i)*=sqrt(m_state->M(i));
  }

  multiply_dx_by_W(a_x, W_11, w11Dx); multiply_dx_by_W(a_x, W_12, w12Dx);
  multiply_dx_by_W(a_y, W_11, w11Dy); multiply_dx_by_W(a_y, W_12, w12Dy);
  multiply_dx_by_W(a_x, W_21, w21Dx); multiply_dx_by_W(a_x, W_22, w22Dx);
  multiply_dx_by_W(a_y, W_21, w21Dy); multiply_dx_by_W(a_y, W_22, w22Dy);

  //cout << "Multiplied weights: " << m_state->timer.getElapsedTime() << endl;

  K.setZero();

  // K1
  add_dx_mult_dx_to_K(w11Dx,w11Dx, K, inst1,inst1_idx); add_dx_mult_dx_to_K(w11Dy,w11Dy, K, inst1,inst1_idx);
  add_dx_mult_dx_to_K(w21Dx,w21Dx, K, inst1,inst1_idx); add_dx_mult_dx_to_K(w21Dy,w21Dy, K, inst1,inst1_idx);

  // K2
  add_dx_mult_dx_to_K(w11Dx,w12Dx, K, inst2,inst2_idx); add_dx_mult_dx_to_K(w11Dy,w12Dy, K, inst2,inst2_idx);
  add_dx_mult_dx_to_K(w21Dx,w22Dx, K, inst2,inst2_idx); add_dx_mult_dx_to_K(w21Dy,w22Dy, K, inst2,inst2_idx);

  // K4
  add_dx_mult_dx_to_K(w12Dx,w12Dx, K, inst4,inst4_idx); add_dx_mult_dx_to_K(w12Dy,w12Dy, K, inst4,inst4_idx);
  add_dx_mult_dx_to_K(w22Dx,w22Dx, K, inst4,inst4_idx); add_dx_mult_dx_to_K(w22Dy,w22Dy, K, inst4,inst4_idx);

  //cout << "Computed new K: " << m_state->timer.getElapsedTime() << endl;

  //cout << "Added proximal penalty to K: " << m_state->timer.getElapsedTime() << endl;

  add_proximal_penalty();
}

void LocalWeightedArapParametrizer::add_proximal_penalty() {
  double h = m_state->proximal_p;
    // add proximal penalty
    for (int i = 0; i < v_n; i++) {
      rhs(i) += h * m_state->uv(i,0);
      rhs(v_n + i) += h * m_state->uv(i,1);
    }
  //cout << "Computed rhs: " << m_state->timer.getElapsedTime() << endl;
  int k_idx = 0;
  for (int i = 0; i < ai.rows()-1; i++) {
    int nnz = ai[i+1] - ai[i];
    for (int j = 0; j < nnz; j++) {
      int col = aj[k_idx];
      if ((i+1)==col) {
        K[k_idx] += h;
      }
      k_idx++;
    }
  }
}

void LocalWeightedArapParametrizer::compute_grad(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F,
                 Eigen::MatrixXd& uv, Eigen::MatrixXd& grad) {

  symmd_p->compute_negative_gradient(V, F, uv, grad);
  grad = -1*grad;
}

double LocalWeightedArapParametrizer::compute_energy(const Eigen::MatrixXd& V,
                                                       const Eigen::MatrixXi& F,
                                                       Eigen::MatrixXd& uv) {

  if (m_state->global_local_energy == Param_State::SYMMETRIC_DIRICHLET) {
    double symmd_e = symmd_p->compute_energy(V,F,uv);
    return symmd_e;
  } else {
    double symmd_e, log_e, conf_e,norm_arap_e, amips, exp_symmd;

    compute_jacobians(uv);
    compute_energies_with_jacobians(V,F, Ji, uv,m_state->M, symmd_e,log_e,conf_e,norm_arap_e, amips, exp_symmd, m_state->exp_factor, m_state->flips_linesearch);

    if ( m_state->global_local_energy == Param_State::SYMMETRIC_DIRICHLET) {
      //cout << "returning symmd energy, time = " << m_state->timer.getElapsedTime() << endl;
      return symmd_e;
    } else if (m_state->global_local_energy == Param_State::LOG_ARAP) {
      //cout << "returning LOG energy" << endl;
      return log_e;
    } else if (m_state->global_local_energy == Param_State::CONFORMAL) { // CONFORMAL
      //cout << "returning conformal energy" << endl;
      return conf_e;
    } else if (m_state->global_local_energy == Param_State::ARAP) {
      //cout << "returning arap energy" << endl;
      return norm_arap_e;
    } else if (m_state->global_local_energy == Param_State::AMIPS_ISO_2D) {
      return amips;
    } else if (m_state->global_local_energy == Param_State::EXP_symmd) {
      //cout << "returning exp symmd = " << exp_symmd << endl;
      return exp_symmd;
    }
  }
}


//==================================================================================================
/*!
  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)
*/
//==================================================================================================
#include <boost/simd/pack.hpp>
#include <iostream>

using namespace std;
using namespace boost::simd;

#define SECONDS_IN_ONE_DAY      86400

template <typename T>
class op_boost_utc_add
{
  typedef boost::simd::pack<T, 16 / sizeof(T)> p_t;
  const p_t seconds_in_one_day = boost::simd::splat<p_t>(SECONDS_IN_ONE_DAY);

  public:
  p_t operator()(p_t const &a0, p_t const &a1, p_t const &delta)
  {
    return a0 + (seconds_in_one_day * a1) + delta;
  }
};

int main()
{
  // long long is not supported, prefer std::int64_t
  typedef boost::simd::pack<std::int64_t, 2> p_l_t;

  p_l_t a(10, 100);
  p_l_t b(10, 100);
  p_l_t c(1, 1);

  p_l_t r = op_boost_utc_add<std::int64_t>()(a, b, c);

  cout << r << endl;

  return 0;
}


#include "leafsep.h"

#include <pcl/io/pcd_io.h>

#include <armadillo>

int main (int argc, char **argv)
{
	std::vector<std::string> args(argv+1,argv+argc);
	pcl::PCDReader reader;
	pcl::PCDWriter writer;
	int kn = std::stoi(args[0]);
	int n_gaus = std::stoi(args[1]);
	int dist_mode = std::stoi(args[2]);
	int seed_mode = std::stoi(args[3]);
	int km_iter = std::stoi(args[4]);
	int em_iter = std::stoi(args[5]);
	float smoothness = std::stof(args[6]);
	for(int i=7;i<args.size();i++)
	{
		std::cout << "----------: " << args[i] << std::endl;
		std::cout << "Reading cloud: " << std::flush;
		std::vector<std::string> id = getFileID(args[i]);
		pcl::PointCloud<PointTreeseg>::Ptr cloud(new pcl::PointCloud<PointTreeseg>);
		reader.read(args[i],*cloud);
		std::cout << "complete" << std::endl;
		//
		std::cout << "Region-based segmentation: " << std::flush;
		pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
		std::vector<pcl::PointCloud<PointTreeseg>::Ptr> regions;
		estimateNormals(cloud,250,normals);
		regionSegmentation(cloud,normals,30,3,std::numeric_limits<int>::max(),smoothness,1,regions);
		std::stringstream ss;
		ss << "regions_" << id[0] << ".pcd";
		writeClouds(regions,ss.str(),false);
		std::cout << ss.str() << std::endl;
		//
		std::cout << "Classifying cloud by region: " << std::flush;
		arma::mat featmatrix;
		arma::gmm_full model;
		gmmByCluster(regions,n_gaus,dist_mode,seed_mode,km_iter,em_iter,featmatrix,model);
		std::vector<int> classifications;
		classifications = classifyGmmClusterModel(regions,n_gaus,featmatrix,model);
		std::vector<pcl::PointCloud<PointTreeseg>::Ptr> clouds;
		separateCloudsClassifiedByCluster(regions,classifications,clouds);
		ss.str("");
		ss << "regions_rclass_" << id[0] << ".pcd";
		writeCloudClassifiedByCluster(regions,classifications,ss.str());
		std::cout << ss.str() << std::endl;
		//
		std::cout << "Classifying remaining cloud by point: " << std::flush;
		arma::mat pfeatmat;
		arma::gmm_diag pmodel;
		gmmByPoint(clouds[1],kn,n_gaus,dist_mode,seed_mode,km_iter,em_iter,pfeatmat,pmodel);
		std::vector<int> pclassifications;
		pclassifications = classifyGmmPointModel(clouds[1],n_gaus,pfeatmat,pmodel);
		std::vector<pcl::PointCloud<PointTreeseg>::Ptr> pclouds;
		separateCloudsClassifiedByPoint(clouds[1],pclassifications,pclouds);
		ss.str("");
		ss << "regions_rclass_pclass_" << id[0] << ".pcd";
		writeCloudClassifiedByPoint(clouds[1],pclassifications,ss.str());
		std::cout << ss.str() << std::endl;
		//
		std::cout << "Writing wood/leaf clouds: " << std::flush;
		pcl::PointCloud<PointTreeseg>::Ptr wood(new pcl::PointCloud<PointTreeseg>);
		*wood += *clouds[0] + *pclouds[0];
		ss.str("");
		ss << id[1] << "_" << id[0] << "w" << ".pcd";
		writer.write(ss.str(),*wood,true);
		std::cout << ss.str() << "," << std::flush;
		pcl::PointCloud<PointTreeseg>::Ptr leaf(new pcl::PointCloud<PointTreeseg>);
		*leaf = *pclouds[1];
		ss.str("");
		ss << id[1] << "_" << id[0] << "l" << ".pcd";
		writer.write(ss.str(),*leaf,true);
		std::cout << ss.str() << std::endl;
	}
	return 0;
}


#ifndef BART_SRC_FORMULATION_SCALAR_DIFFUSION_HPP_
#define BART_SRC_FORMULATION_SCALAR_DIFFUSION_HPP_

#include <memory>

#include <deal.II/lac/full_matrix.h>

#include "data/cross_sections/cross_sections_i.hpp"
#include "domain/finite_element/finite_element_i.hpp"
#include "formulation/scalar/diffusion_i.hpp"
#include "system/moments/spherical_harmonic_types.h"
#include "utility/has_dependencies.h"

namespace bart::formulation::scalar {

template <int dim>
class Diffusion : public DiffusionI<dim>, public utility::HasDependencies {
 public:
  using typename DiffusionI<dim>::BoundaryType;
  using typename DiffusionI<dim>::CellPtr;
  using typename DiffusionI<dim>::Matrix;
  using typename DiffusionI<dim>::Vector;
  using typename DiffusionI<dim>::GroupNumber;
  using typename DiffusionI<dim>::FaceNumber;

  // Dependency types
  using FiniteElement = typename domain::finite_element::FiniteElementI<dim>;
  using CrossSections = data::cross_sections::CrossSectionsI;

  // Moment types
  using MomentVector = system::moments::MomentVector;
  using MomentVectorMap = system::moments::MomentsMap;

  Diffusion(std::shared_ptr<FiniteElement>, std::shared_ptr<CrossSections>);

  auto Precalculate(const CellPtr& cell_ptr) -> void override;

  auto FillCellConstantTerm(Vector &to_fill, const CellPtr &ptr, const Vector &constant_vector) const -> void override;

  auto FillCellStreamingTerm(Matrix& to_fill, const CellPtr&, GroupNumber) const -> void override;

  auto FillCellCollisionTerm(Matrix& to_fill, const CellPtr&, GroupNumber) const -> void override;

  auto FillBoundaryTerm(Matrix& to_fill, const CellPtr&, FaceNumber, BoundaryType) const -> void override;

  auto FillCellFixedSource(Vector& to_fill, const CellPtr&, GroupNumber) const -> void override;

  auto FillCellFissionSource(Vector& to_fill, const CellPtr&, GroupNumber, double k_eigenvalue,
                             const MomentVector& in_group_moment,
                             const MomentVectorMap& group_moments) const -> void override;

  auto FillCellScatteringSource(Vector& to_fill, const CellPtr&, GroupNumber,
                                const MomentVectorMap & group_moments) const -> void override;

  auto is_initialized() const -> bool override { return is_initialized_; }

  // Getters & Setters
  /*! \brief Get precalculated matrices for the square of the shape function.
   *
   * \return Vector containing matrices corresponding to each quadrature point.
   */
  auto GetShapeSquared() const -> std::vector<Matrix> { return shape_squared_; }

  /*! \brief Get precalculated matrices for the square of the gradient
   * of the shape function.
   *
   * \return Vector containing matrices corresponding to each quadrature point.
   */
  auto GetGradientSquared() const -> std::vector<Matrix> { return gradient_squared_; }

  auto finite_element_ptr() const { return finite_element_ptr_.get(); }
  auto cross_sections_ptr() const { return cross_sections_ptr_.get(); }

 protected:
  //! Finite element object to provide shape function values
  std::shared_ptr<FiniteElement> finite_element_ptr_{ nullptr };
  //! Cross-sections object for cross-section data
  std::shared_ptr<CrossSections> cross_sections_ptr_{ nullptr };

  std::vector<Matrix> shape_squared_;
  std::vector<Matrix> gradient_squared_;
  const int cell_degrees_of_freedom_; //!< Number of degrees of freedom per cell
  const int cell_quadrature_points_; //!< Number of quadrature points per cell
  const int face_quadrature_points_; //!< Number of quadrature points per face
  bool is_initialized_{ false };

  auto VerifyInitialized(const std::string& called_function_name) const -> void;
};

} // namespace bart::formulation::scalar

#endif //BART_SRC_FORMULATION_SCALAR_DIFFUSION_HPP_


/**
* This file is part of DSO.
*
* Copyright 2016 Technical University of Munich and Intel.
* Developed by Jakob Engel <engelj at in dot tum dot de>,
* for more information see <http://vision.in.tum.de/dso>.
* If you use this code, please cite the respective publications as
* listed on the above website.
*
* DSO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DSO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DSO. If not, see <http://www.gnu.org/licenses/>.
*/

/*
 * KFBuffer.cpp
 *
 *  Created on: Jan 7, 2014
 *      Author: engelj
 */

#include "FullSystem/FullSystem.h"

#include "stdio.h"
#include "util/globalFuncs.h"
#include <Eigen/LU>
#include <algorithm>
#include "IOWrapper/ImageDisplay.h"
#include "util/globalCalib.h"

#include <Eigen/SVD>
#include <Eigen/Eigenvalues>
#include "FullSystem/ImmaturePoint.h"
#include "math.h"

namespace dso
{

PointHessian* FullSystem::optimizeImmaturePoint(
		ImmaturePoint* point, int minObs,
		ImmaturePointTemporaryResidual* residuals)
{
	int nres = 0;
	for(FrameHessian* fh : frameHessians)
	{
		if(fh != point->host)
		{
			residuals[nres].state_NewEnergy = residuals[nres].state_energy = 0;
			residuals[nres].state_NewState = ResState::OUTLIER;
			residuals[nres].state_state = ResState::IN;
			residuals[nres].target = fh;
			nres++;
		}
	}
	assert(nres == ((int)frameHessians.size())-1);

	bool print = false;//rand()%50==0;

	float lastEnergy = 0;
	float lastHdd=0;
	float lastbd=0;
	float currentIdepth=(point->idepth_max+point->idepth_min)*0.5f;

	for(int i=0;i<nres;i++)
	{
		lastEnergy += point->linearizeResidual(&Hcalib, 1000, residuals+i,lastHdd, lastbd, currentIdepth);
		residuals[i].state_state = residuals[i].state_NewState;
		residuals[i].state_energy = residuals[i].state_NewEnergy;
	}

	if(!std::isfinite(lastEnergy) || lastHdd < setting_minIdepthH_act)
	{
		if(print)
			printf("OptPoint: Not well-constrained (%d res, H=%.1f). E=%f. SKIP!\n",
				nres, lastHdd, lastEnergy);
		return 0;
	}

	if(print) printf("Activate point. %d residuals. H=%f. Initial Energy: %f. Initial Id=%f\n" ,
			nres, lastHdd,lastEnergy,currentIdepth);

	float lambda = 0.1;
	for(int iteration=0;iteration<setting_GNItsOnPointActivation;iteration++)
	{
		float H = lastHdd;
		H *= 1+lambda;
		float step = (1.0/H) * lastbd;
		float newIdepth = currentIdepth - step;

		float newHdd=0; float newbd=0; float newEnergy=0;
		for(int i=0;i<nres;i++)
			newEnergy += point->linearizeResidual(&Hcalib, 1, residuals+i,newHdd, newbd, newIdepth);

		if(!std::isfinite(lastEnergy) || newHdd < setting_minIdepthH_act)
		{
			if(print) printf("OptPoint: Not well-constrained (%d res, H=%.1f). E=%f. SKIP!\n",
					nres,
					newHdd,
					lastEnergy);
			return 0;
		}

		if(print) printf("%s %d (L %.2f) %s: %f -> %f (idepth %f)!\n",
				(true || newEnergy < lastEnergy) ? "ACCEPT" : "REJECT",
				iteration,
				log10(lambda),
				"",
				lastEnergy, newEnergy, newIdepth);

		if(newEnergy < lastEnergy)
		{
			currentIdepth = newIdepth;
			lastHdd = newHdd;
			lastbd = newbd;
			lastEnergy = newEnergy;
			for(int i=0;i<nres;i++)
			{
				residuals[i].state_state = residuals[i].state_NewState;
				residuals[i].state_energy = residuals[i].state_NewEnergy;
			}

			lambda *= 0.5;
		}
		else
		{
			lambda *= 5;
		}

		if(fabsf(step) < 0.0001*currentIdepth)
			break;
	}

	if(!std::isfinite(currentIdepth))
	{
		printf("MAJOR ERROR! point idepth is nan after initialization (%f).\n", currentIdepth);
		return (PointHessian*)((long)(-1));		// yeah I'm like 99% sure this is OK on 32bit systems.
	}

	int numGoodRes=0;
	for(int i=0;i<nres;i++)
		if(residuals[i].state_state == ResState::IN) numGoodRes++;

	if(numGoodRes < minObs)
	{
		if(print) printf("OptPoint: OUTLIER!\n");
		return (PointHessian*)((long)(-1));		// yeah I'm like 99% sure this is OK on 32bit systems.
	}

	PointHessian* p = new PointHessian(point, &Hcalib);
	if(!std::isfinite(p->energyTH)) {delete p; return (PointHessian*)((long)(-1));}

	p->lastResiduals[0].first = 0;
	p->lastResiduals[0].second = ResState::OOB;
	p->lastResiduals[1].first = 0;
	p->lastResiduals[1].second = ResState::OOB;
	p->setIdepthZero(currentIdepth);
	p->setIdepth(currentIdepth);
	p->setPointStatus(PointHessian::ACTIVE);

	for(int i=0;i<nres;i++)
		if(residuals[i].state_state == ResState::IN)
		{
			PointFrameResidual* r = new PointFrameResidual(p, p->host, residuals[i].target);
			r->state_NewEnergy = r->state_energy = 0;
			r->state_NewState = ResState::OUTLIER;
			r->setState(ResState::IN);
			p->residuals.push_back(r);

			if(r->target == frameHessians.back())
			{
				p->lastResiduals[0].first = r;
				p->lastResiduals[0].second = ResState::IN;
			}
			else if(r->target == (frameHessians.size()<2 ? 0 : frameHessians[frameHessians.size()-2]))
			{
				p->lastResiduals[1].first = r;
				p->lastResiduals[1].second = ResState::IN;
			}
		}

	if(print) printf("point activated!\n");

	statistics_numActivatedPoints++;
	return p;
}

}


// Copyright Nick Thompson, 2021
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_INTERPOLATORS_BEZIER_POLYNOMIAL_HPP
#define BOOST_MATH_INTERPOLATORS_BEZIER_POLYNOMIAL_HPP
#include <memory>
#include <boost/math/interpolators/detail/bezier_polynomial_detail.hpp>

#ifdef BOOST_MATH_NO_THREAD_LOCAL_WITH_NON_TRIVIAL_TYPES
#warning "Thread local storage support is necessary for the Bezier polynomial class to work."
#endif

namespace boost::math::interpolators {

template <class RandomAccessContainer>
class bezier_polynomial
{
public:
    using Point = typename RandomAccessContainer::value_type;
    using Real = typename Point::value_type;
    using Z = typename RandomAccessContainer::size_type;

    bezier_polynomial(RandomAccessContainer && control_points)
    : m_imp(std::make_shared<detail::bezier_polynomial_imp<RandomAccessContainer>>(std::move(control_points)))
    {
    }

    inline Point operator()(Real t) const
    {
        return (*m_imp)(t);
    }

    inline Point prime(Real t) const
    {
        return m_imp->prime(t);
    }

    void edit_control_point(Point const & p, Z index)
    {
        m_imp->edit_control_point(p, index);
    }

    RandomAccessContainer const & control_points() const
    {
        return m_imp->control_points();
    }

    friend std::ostream& operator<<(std::ostream& out, bezier_polynomial<RandomAccessContainer> const & bp) {
        out << *bp.m_imp;
        return out;
    }

private:
    std::shared_ptr<detail::bezier_polynomial_imp<RandomAccessContainer>> m_imp;
};

}
#endif


//==================================================================================================
/*!
  @file

  @copyright 2015 NumScale SAS
  @copyright 2015 J.T. Lapreste

  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_GENERIC_FUNCTION_BITGET_HPP_INCLUDED
#define BOOST_SIMD_ARCH_COMMON_GENERIC_FUNCTION_BITGET_HPP_INCLUDED

#include <boost/simd/meta/cardinal_of.hpp>
#include <boost/simd/detail/assert_utils.hpp>
#include <boost/simd/function/bitwise_cast.hpp>
#include <boost/simd/function/dec.hpp>
#include <boost/simd/function/minus.hpp>
#include <boost/simd/function/shift_left.hpp>
#include <boost/simd/function/shift_right.hpp>
#include <boost/simd/function/splat.hpp>
#include <boost/dispatch/function/overload.hpp>
#include <boost/dispatch/meta/as_integer.hpp>
#include <boost/dispatch/meta/scalar_of.hpp>
#include <boost/config.hpp>

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

  BOOST_DISPATCH_OVERLOAD ( bitget_
                          , (typename A0, typename A1)
                          , bd::cpu_
                          , bd::generic_< bd::arithmetic_<A0> >
                          , bd::generic_< bd::integer_<A1> >
                          )
  {
    using result_t = bd::as_integer_t<A0, unsigned>;

    static_assert
      ( bs::cardinal_of<A0>::value == bs::cardinal_of<A1>::value
      , "boost.simd cardinalities are inconsistent in biget call"
      );

    BOOST_FORCEINLINE result_t operator() ( A0 const& a0, A1 const& a1) const BOOST_NOEXCEPT
    {
      using sA0 = bd::scalar_of_t<A0>;
      A1 c = splat<A1>(sizeof(sA0)*CHAR_BIT);
      BOOST_ASSERT_MSG(assert_good_shift<A0>(c-a1)&&assert_good_shift<A0>(dec(c))
                      , "bitget :index is out of range");

      return shift_right(shift_left(bitwise_cast<result_t>(a0), c-a1), dec(c));
    }
  };

  BOOST_DISPATCH_OVERLOAD ( bitget_
                          , (typename A0, typename A1)
                          , bd::cpu_
                          , bd::generic_< bd::arithmetic_<A0> >
                          , bd::scalar_< bd::integer_<A1> >
                          )
  {
    using result_t =  bd::as_integer_t<A0, unsigned>;

    BOOST_FORCEINLINE result_t operator() ( A0 const& a0, A1 const& a1) const BOOST_NOEXCEPT
    {
      using sA0 = bd::scalar_of_t<A0>;
      A1 c = sizeof(sA0)*CHAR_BIT;
      BOOST_ASSERT_MSG(assert_good_shift<A0>(c-a1)&&assert_good_shift<A0>(dec(c))
                      , "bitget :index is out of range");
      return shift_right(shift_left(bitwise_cast<result_t>(a0), c-a1), dec(c));
    }
  };
} } }

#endif


//==================================================================================================
/*!
  @file

  @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_SIMD_FUNCTION_SINH_HPP_INCLUDED
#define BOOST_SIMD_ARCH_COMMON_SIMD_FUNCTION_SINH_HPP_INCLUDED

#include <boost/simd/detail/overload.hpp>
#include <boost/simd/arch/common/detail/generic/sinh_kernel.hpp>
#include <boost/simd/meta/as_logical.hpp>
#include <boost/simd/constant/half.hpp>
#include <boost/simd/constant/log_2.hpp>
#include <boost/simd/detail/constant/maxlog.hpp>
#include <boost/simd/constant/one.hpp>
#include <boost/simd/constant/zero.hpp>
#include <boost/simd/function/abs.hpp>
#include <boost/simd/function/bitofsign.hpp>
#include <boost/simd/function/bitwise_xor.hpp>
#include <boost/simd/function/exp.hpp>
#include <boost/simd/function/if_else.hpp>
#include <boost/simd/function/nbtrue.hpp>
#include <boost/simd/function/is_greater.hpp>
#include <boost/simd/function/is_less.hpp>
#include <boost/simd/function/minus.hpp>
#include <boost/simd/function/multiplies.hpp>
#include <boost/simd/function/rec.hpp>
#include <boost/simd/function/sqr.hpp>

namespace boost { namespace simd { namespace ext
{
   namespace bd = boost::dispatch;
   namespace bs = boost::simd;
   BOOST_DISPATCH_OVERLOAD_IF( sinh_
                          , (typename A0, typename X)
                          , (detail::is_native<X>)
                          , bd::cpu_
                          , bs::pack_<bd::floating_<A0>, X>
                          )
   {
      BOOST_FORCEINLINE A0 operator()( const A0& a0) const BOOST_NOEXCEPT
      {
        A0 x = bs::abs(a0);
        auto lt1= is_less(x, One<A0>());
        A0 bts = bitofsign(a0);
        std::size_t nb = nbtrue(lt1);
        A0 z = Zero<A0>();
        if(nb > 0)
        {
          A0 x2 = sqr(x);
          z = detail::sinh_kernel<A0>::compute(x, x2);
          if(nb >= A0::static_size) return bitwise_xor(z, bts);
        }
        auto test1 = is_greater(x, Maxlog<A0>()-Log_2<A0>());
        A0 fac = if_else(test1, Half<A0>(), One<A0>());
        A0 tmp = exp(x*fac);
        A0 tmp1 = Half<A0>()*tmp;
        A0 r =  if_else(test1, tmp1*tmp, tmp1-Half<A0>()*rec(tmp));
        return bitwise_xor(if_else(lt1, z, r), bts);
      }
   };

} } }

#endif


//==================================================================================================
/*!
  @file

  @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_DIVTRUNC_HPP_INCLUDED
#define BOOST_SIMD_ARCH_COMMON_SCALAR_FUNCTION_DIVTRUNC_HPP_INCLUDED

#include <boost/simd/function/definition/trunc.hpp>
#include <boost/simd/constant/valmax.hpp>
#include <boost/simd/constant/valmin.hpp>
#include <boost/simd/constant/zero.hpp>
#include <boost/simd/function/trunc.hpp>
#include <boost/simd/detail/dispatch/function/overload.hpp>
#include <boost/config.hpp>

namespace boost { namespace simd { namespace ext
{
  namespace bd = boost::dispatch;
  BOOST_DISPATCH_OVERLOAD ( div_
                          , (typename A0)
                          , bd::cpu_
                          , bs::tag::trunc_
                          , bd::scalar_< bd::signed_<A0> >
                          , bd::scalar_< bd::signed_<A0> >
                          )
  {
    BOOST_FORCEINLINE A0 operator() ( bd::functor<bs::tag::trunc_> const&
                                    , A0 a0, A0 a1) const BOOST_NOEXCEPT
    {
      if (!a0) return  Zero<A0>();
      if(a1)
      {
        return a0/a1;
      }
      else
        return ((a0>0) ? Valmax<A0>() : Valmin<A0>());

    }
  };

  BOOST_DISPATCH_OVERLOAD ( div_
                          , (typename A0)
                          , bd::cpu_
                          , bs::tag::trunc_
                          , bd::scalar_< bd::unsigned_<A0> >
                          , bd::scalar_< bd::unsigned_<A0> >
                          )
  {
    BOOST_FORCEINLINE A0 operator() ( bd::functor<bs::tag::trunc_> const&
                                    , A0 a0, A0 a1) const BOOST_NOEXCEPT
    {
      if (!a0) return  Zero<A0>();
      if(a1)
      {
        return a0/a1;
      }
      else
        return Valmax<A0>();

    }
  };

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

  BOOST_DISPATCH_OVERLOAD ( div_
                          , (typename A0)
                          , bd::cpu_
                          , bs::tag::trunc_
                          , bd::scalar_< bd::floating_<A0> >
                          , bd::scalar_< bd::floating_<A0> >
                          )
  {
    BOOST_FORCEINLINE A0 operator() ( bd::functor<bs::tag::trunc_> const&
                                    , A0 a0, A0 a1) const BOOST_NOEXCEPT
    {
      return trunc(a0/a1);
    }
  };

#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

} } }

#endif


// Test for boost/core/bit.hpp (bit_cast)
//
// Copyright 2020 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

#include <boost/core/bit.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/cstdint.hpp>
#include <cstring>

int main()
{
    {
        float x = 0.89f;
        boost::uint32_t y = boost::core::bit_cast<boost::uint32_t>( x );

        BOOST_TEST( std::memcmp( &x, &y, sizeof(x) ) == 0 );
    }

    {
        double x = 0.89;
        boost::uint64_t y = boost::core::bit_cast<boost::uint64_t>( x );

        BOOST_TEST( std::memcmp( &x, &y, sizeof(x) ) == 0 );
    }

    return boost::report_errors();
}


/*******************************************************************************
 *         Copyright 2003 & onward LASMEA UMR 6602 CNRS/Univ. Clermont II
 *         Copyright 2009 & onward LRI    UMR 8623 CNRS/Univ Paris Sud XI
 *
 *          Distributed under the Boost Software License, Version 0x01.0.
 *                 See accompanying file LICENSE.txt or copy at
 *                     http://www.boost.org/LICENSE_1_0.txt
 ******************************************************************************/
#define NT2_UNIT_MODULE "boost::simd::value"

#include <boost/mpl/integral_c.hpp>
#include <boost/simd/include/functions/value.hpp>
#include <boost/simd/sdk/config/types.hpp>
#include <boost/simd/sdk/config/type_lists.hpp>
#include <boost/simd/sdk/simd/logical.hpp>

#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/unit/tests/relation.hpp>
#include <nt2/sdk/unit/tests/type_expr.hpp>

NT2_TEST_CASE_TPL(scalar, BOOST_SIMD_TYPES)
{
  using boost::simd::value;
  using boost::simd::tag::value_;

  NT2_TEST_TYPE_IS( typename boost::dispatch::meta::call<value_(T&)>::type, T&);
  NT2_TEST_TYPE_IS( typename boost::dispatch::meta::call<value_(T const&)>::type, T const&);
  NT2_TEST_EQUAL(value(T(42)), T(42));
}

NT2_TEST_CASE_TPL(pointer, BOOST_SIMD_TYPES)
{
  using boost::simd::value;
  using boost::simd::tag::value_;

  NT2_TEST_TYPE_IS( typename boost::dispatch::meta::call<value_(T*&)>::type
                  , T*&
                  );

  NT2_TEST_TYPE_IS( typename boost::dispatch::meta::call<value_(T* const&)>::type
                  , T* const&
                  );

  T v = 42;
  NT2_TEST_EQUAL(value(&v), &v);
}

NT2_TEST_CASE_TPL(logical, BOOST_SIMD_TYPES)
{
  using boost::simd::value;
  using boost::simd::logical;
  using boost::simd::tag::value_;

  NT2_TEST_TYPE_IS( typename boost::dispatch::meta
                    ::call<value_(logical<T> const&)>::type
                  , bool
                  );

  NT2_TEST_TYPE_IS( typename boost::dispatch::meta
                    ::call<value_(logical<T>&)>::type
                  , bool
                  );

  NT2_TEST_EQUAL(value(logical<T>(true)), true);
}

NT2_TEST_CASE_TPL(mpl_int, BOOST_SIMD_INTEGRAL_TYPES)
{
  using boost::simd::value;
  using boost::mpl::integral_c;
  using boost::simd::tag::value_;

  NT2_TEST_TYPE_IS( typename boost::dispatch::meta
                    ::call<value_(integral_c<T,42> const&)>::type
                  , T
                  );

  NT2_TEST_TYPE_IS( typename boost::dispatch::meta
                    ::call<value_(integral_c<T,42>&)>::type
                  , T
                  );

  NT2_TEST_EQUAL(value(integral_c<T,42>()), T(42));
}


//==================================================================================================
/**

  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_SIMD_FUNCTION_UNARY_MINUS_HPP_INCLUDED
#define BOOST_SIMD_ARCH_COMMON_SIMD_FUNCTION_UNARY_MINUS_HPP_INCLUDED

#include <boost/simd/detail/overload.hpp>
#include <boost/simd/detail/traits.hpp>
#include <boost/simd/constant/valmax.hpp>
#include <boost/simd/constant/valmin.hpp>
#include <boost/simd/function/bitwise_xor.hpp>
#include <boost/simd/function/minus.hpp>
#include <boost/simd/constant/mzero.hpp>
#include <boost/simd/constant/zero.hpp>

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

  BOOST_DISPATCH_OVERLOAD_IF( unary_minus_
                            , (typename A0,typename X)
                            , (detail::is_native<X>)
                            , bd::cpu_
                            , bs::pack_<bd::arithmetic_<A0>,X>
                            )
  {
    BOOST_FORCEINLINE A0 operator()(const A0& a0) const BOOST_NOEXCEPT
    {
      return bs::Zero<A0>() - a0;
    }
  };

  BOOST_DISPATCH_OVERLOAD_IF( unary_minus_
                            , (typename A0,typename X)
                            , (detail::is_native<X>)
                            , bd::cpu_
                            , bs::pack_<bd::floating_<A0>,X>
                            )
  {
    BOOST_FORCEINLINE A0 operator()(const A0& a0) const BOOST_NOEXCEPT
    {
      return bitwise_xor(bs::Mzero<A0>(),a0);
    }
  };

} } }

#endif


/**
 * Copyright 2022 Scott Brauer
 *
 * 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  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.
 */

/**
 * @file   Types.hpp
 * @author Scott Brauer
 * @date   03-15-2022
 */

#ifndef OFFCENTER_COMMON_TYPES_HPP_
#define OFFCENTER_COMMON_TYPES_HPP_

namespace offcenter {
namespace common {

#include <boost/multiprecision/mpfr.hpp>

using MPF = boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<0> >;
using MPF_7 = boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<7> >;
using MPF_10 = boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<10> >;
using MPF_20 = boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<20> >;

} /* namespace common */
} /* namespace offcenter */

#endif /* OFFCENTER_COMMON_TYPES_HPP_ */


#ifndef YASMIC_GRAPH_IFSTREAM_MATRIX
#define YASMIC_GRAPH_IFSTREAM_MATRIX

#include <fstream>
#include <boost/tuple/tuple.hpp>
#include <iterator>
#include <string>
#include <sstream>
#include <boost/iterator/iterator_facade.hpp>

#include <yasmic/generic_matrix_operations.hpp>

namespace yasmic
{
	namespace impl
	{
		template <class i_index_type, class i_value_type>
		class graph_ifstream_matrix_const_iterator
		: public boost::iterator_facade<
            graph_ifstream_matrix_const_iterator<i_index_type, i_value_type>,
            boost::tuple<
                i_index_type, i_index_type, i_value_type> const,
            boost::forward_traversal_tag,
            boost::tuple<
                i_index_type, i_index_type, i_value_type> const >
        {
        public:
            graph_ifstream_matrix_const_iterator()
				: _str(0), _r(0), _c(0), _line(0)
			{}

            graph_ifstream_matrix_const_iterator(std::ifstream &str, std::istringstream &line)
				: _str(&str), _r(0), _c(0), _line(&line), _start(true)
            {
				std::string curline;
				getline( *(_str), curline );

                // set the fail bit so that that increment will
                // discard this line immediately...
                _line->setstate(std::ios_base::failbit);

				increment();
			}

        private:
            friend class boost::iterator_core_access;

            void increment()
            {
				if (_str != 0)
				{
                    // graph uses 1 indexed columns
                    *(_line) >> _c;
                    --_c;

					while (_line->fail())
					{
						// I don't like the early return here, but
						// I don't know what to do about it...
						if (_str->eof()) { _str = 0; return; }

						std::string curline;
						getline( *(_str), curline );
						_line->clear();
						_line->str(curline);

                        if (!_start)
                        {
    						++_r;
                        }
                        else
                        {
                            _start = false;
                        }

                        *(_line) >> _c;
                        --_c;
					}
				}
            }

            bool equal(graph_ifstream_matrix_const_iterator const& other) const
            {
				return (_str == other._str);
            }

            boost::tuple<
                i_index_type, i_index_type, i_value_type>
            dereference() const
            {
            	return boost::make_tuple(_r, _c, 1);
            }

			i_index_type _r, _c;

            bool _start;

			std::istringstream* _line;

			std::ifstream* _str;
        };

	}

	template <class index_type = int, class value_type = double, class size_type = unsigned int>
	struct graph_ifstream_matrix
	{
		std::ifstream& _f;
		std::istringstream _line;

		graph_ifstream_matrix(std::ifstream& f)
			: _f(f)
		{
        }
	};

	template <class i_index_type, class i_value_type, class i_size_type>
    struct smatrix_traits<graph_ifstream_matrix<i_index_type, i_value_type, i_size_type> >
    {
    	typedef i_size_type size_type;
    	typedef i_index_type index_type;
		typedef i_value_type value_type;

		typedef boost::tuple<index_type, index_type, value_type> nonzero_descriptor;

		typedef impl::graph_ifstream_matrix_const_iterator<i_index_type, i_value_type> nonzero_iterator;

		typedef size_type nz_index_type;

		typedef void row_iterator;

		typedef void row_nonzero_descriptor;
		typedef void row_nonzero_iterator;

		typedef void column_iterator;
    };

	template <class i_index_type, class i_value_type, class i_size_type>
    inline std::pair<typename smatrix_traits<graph_ifstream_matrix<i_index_type, i_value_type, i_size_type> >::size_type,
                     typename smatrix_traits<graph_ifstream_matrix<i_index_type, i_value_type, i_size_type> >::size_type >
    dimensions(graph_ifstream_matrix<i_index_type, i_value_type, i_size_type>& m)
    {
		typedef smatrix_traits<graph_ifstream_matrix<i_index_type, i_value_type, i_size_type> > traits;
    	typename traits::size_type nrows,ncols;

    	m._f.clear();
    	m._f.seekg(0, std::ios_base::beg);

        m._f >> nrows;
        ncols = nrows;

        return (std::make_pair(nrows, ncols));
    }

	template <class i_index_type, class i_value_type, class i_size_type>
	typename smatrix_traits<graph_ifstream_matrix<i_index_type, i_value_type, i_size_type> >::size_type
	nnz(graph_ifstream_matrix<i_index_type, i_value_type, i_size_type>& m)
	{
		typedef smatrix_traits<graph_ifstream_matrix<i_index_type, i_value_type, i_size_type> > traits;
    	typename traits::index_type d1;
        typename traits::size_type nnz;

        typedef typename traits::size_type size_type;

		// clear any error bits
		m._f.clear();
		m._f.seekg(0, std::ios_base::beg);

        m._f >> d1 >> nnz;
        return (2*nnz);
	}

	template <class i_index_type, class i_value_type, class i_size_type>
	std::pair<typename smatrix_traits<graph_ifstream_matrix<i_index_type, i_value_type, i_size_type> >::nonzero_iterator,
              typename smatrix_traits<graph_ifstream_matrix<i_index_type, i_value_type, i_size_type> >::nonzero_iterator>
    nonzeros(graph_ifstream_matrix<i_index_type, i_value_type, i_size_type>& m)
    {
    	typedef smatrix_traits<graph_ifstream_matrix<i_index_type, i_value_type, i_size_type> > traits;
    	//typename traits::size_type ncols;

    	m._f.clear();
		m._f.seekg(0, std::ios_base::beg);

        typedef typename traits::nonzero_iterator nz_iter;

        return (std::make_pair(nz_iter(m._f, m._line), nz_iter()));

    }
}

#endif //YASMIC_GRAPH_IFSTREAM_MATRIX


#include <pybind11/pybind11.h>
#include <pybind11/eigen.h>
#include <pybind11/stl.h>

#include <Eigen/Dense>

#include <kontiki/trajectories/split_trajectory.h>
#include <kontiki/trajectories/uniform_r3_spline_trajectory.h>
#include <kontiki/trajectories/uniform_so3_spline_trajectory.h>
#include "trajectory_helper.h"

namespace py = pybind11;
using namespace pybind11::literals;

namespace TT = kontiki::trajectories;

static constexpr int python_index_to_linear(int i, int N) {
  if ((i >= N) || (i < -N)) {
    throw py::index_error("Invalid sequence index");
  }
  else if ( i < 0 )
    return i + N;
  else
    return i;
}

PYBIND11_MODULE(_split_trajectory, m) {
  m.doc() = "Split R3+SO3 trajectory";

  using Class = TT::SplitTrajectory;
  auto cls = py::class_<Class, std::shared_ptr<Class>>(m, "SplitTrajectory");

  cls.doc() = R"pbdoc(
  Split interpolation trajectory

  This trajectory is implemented using two splines: one in R3 and one in SO3.
  )pbdoc";

  cls.def(py::init<>());
  cls.def(py::init<std::shared_ptr<TT::UniformR3SplineTrajectory>,
                   std::shared_ptr<TT::UniformSO3SplineTrajectory>>());
  cls.def(py::init<double, double>());
  cls.def(py::init<double, double, double, double>(),
  "r3_dt"_a=1, "so3_dt"_a=1, "r3_t0"_a=0, "so3_t0"_a=0, "Create new trajectory");

  cls.def_property_readonly("R3_spline", &Class::R3Spline,
                            "The :class:`.UniformR3SplineTrajectory` instance");
  cls.def_property_readonly("SO3_spline", &Class::SO3Spline,
                            "The :class:`.UniformSO3SplineTrajectory` instance");

  // Common trajectory methods/properties/...
  declare_trajectory_common<Class>(cls);

} // PYBIND11_MODULE


#include "Day10-KnotHash.h"

#include "KnotHasher.h"

#include <AdventOfCodeCommon/DisableLibraryWarningsMacros.h>

__BEGIN_LIBRARIES_DISABLE_WARNINGS
#include <boost/algorithm/string.hpp>

#include <array>
__END_LIBRARIES_DISABLE_WARNINGS

namespace
{

std::array<unsigned char, 5> EXTRA_SALT_BYTES = {17, 31, 73, 47, 23};

}

namespace AdventOfCode
{
namespace Year2017
{
namespace Day10
{

unsigned firstTwoMultipliedAfterKnotting(size_t listSize, const std::vector<unsigned>& lengths)
{
    std::vector<unsigned char> bytesToHash;
    bytesToHash.reserve(lengths.size());

    // Lengths are taken directly from the input, so we need to validate the numbers
    std::transform(lengths.cbegin(), lengths.cend(), std::back_inserter(bytesToHash), [](unsigned lengthElem)
                   {
                       if (lengthElem > 255)
                       {
                           throw std::runtime_error("An input is larger than 255.");
                       }

                       return static_cast<unsigned char>(lengthElem);
                   });

    // We are only interested in the first round of the hashing, so the block size is actually irrelevant as long as it's valid
    // Let's use 1 as the block size as that can divide any number of elements, therefore always valid
    KnotHasher knotHasher{bytesToHash, listSize, 1};
    knotHasher.executeHashRound();
    return knotHasher.firstTwoMultiplied();
}

std::string knotHashDenseString(const std::string& stringToHash)
{
    auto stringToHashTrimmed(stringToHash);
    boost::trim(stringToHashTrimmed);

    std::vector<unsigned char> bytesToHash;
    bytesToHash.reserve(stringToHashTrimmed.size());

    // Each character is converted to a byte
    std::transform(stringToHashTrimmed.cbegin(), stringToHashTrimmed.cend(), std::back_inserter(bytesToHash), [](char c) noexcept
                   {
                       return static_cast<unsigned char>(c);
                   });

    // Add the extra bytes defined in the puzzle
    bytesToHash.insert(bytesToHash.end(), EXTRA_SALT_BYTES.cbegin(), EXTRA_SALT_BYTES.cend());

    KnotHasher knotHasher{bytesToHash};
    return knotHasher.denseHashStringAfterMultipleRounds();
}

}
}
}


/*
 * Storyboard operator logic gate file
 *
 * This file is part of the "SoftPixel Engine" (Copyright (c) 2008 by Lukas Hermanns)
 * See "SoftPixelEngine.hpp" for license information.
 */

#include "Framework/Tools/spStoryboardLogicGate.hpp"

#ifdef SP_COMPILE_WITH_STORYBOARD

#include <boost/foreach.hpp>

#if 1//!!!
#   include "Base/spInputOutputLog.hpp"
#endif

namespace sp
{
namespace tool
{

LogicGate::LogicGate(const ELogicGates Type) :
    Trigger (       ),
    Type_   (Type   )
{
    trigger();
}
LogicGate::~LogicGate()
{
}

//bool LogicGate::triggeredParents() const
bool LogicGate::active() const
{
    s32 Count = 0;

    switch (Type_)
    {
        case LOGICGATE_AND:
            foreach (Trigger* Parent, getParentList())
            {
                if (!Parent->active())
                    return false;
            }
            return true;

        case LOGICGATE_NAND:
            foreach (Trigger* Parent, getParentList())
            {
                if (!Parent->active())
                    return true;
            }
            return false;

        case LOGICGATE_OR:
            foreach (Trigger* Parent, getParentList())
            {
                if (Parent->active())
                    return true;
            }
            return false;

        case LOGICGATE_NOR:
            foreach (Trigger* Parent, getParentList())
            {
                if (Parent->active())
                    return false;
            }
            return true;

        case LOGICGATE_XOR:
            foreach (Trigger* Parent, getParentList())
            {
                if (Parent->active())
                    ++Count;
            }
            return Count % 2 == 1;

        case LOGICGATE_XNOR:
            foreach (Trigger* Parent, getParentList())
            {
                if (Parent->active())
                    ++Count;
            }
            return Count % 2 == 0;
    }

    return false;
}

bool LogicGate::needLoopUpdate() const
{
    return false;
}

} // /namespace tool

} // /namespace sp

#endif

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


#include "testsuite.h"
#include <blitz/array.h>

BZ_USING_NAMESPACE(blitz)

int main()
{
    // NEEDS_WORK: resize

    // One-dimensional resizeAndPreserve
    Array<int,1> A(5);
    A = 0, 1, 2, 3, 4;
    A.resizeAndPreserve(10);
    A(Range(5,toEnd)) = 0;

    BZTEST(A.lbound(0) == 0);
    BZTEST(A.ubound(0) == 9);

    Array<int,1> B(5);
    B = 0, 1, 2, 3, 4;

    BZTEST(all(A(Range(0,4)) == B));
    BZTEST(all(A(Range(5,9)) == 0));

    A.resizeAndPreserve(5);
    BZTEST(all(A == B));
    A.resizeAndPreserve(2);
    BZTEST((A(0) == 0) && (A(1) == 1));
    BZTEST(A.lbound(0) == 0);
    BZTEST(A.ubound(0) == 1);

    // Two-dimensional resizeAndPreserve, with Fortran-style arrays
    Array<int,2> C(3,3,FortranArray<2>());
    C = 0, 1, 2,
        3, 4, 5,
        6, 7, 8;
    C.resizeAndPreserve(2,4);
    // valgrind here correctly complains about use of uninitialized
    // values, because the (i,4) elements are uninitialized. harmless.
    BZTEST(all(C(Range(1,2),Range(1,4)) == C(Range(1,2),Range(1,4))));
    BZTEST(C.lbound(0) == 1);
    BZTEST(C.lbound(1) == 1);
    BZTEST(C.ubound(0) == 2);
    BZTEST(C.ubound(1) == 4);

    // Three dimensional resize
    Array<int,3> G(4,5,6);
    G.resize(7,8,9);
    BZTEST(G.extent(0) == 7);
    BZTEST(G.extent(1) == 8);
    BZTEST(G.extent(2) == 9);
    return 0;
}


//==============================================================================
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   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
//==============================================================================
#include <nt2/arithmetic/include/functions/two_split.hpp>
#include <boost/simd/sdk/simd/native.hpp>
#include <boost/simd/sdk/simd/io.hpp>
#include <nt2/include/constants/eps.hpp>
#include <nt2/include/constants/one.hpp>
#include <nt2/include/functions/unary_minus.hpp>
#include <boost/dispatch/functor/meta/call.hpp>
#include <boost/dispatch/meta/as_integer.hpp>
#include <boost/fusion/include/vector_tie.hpp>

#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/unit/tests/relation.hpp>
#include <nt2/sdk/unit/tests/type_expr.hpp>

NT2_TEST_CASE_TPL( two_split, NT2_SIMD_REAL_TYPES)
{
  using nt2::two_split;
  using boost::simd::native;
  using nt2::tag::two_split_;

  typedef native<T,BOOST_SIMD_DEFAULT_EXTENSION> vT;

  NT2_TEST_TYPE_IS( (typename boost::dispatch::meta::call<two_split_(vT)>::type)
                  , (std::pair<vT,vT>)
                  );

  vT eps_ = nt2::Eps<vT>();
  vT one_ = nt2::One<vT>();

  {
    vT f,s;

    two_split(one_-eps_, f, s);
    NT2_TEST_EQUAL(f, one_);
    NT2_TEST_EQUAL(s, -eps_);
  }

  {
    vT f,s;

    f = two_split(one_-eps_, s);
    NT2_TEST_EQUAL(f, one_);
    NT2_TEST_EQUAL(s, -eps_);
  }

  {
    vT f,s;

    boost::fusion::vector_tie(f,s) = two_split(one_-eps_);
    NT2_TEST_EQUAL(f, one_);
    NT2_TEST_EQUAL(s, -eps_);
  }

  {
    std::pair<vT,vT> p;

    p = two_split(one_-eps_);
    NT2_TEST_EQUAL(p.first, one_);
    NT2_TEST_EQUAL(p.second, -eps_);
  }
}


#include <iostream>
#include <boost/coroutine2/coroutine.hpp>

using coro_t = boost::coroutines2::coroutine<int>;

coro_t::pull_type Fibonacci(const int n) {
    return typename coro_t::pull_type([n](typename coro_t::push_type& yield){
        int x = 0u;
        for (int i=x, next=1; i<=n; ++i) {
            yield(x);
            auto prev = x;
            x = next;
            next += prev;
        }
    });
}

int main() {
    for (const auto x: Fibonacci(20u)) {
        std::cout << x << " ";
    }
    std::cout << "\n";
    return 0;
}


/*
 * VectorAverage.hpp
 *
 *  Created on: Sep 25, 2014
 *      Author: Péter Fankhauser
 *   Institute: ETH Zurich, Autonomous Systems Lab
 *
 */

#pragma once

// Eigen
#include <Eigen/Core>

// STD
#include <iostream>

namespace foothold_finder {

class VectorAverage
{
 public:
  VectorAverage();
  virtual ~VectorAverage();

  void add(const Eigen::Vector3d& vector);

  const Eigen::Vector3d& getAverage() const;

  void clear();

  friend std::ostream& operator <<(std::ostream& ostream, const VectorAverage& vectorAverage);

 private:

  //! Number of samples.
  unsigned int nSamples_;

  //! Average vector.
  Eigen::Vector3d average_;
};

} /* namespace foothold_finder */


#define BOOST_TEST_MODULE shperical data
#define BOOST_TEST_DYN_LINK
#include <cmath>
#include <random>
#include <vector>
#include <chrono>
#include <boost/test/unit_test.hpp>
#include <blackpearl/core/sph_data.hpp>

template<typename real_scalar_type>
void test_shp_data(){
    using namespace blackpearl::core;
    std::size_t n_side = 2048;
    std::size_t num_pixels = 12*n_side*n_side;
    std::vector<size_t> spins = {0,0,2,2,2,2};
    shp_data<real_scalar_type> data(num_pixels,spins);
}

BOOST_AUTO_TEST_CASE(shp_data){
    test_shp_data<float>();
    test_shp_data<double>();
}


#include <util/DynamicBloomFilter.h>
#include <util/Int2String.h>

#include <boost/test/unit_test.hpp>
#include <boost/timer.hpp>
#include <boost/thread.hpp>

#include <string>
#include <iostream>

using namespace izenelib::util;
using namespace std;

BOOST_AUTO_TEST_CASE(BloomFilter_test)
{
    BloomFilter<std::string> bloomfiler(10000,0.01);
    for(unsigned i =0; i < 100; ++i)
    {
        std::string key(Int2String(i).x);
        bloomfiler.Insert(key);
    }
    for(unsigned i =0; i < 100; ++i)
    {
        std::string key(Int2String(i).x);
        BOOST_CHECK(bloomfiler.Get(key));
    }
    for(unsigned i =101; i < 200; ++i)
    {
        std::string key(Int2String(i).x);
        BOOST_CHECK(!bloomfiler.Get(key));
    }
}
typedef BloomFilter<std::string> BloomFilterType;
MAKE_FEBIRD_SERIALIZATION(BloomFilterType )

BOOST_AUTO_TEST_CASE(BloomFilter_storage_test)
{
    BloomFilterType bloomfiler(10000,0.01);
    for(unsigned i =0; i < 100; ++i)
    {
        std::string key(Int2String(i).x);
        bloomfiler.Insert(key);
    }

    izene_serialization_febird<BloomFilterType > isb(bloomfiler);
    char* ptr;
    size_t sz;
    isb.write_image(ptr, sz);
    BloomFilterType inFilter;

    izene_deserialization_febird<BloomFilterType > idb(ptr, sz);
    idb.read_image(inFilter);

    for(unsigned i =0; i < 100; ++i)
    {
        std::string key(Int2String(i).x);
        BOOST_CHECK(inFilter.Get(key));
    }
    for(unsigned i =101; i < 200; ++i)
    {
        std::string key(Int2String(i).x);
        BOOST_CHECK(!inFilter.Get(key));
    }
}

BOOST_AUTO_TEST_CASE(DynamicBloomFilter_test)
{
    DynamicBloomFilter<std::string> bloomfiler(10000,0.01,10);
    for(unsigned i =0; i < 100; ++i)
    {
        std::string key(Int2String(i).x);
        bloomfiler.Insert(key);
    }
    for(unsigned i =0; i < 100; ++i)
    {
        std::string key(Int2String(i).x);
        BOOST_CHECK(bloomfiler.Get(key));
    }
    for(unsigned i =101; i < 200; ++i)
    {
        std::string key(Int2String(i).x);
        BOOST_CHECK(!bloomfiler.Get(key));
    }
}

typedef DynamicBloomFilter<std::string> DynamicBloomFilterType;
MAKE_FEBIRD_SERIALIZATION(DynamicBloomFilterType )

BOOST_AUTO_TEST_CASE(DynamicBloomFilter_storage_test)
{
    DynamicBloomFilterType bloomfiler(10000,0.01,10);
    for(unsigned i =0; i < 100; ++i)
    {
        std::string key(Int2String(i).x);
        bloomfiler.Insert(key);
    }

    izene_serialization_febird<DynamicBloomFilterType > isb(bloomfiler);
    char* ptr;
    size_t sz;
    isb.write_image(ptr, sz);
    DynamicBloomFilterType inFilter;

    izene_deserialization_febird<DynamicBloomFilterType > idb(ptr, sz);
    idb.read_image(inFilter);

    for(unsigned i =0; i < 100; ++i)
    {
        std::string key(Int2String(i).x);
        BOOST_CHECK(inFilter.Get(key));
    }
    for(unsigned i =101; i < 200; ++i)
    {
        std::string key(Int2String(i).x);
        BOOST_CHECK(!inFilter.Get(key));
    }
}


#include <blitz/array.h>

BZ_USING_NAMESPACE(blitz)

int main()
{
}

void foo()
{
    const int N = 10;
    Array<float,1> A(N), B(N), C(N), D(N), E(N);
    A = B*C + D*E;
}


/*
 [auto_generated]
 boost/numeric/odeint/stepper/runge_kutta4_classic.hpp

 [begin_description]
 Implementation for the classical Runge Kutta stepper.
 [end_description]

 Copyright 2010-2013 Karsten Ahnert
 Copyright 2010-2013 Mario Mulansky
 Copyright 2012 Christoph Koke

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

#ifndef BOOST_NUMERIC_ODEINT_STEPPER_RUNGE_KUTTA4_CLASSIC_HPP_INCLUDED
#define BOOST_NUMERIC_ODEINT_STEPPER_RUNGE_KUTTA4_CLASSIC_HPP_INCLUDED

#include <boost/numeric/odeint/stepper/base/explicit_stepper_base.hpp>
#include <boost/numeric/odeint/algebra/range_algebra.hpp>
#include <boost/numeric/odeint/algebra/default_operations.hpp>
#include <boost/numeric/odeint/algebra/algebra_dispatcher.hpp>
#include <boost/numeric/odeint/algebra/operations_dispatcher.hpp>

#include <boost/numeric/odeint/util/state_wrapper.hpp>
#include <boost/numeric/odeint/util/is_resizeable.hpp>
#include <boost/numeric/odeint/util/resizer.hpp>

namespace boost {
namespace numeric {
namespace odeint {

template<
class State ,
class Value = double ,
class Deriv = State ,
class Time = Value ,
class Algebra = typename algebra_dispatcher< State >::algebra_type ,
class Operations = typename operations_dispatcher< State >::operations_type ,
class Resizer = initially_resizer
>
#ifndef DOXYGEN_SKIP
class runge_kutta4_classic
: public explicit_stepper_base<
  runge_kutta4_classic< State , Value , Deriv , Time , Algebra , Operations , Resizer > ,
  4 , State , Value , Deriv , Time , Algebra , Operations , Resizer >
#else
class runge_kutta4_classic : public explicit_stepper_base
#endif
{

public :

    #ifndef DOXYGEN_SKIP
    typedef explicit_stepper_base<
    runge_kutta4_classic< State , Value , Deriv , Time , Algebra , Operations , Resizer > ,
    4 , State , Value , Deriv , Time , Algebra , Operations , Resizer > stepper_base_type;
    #else
    typedef explicit_stepper_base< runge_kutta4_classic< ... > , ... > stepper_base_type;
    #endif

    typedef typename stepper_base_type::state_type state_type;
    typedef typename stepper_base_type::value_type value_type;
    typedef typename stepper_base_type::deriv_type deriv_type;
    typedef typename stepper_base_type::time_type time_type;
    typedef typename stepper_base_type::algebra_type algebra_type;
    typedef typename stepper_base_type::operations_type operations_type;
    typedef typename stepper_base_type::resizer_type resizer_type;

    #ifndef DOXYGEN_SKIP
    typedef typename stepper_base_type::stepper_type stepper_type;
    typedef typename stepper_base_type::wrapped_state_type wrapped_state_type;
    typedef typename stepper_base_type::wrapped_deriv_type wrapped_deriv_type;
    #endif // DOXYGEN_SKIP

    runge_kutta4_classic( const algebra_type &algebra = algebra_type() ) : stepper_base_type( algebra )
    { }

    template< class System , class StateIn , class DerivIn , class StateOut >
    void do_step_impl( System system , const StateIn &in , const DerivIn &dxdt , time_type t , StateOut &out , time_type dt )
    {
        // ToDo : check if size of in,dxdt,out are equal?

        static const value_type val1 = static_cast< value_type >( 1 );

        m_resizer.adjust_size( in , detail::bind( &stepper_type::template resize_impl< StateIn > , detail::ref( *this ) , detail::_1 ) );

        typename odeint::unwrap_reference< System >::type &sys = system;

        const time_type dh = dt / static_cast< value_type >( 2 );
        const time_type th = t + dh;

        // dt * dxdt = k1
        // m_x_tmp = x + dh*dxdt
        stepper_base_type::m_algebra.for_each3( m_x_tmp.m_v , in , dxdt ,
                typename operations_type::template scale_sum2< value_type , time_type >( val1 , dh ) );

        // dt * m_dxt = k2
        sys( m_x_tmp.m_v , m_dxt.m_v , th );

        // m_x_tmp = x + dh*m_dxt
        stepper_base_type::m_algebra.for_each3( m_x_tmp.m_v , in , m_dxt.m_v ,
                typename operations_type::template scale_sum2< value_type , time_type >( val1 , dh ) );

        // dt * m_dxm = k3
        sys( m_x_tmp.m_v , m_dxm.m_v , th );
        //m_x_tmp = x + dt*m_dxm
        stepper_base_type::m_algebra.for_each3( m_x_tmp.m_v , in , m_dxm.m_v ,
                typename operations_type::template scale_sum2< value_type , time_type >( val1 , dt ) );

        // dt * m_dxh = k4
        sys( m_x_tmp.m_v , m_dxh.m_v , t + dt );

        //x += dt/6 * ( m_dxdt + m_dxt + val2*m_dxm )
        time_type dt6 = dt / static_cast< value_type >( 6 );
        time_type dt3 = dt / static_cast< value_type >( 3 );
        stepper_base_type::m_algebra.for_each6( out , in , dxdt , m_dxt.m_v , m_dxm.m_v , m_dxh.m_v ,
                                             typename operations_type::template scale_sum5< value_type , time_type , time_type , time_type , time_type >( 1.0 , dt6 , dt3 , dt3 , dt6 ) );

        // x += dt/6 * m_dxdt + dt/3 * m_dxt )
        // stepper_base_type::m_algebra.for_each4( out , in , dxdt , m_dxt.m_v ,
        //                                         typename operations_type::template scale_sum3< value_type , time_type , time_type >( 1.0 , dt6 , dt3 ) );
        // // x += dt/3 * m_dxm + dt/6 * m_dxh )
        // stepper_base_type::m_algebra.for_each4( out , out , m_dxm.m_v , m_dxh.m_v ,
        //                                         typename operations_type::template scale_sum3< value_type , time_type , time_type >( 1.0 , dt3 , dt6 ) );

    }

    template< class StateType >
    void adjust_size( const StateType &x )
    {
        resize_impl( x );
        stepper_base_type::adjust_size( x );
    }

private:

    template< class StateIn >
    bool resize_impl( const StateIn &x )
    {
        bool resized = false;
        resized |= adjust_size_by_resizeability( m_x_tmp , x , typename is_resizeable<state_type>::type() );
        resized |= adjust_size_by_resizeability( m_dxm , x , typename is_resizeable<deriv_type>::type() );
        resized |= adjust_size_by_resizeability( m_dxt , x , typename is_resizeable<deriv_type>::type() );
        resized |= adjust_size_by_resizeability( m_dxh , x , typename is_resizeable<deriv_type>::type() );
        return resized;
    }

    resizer_type m_resizer;

    wrapped_deriv_type m_dxt;
    wrapped_deriv_type m_dxm;
    wrapped_deriv_type m_dxh;
    wrapped_state_type m_x_tmp;

};

/********* DOXYGEN *********/

/**
 * \class runge_kutta4_classic
 * \brief The classical Runge-Kutta stepper of fourth order.
 *
 * The Runge-Kutta method of fourth order is one standard method for
 * solving ordinary differential equations and is widely used, see also
 * en.wikipedia.org/wiki/Runge-Kutta_methods
 * The method is explicit and fulfills the Stepper concept. Step size control
 * or continuous output are not provided.  This class implements the method directly, hence the
 * generic Runge-Kutta algorithm is not used.
 *
 * This class derives from explicit_stepper_base and inherits its interface via
 * CRTP (current recurring template pattern). For more details see
 * explicit_stepper_base.
 *
 * \tparam State The state type.
 * \tparam Value The value type.
 * \tparam Deriv The type representing the time derivative of the state.
 * \tparam Time The time representing the independent variable - the time.
 * \tparam Algebra The algebra type.
 * \tparam Operations The operations type.
 * \tparam Resizer The resizer policy type.
 */

    /**
     * \fn runge_kutta4_classic::runge_kutta4_classic( const algebra_type &algebra )
     * \brief Constructs the runge_kutta4_classic class. This constructor can be used as a default
     * constructor if the algebra has a default constructor.
     * \param algebra A copy of algebra is made and stored inside explicit_stepper_base.
     */

    /**
     * \fn runge_kutta4_classic::do_step_impl( System system , const StateIn &in , const DerivIn &dxdt , time_type t , StateOut &out , time_type dt )
     * \brief This method performs one step. The derivative `dxdt` of `in` at the time `t` is passed to the method.
     * The result is updated out of place, hence the input is in `in` and the output in `out`.
     * Access to this step functionality is provided by explicit_stepper_base and
     * `do_step_impl` should not be called directly.
     *
     * \param system The system function to solve, hence the r.h.s. of the ODE. It must fulfill the
     *               Simple System concept.
     * \param in The state of the ODE which should be solved. in is not modified in this method
     * \param dxdt The derivative of x at t.
     * \param t The value of the time, at which the step should be performed.
     * \param out The result of the step is written in out.
     * \param dt The step size.
     */

    /**
     * \fn runge_kutta4_classic::adjust_size( const StateType &x )
     * \brief Adjust the size of all temporaries in the stepper manually.
     * \param x A state from which the size of the temporaries to be resized is deduced.
     */

} // odeint
} // numeric
} // boost

#endif // BOOST_NUMERIC_ODEINT_STEPPER_RUNGE_KUTTA4_CLASSIC_HPP_INCLUDED