/*    Copyright (c) 2010-2018, Delft University of Technology
 *    All rigths reserved
 *
 *    This file is part of the Tudat. Redistribution and use in source and
 *    binary forms, with or without modification, are permitted exclusively
 *    under the terms of the Modified BSD license. You should have received
 *    a copy of the license with this file. If not, please or visit:
 *    http://tudat.tudelft.nl/LICENSE.
 *
 *    References
 *      Noomen, R., Lambert targeter Excel file.
 *
 */

#define BOOST_TEST_MAIN

#include <limits>

#include <boost/test/unit_test.hpp>

#include <Eigen/Core>

#include "Tudat/Basics/testMacros.h"

#include "Tudat/Astrodynamics/MissionSegments/lambertTargeter.h"

namespace tudat
{
namespace mission_segments
{

// A dummy derived class to test the functionality of the Lambert targeter base class.
class LambertTargeterDummy : public LambertTargeter
{
public:

    // Default constructor.
    LambertTargeterDummy( const Eigen::Vector3d& cartesianPositionAtDeparture,
                          const Eigen::Vector3d& cartesianPositionAtArrival,
                          const double& timeOfFlight,
                          const double& gravitationalParameter )
        : LambertTargeter( cartesianPositionAtDeparture, cartesianPositionAtArrival, timeOfFlight,
                           gravitationalParameter )
    {
        execute( );
    }

protected:

    void execute( )
    {
        // Set inertial velocities.
        cartesianVelocityAtDeparture << 2735.8, 6594.3, 0.0;
        cartesianVelocityAtArrival << -1367.9, 4225.03, 0.0;
    }

};

} // namespace mission_segments

namespace unit_tests
{

//! Test the Izzo Lambert targeting algorithm code.
BOOST_AUTO_TEST_SUITE( test_lambert_targeter )

//! Test the return of the inertial velocities.
BOOST_AUTO_TEST_CASE( testGetInertialVelocity )
{
    // Set tolerance.
    const double tolerance = std::numeric_limits< double >::epsilon( );

    // Set canonical units for Earth (see page 29 [1]).
    const double distanceUnit = 6.378136e6;
    const double timeUnit = 806.78;

    // Set expected inertial vectors.
    const Eigen::Vector3d expectedInertialVelocityAtDeparture( 2735.8, 6594.3, 0.0 ),
            expectedInertialVelocityAtArrival( -1367.9, 4225.03, 0.0 );

    // Time conversions.
    const double testTimeOfFlight = 5.0 * timeUnit;

    // Set central body graviational parameter.
    const double testGravitationalParameter = 398600.4418e9;

    // Set position at departure and arrival.
    const Eigen::Vector3d testCartesianPositionAtDeparture( 2.0 * distanceUnit, 0.0, 0.0 ),
            testCartesianPositionAtArrival( 2.0 * distanceUnit, 2.0 * sqrt( 3.0 ) * distanceUnit,
                                            0.0 );
    // Declare Lambert targeter object.
    mission_segments::LambertTargeterDummy
            testLambertTargeter( testCartesianPositionAtDeparture, testCartesianPositionAtArrival,
                                 testTimeOfFlight, testGravitationalParameter );

    // Check that returned vectors are equal to expected vectors.
    BOOST_CHECK_CLOSE_FRACTION( expectedInertialVelocityAtDeparture.x( ),
                                testLambertTargeter.getInertialVelocityAtDeparture( ).x( ),
                                tolerance );
    BOOST_CHECK_CLOSE_FRACTION( expectedInertialVelocityAtDeparture.y( ),
                                testLambertTargeter.getInertialVelocityAtDeparture( ).y( ),
                                tolerance );
    BOOST_CHECK_SMALL( testLambertTargeter.getInertialVelocityAtDeparture( ).z( ), tolerance );

    BOOST_CHECK_CLOSE_FRACTION( expectedInertialVelocityAtArrival.x( ),
                                testLambertTargeter.getInertialVelocityAtArrival( ).x( ),
                                tolerance );
    BOOST_CHECK_CLOSE_FRACTION( expectedInertialVelocityAtArrival.y( ),
                                testLambertTargeter.getInertialVelocityAtArrival( ).y( ),
                                tolerance );
    BOOST_CHECK_SMALL( testLambertTargeter.getInertialVelocityAtArrival( ).z( ), tolerance );

    BOOST_CHECK_CLOSE_FRACTION( expectedInertialVelocityAtDeparture.x( ),
                                testLambertTargeter.getInertialVelocityVectors( ).first.x( ),
                                tolerance );
    BOOST_CHECK_CLOSE_FRACTION( expectedInertialVelocityAtDeparture.y( ),
                                testLambertTargeter.getInertialVelocityVectors( ).first.y( ),
                                tolerance );
    BOOST_CHECK_SMALL( testLambertTargeter.getInertialVelocityVectors( ).first.z( ), tolerance );

    BOOST_CHECK_CLOSE_FRACTION( expectedInertialVelocityAtArrival.x( ),
                                testLambertTargeter.getInertialVelocityVectors( ).second.x( ),
                                tolerance );
    BOOST_CHECK_CLOSE_FRACTION( expectedInertialVelocityAtArrival.y( ),
                                testLambertTargeter.getInertialVelocityVectors( ).second.y( ),
                                tolerance );
    BOOST_CHECK_SMALL( testLambertTargeter.getInertialVelocityVectors( ).second.z( ), tolerance );
}

BOOST_AUTO_TEST_SUITE_END( )

} // namespace unit_tests
} // namespace tudat


#ifndef BOOST_GEOMETRY_PROJECTIONS_AITOFF_HPP
#define BOOST_GEOMETRY_PROJECTIONS_AITOFF_HPP

// Boost.Geometry - extensions-gis-projections (based on PROJ4)
// This file is automatically generated. DO NOT EDIT.

// Copyright (c) 2008-2015 Barend Gehrels, Amsterdam, the Netherlands.

// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle.

// Use, modification and distribution is 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)

// This file is converted from PROJ4, http://trac.osgeo.org/proj
// PROJ4 is originally written by Gerald Evenden (then of the USGS)
// PROJ4 is maintained by Frank Warmerdam
// PROJ4 is converted to Boost.Geometry by Barend Gehrels

// Last updated version of proj: 4.9.1

// Original copyright notice:

// Purpose:  Implementation of the aitoff (Aitoff) and wintri (Winkel Tripel)
// projections.
// Author:   Gerald Evenden
// Copyright (c) 1995, Gerald Evenden

// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/util/math.hpp>

#include <boost/geometry/srs/projections/impl/base_static.hpp>
#include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
#include <boost/geometry/srs/projections/impl/projects.hpp>
#include <boost/geometry/srs/projections/impl/factory_entry.hpp>

namespace boost { namespace geometry
{

namespace srs { namespace par4
{
    struct aitoff {};
    struct wintri {};

}} //namespace srs::par4

namespace projections
{
    #ifndef DOXYGEN_NO_DETAIL
    namespace detail { namespace aitoff
    {
            template <typename T>
            struct par_aitoff
            {
                T    cosphi1;
                int  mode;
            };

            // template class, using CRTP to implement forward/inverse
            template <typename CalculationType, typename Parameters>
            struct base_aitoff_spheroid : public base_t_fi<base_aitoff_spheroid<CalculationType, Parameters>,
                     CalculationType, Parameters>
            {

                typedef CalculationType geographic_type;
                typedef CalculationType cartesian_type;

                par_aitoff<CalculationType> m_proj_parm;

                inline base_aitoff_spheroid(const Parameters& par)
                    : base_t_fi<base_aitoff_spheroid<CalculationType, Parameters>,
                     CalculationType, Parameters>(*this, par) {}

                // FORWARD(s_forward)  spheroid
                // Project coordinates from geographic (lon, lat) to cartesian (x, y)
                inline void fwd(geographic_type& lp_lon, geographic_type& lp_lat, cartesian_type& xy_x, cartesian_type& xy_y) const
                {
                    CalculationType c, d;

                    if((d = acos(cos(lp_lat) * cos(c = 0.5 * lp_lon)))) {/* basic Aitoff */
                        xy_x = 2. * d * cos(lp_lat) * sin(c) * (xy_y = 1. / sin(d));
                        xy_y *= d * sin(lp_lat);
                    } else
                        xy_x = xy_y = 0.;
                    if (this->m_proj_parm.mode) { /* Winkel Tripel */
                        xy_x = (xy_x + lp_lon * this->m_proj_parm.cosphi1) * 0.5;
                        xy_y = (xy_y + lp_lat) * 0.5;
                    }
                }
                /***********************************************************************************
                *
                * Inverse functions added by Drazen Tutic and Lovro Gradiser based on paper:
                *
                * I.Özbug Biklirici and Cengizhan Ipbüker. A General Algorithm for the Inverse
                * Transformation of Map Projections Using Jacobian Matrices. In Proceedings of the
                * Third International Symposium Mathematical & Computational Applications,
                * pages 175{182, Turkey, September 2002.
                *
                * Expected accuracy is defined by EPSILON = 1e-12. Should be appropriate for
                * most applications of Aitoff and Winkel Tripel projections.
                *
                * Longitudes of 180W and 180E can be mixed in solution obtained.
                *
                * Inverse for Aitoff projection in poles is undefined, longitude value of 0 is assumed.
                *
                * Contact : dtutic@geof.hr
                * Date: 2015-02-16
                *
                ************************************************************************************/

                // INVERSE(s_inverse)  sphere
                // Project coordinates from cartesian (x, y) to geographic (lon, lat)
                inline void inv(cartesian_type& xy_x, cartesian_type& xy_y, geographic_type& lp_lon, geographic_type& lp_lat) const
                {
                    static const CalculationType ONEPI = detail::ONEPI<CalculationType>();
                    static const CalculationType TWOPI = detail::TWOPI<CalculationType>();
                    static const CalculationType EPSILON = 1e-12;

                    int iter, MAXITER = 10, round = 0, MAXROUND = 20;
                    CalculationType D, C, f1, f2, f1p, f1l, f2p, f2l, dp, dl, sl, sp, cp, cl, x, y;

                    if ((fabs(xy_x) < EPSILON) && (fabs(xy_y) < EPSILON )) { lp_lat = 0.; lp_lon = 0.; return; }

                    /* intial values for Newton-Raphson method */
                    lp_lat = xy_y; lp_lon = xy_x;
                    do {
                        iter = 0;
                        do {
                            sl = sin(lp_lon * 0.5); cl = cos(lp_lon * 0.5);
                            sp = sin(lp_lat); cp = cos(lp_lat);
                            D = cp * cl;
                                   C = 1. - D * D;
                            D = acos(D) / pow(C, 1.5);
                                   f1 = 2. * D * C * cp * sl;
                                   f2 = D * C * sp;
                                   f1p = 2.* (sl * cl * sp * cp / C - D * sp * sl);
                                   f1l = cp * cp * sl * sl / C + D * cp * cl * sp * sp;
                                f2p = sp * sp * cl / C + D * sl * sl * cp;
                                  f2l = 0.5 * (sp * cp * sl / C - D * sp * cp * cp * sl * cl);
                                  if (this->m_proj_parm.mode) { /* Winkel Tripel */
                                f1 = 0.5 * (f1 + lp_lon * this->m_proj_parm.cosphi1);
                                f2 = 0.5 * (f2 + lp_lat);
                                f1p *= 0.5;
                                f1l = 0.5 * (f1l + this->m_proj_parm.cosphi1);
                                f2p = 0.5 * (f2p + 1.);
                                f2l *= 0.5;
                            }
                            f1 -= xy_x; f2 -= xy_y;
                            dl = (f2 * f1p - f1 * f2p) / (dp = f1p * f2l - f2p * f1l);
                            dp = (f1 * f2l - f2 * f1l) / dp;
                            while (dl > ONEPI) dl -= ONEPI; /* set to interval [-ONEPI, ONEPI]  */
                            while (dl < -ONEPI) dl += ONEPI; /* set to interval [-ONEPI, ONEPI]  */
                            lp_lat -= dp;    lp_lon -= dl;
                        } while ((fabs(dp) > EPSILON || fabs(dl) > EPSILON) && (iter++ < MAXITER));
                        if (lp_lat > TWOPI) lp_lat -= 2.*(lp_lat-TWOPI); /* correct if symmetrical solution for Aitoff */
                        if (lp_lat < -TWOPI) lp_lat -= 2.*(lp_lat+TWOPI); /* correct if symmetrical solution for Aitoff */
                        if ((fabs(fabs(lp_lat) - TWOPI) < EPSILON) && (!this->m_proj_parm.mode)) lp_lon = 0.; /* if pole in Aitoff, return longitude of 0 */

                        /* calculate x,y coordinates with solution obtained */
                        if((D = acos(cos(lp_lat) * cos(C = 0.5 * lp_lon)))) {/* Aitoff */
                            x = 2. * D * cos(lp_lat) * sin(C) * (y = 1. / sin(D));
                            y *= D * sin(lp_lat);
                        } else
                            x = y = 0.;
                        if (this->m_proj_parm.mode) { /* Winkel Tripel */
                            x = (x + lp_lon * this->m_proj_parm.cosphi1) * 0.5;
                            y = (y + lp_lat) * 0.5;
                        }
                    /* if too far from given values of x,y, repeat with better approximation of phi,lam */
                    } while (((fabs(xy_x-x) > EPSILON) || (fabs(xy_y-y) > EPSILON)) && (round++ < MAXROUND));

                    //if (iter == MAXITER && round == MAXROUND) fprintf(stderr, "Warning: Accuracy of 1e-12 not reached. Last increments: dlat=%e and dlon=%e\n", dp, dl);
                }

                static inline std::string get_name()
                {
                    return "aitoff_spheroid";
                }

            };

            template <typename Parameters, typename T>
            inline void setup(Parameters& par, par_aitoff<T>& proj_parm)
            {
                boost::ignore_unused(proj_parm);
                par.es = 0.;
            }

            // Aitoff
            template <typename Parameters, typename T>
            inline void setup_aitoff(Parameters& par, par_aitoff<T>& proj_parm)
            {
                proj_parm.mode = 0;
                setup(par, proj_parm);
            }

            // Winkel Tripel
            template <typename Parameters, typename T>
            inline void setup_wintri(Parameters& par, par_aitoff<T>& proj_parm)
            {
                static const T TWO_D_PI = detail::TWO_D_PI<T>();

                proj_parm.mode = 1;
                if (pj_param(par.params, "tlat_1").i) {
                    if ((proj_parm.cosphi1 = cos(pj_param(par.params, "rlat_1").f)) == 0.)
                        BOOST_THROW_EXCEPTION( projection_exception(-22) );
                } else /* 50d28' or phi1=acos(2/pi) */
                    proj_parm.cosphi1 = TWO_D_PI;
                setup(par, proj_parm);
            }

    }} // namespace detail::aitoff
    #endif // doxygen

    /*!
        \brief Aitoff projection
        \ingroup projections
        \tparam Geographic latlong point type
        \tparam Cartesian xy point type
        \tparam Parameters parameter type
        \par Projection characteristics
         - Miscellaneous
         - Spheroid
        \par Example
        \image html ex_aitoff.gif
    */
    template <typename CalculationType, typename Parameters>
    struct aitoff_spheroid : public detail::aitoff::base_aitoff_spheroid<CalculationType, Parameters>
    {
        inline aitoff_spheroid(const Parameters& par) : detail::aitoff::base_aitoff_spheroid<CalculationType, Parameters>(par)
        {
            detail::aitoff::setup_aitoff(this->m_par, this->m_proj_parm);
        }
    };

    /*!
        \brief Winkel Tripel projection
        \ingroup projections
        \tparam Geographic latlong point type
        \tparam Cartesian xy point type
        \tparam Parameters parameter type
        \par Projection characteristics
         - Miscellaneous
         - Spheroid
        \par Projection parameters
         - lat_1: Latitude of first standard parallel (degrees)
        \par Example
        \image html ex_wintri.gif
    */
    template <typename CalculationType, typename Parameters>
    struct wintri_spheroid : public detail::aitoff::base_aitoff_spheroid<CalculationType, Parameters>
    {
        inline wintri_spheroid(const Parameters& par) : detail::aitoff::base_aitoff_spheroid<CalculationType, Parameters>(par)
        {
            detail::aitoff::setup_wintri(this->m_par, this->m_proj_parm);
        }
    };

    #ifndef DOXYGEN_NO_DETAIL
    namespace detail
    {

        // Static projection
        BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION(srs::par4::aitoff, aitoff_spheroid, aitoff_spheroid)
        BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION(srs::par4::wintri, wintri_spheroid, wintri_spheroid)

        // Factory entry(s)
        template <typename CalculationType, typename Parameters>
        class aitoff_entry : public detail::factory_entry<CalculationType, Parameters>
        {
            public :
                virtual base_v<CalculationType, Parameters>* create_new(const Parameters& par) const
                {
                    return new base_v_fi<aitoff_spheroid<CalculationType, Parameters>, CalculationType, Parameters>(par);
                }
        };

        template <typename CalculationType, typename Parameters>
        class wintri_entry : public detail::factory_entry<CalculationType, Parameters>
        {
            public :
                virtual base_v<CalculationType, Parameters>* create_new(const Parameters& par) const
                {
                    return new base_v_fi<wintri_spheroid<CalculationType, Parameters>, CalculationType, Parameters>(par);
                }
        };

        template <typename CalculationType, typename Parameters>
        inline void aitoff_init(detail::base_factory<CalculationType, Parameters>& factory)
        {
            factory.add_to_factory("aitoff", new aitoff_entry<CalculationType, Parameters>);
            factory.add_to_factory("wintri", new wintri_entry<CalculationType, Parameters>);
        }

    } // namespace detail
    #endif // doxygen

} // namespace projections

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_PROJECTIONS_AITOFF_HPP


//
// Original authors: Andrew Dowsey <andrew.dowsey@manchester.ac.uk>
//
// Copyright 2014 CADET Bioinformatics Laboratory
//                University of Manchester, UK
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include "aux_Eigen.hpp"

#include <iostream>
#include <sstream>
#include <boost/gil/gil_all.hpp>
#include <boost/gil/extension/io/png_dynamic_io.hpp>
#include <math.h>

// http://stackoverflow.com/questions/7706339/grayscale-to-red-green-blue-matlab-jet-color-scale

COLOUR GetColour(fp v,fp vmin,fp vmax)
{
   COLOUR c = {1.0f,1.0f,1.0f}; // white
   fp dv;

   if (v < vmin)
      v = vmin;
   if (v > vmax)
      v = vmax;
   dv = vmax - vmin;

   if (v < (vmin + 0.25f * dv)) {
      c.r = 0;
      c.g = 4 * (v - vmin) / dv;
   } else if (v < (vmin + 0.5f * dv)) {
      c.r = 0;
      c.b = 1 + 4 * (vmin + 0.25f * dv - v) / dv;
   } else if (v < (vmin + 0.75f * dv)) {
      c.r = 4 * (v - vmin - 0.5f * dv) / dv;
      c.b = 0;
   } else {
      c.g = 1 + 4 * (vmin + 0.75f * dv - v) / dv;
      c.b = 0;
   }

   return(c);
}

// end http://stackoverflow.com/questions/7706339/grayscale-to-red-green-blue-matlab-jet-color-scale


//---------------------------------------------------------------------------//
//!
//! \file   tstBarnUnit.cpp
//! \author Alex Robinson
//! \brief  The barn unit unit tests
//!
//---------------------------------------------------------------------------//

// Boost Includes
#include <boost/units/quantity.hpp>
#include <boost/units/systems/cgs/area.hpp>
#include <boost/units/systems/si/area.hpp>

// Trilinos Includes
#include <Teuchos_UnitTestHarness.hpp>

// FRENSIE Includes
#include "Utility_BarnUnit.hpp"

using namespace Utility::Units;
using boost::units::quantity;
namespace si = boost::units::si;
namespace cgs = boost::units::cgs;

//---------------------------------------------------------------------------//
// Tests
//---------------------------------------------------------------------------//
// Check that the barn unit can be initialized
TEUCHOS_UNIT_TEST( BarnUnit, initialize )
{
  quantity<Barn> barn_area( 1.0*barn );

  TEST_EQUALITY_CONST( barn_area.value(), 1.0 );

  barn_area = 2.0*barn;

  TEST_EQUALITY_CONST( barn_area.value(), 2.0 );
}

//---------------------------------------------------------------------------//
// Check that the barn unit can be initialized from cgs and si units
TEUCHOS_UNIT_TEST( BarnUnit, initialize_from_cgs_si )
{
  quantity<Barn> barn_area_cgs( 1.0*cgs::square_centimeter );

  quantity<Barn> barn_area_si( 1.0*si::square_meter );

  TEST_EQUALITY_CONST( barn_area_cgs.value(), 1e24 );
  TEST_EQUALITY_CONST( barn_area_si.value(), 1e28 );
}

//---------------------------------------------------------------------------//
// Check that the cgs and si units can be initialized from the barn unit
TEUCHOS_UNIT_TEST( BarnUnit, initialize_cgs_si )
{
  quantity<cgs::area> cgs_area( 1.0*barn );

  quantity<si::area> si_area( 1.0*barn );

  TEST_EQUALITY_CONST( cgs_area.value(), 1e-24 );
  TEST_EQUALITY_CONST( si_area.value(), 1e-28 );
}

//---------------------------------------------------------------------------//
// end tstBarnUnit.cpp
//---------------------------------------------------------------------------//


#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>

#include <iostream>
#include <string>
#include <vector>

namespace client{
  namespace qi = boost::spirit::qi;
  namespace ascii = boost::spirit::ascii;

  template <typename Iterator>
    bool parse_numbers(Iterator first, Iterator last, std::vector<double>& v){
      using qi::double_;
      using qi::phrase_parse;
      using qi::_1;
      using ascii::space;

      bool r = phrase_parse(first, last,
          (
            double_ % ','
          ),
          space, v);

      if(first != last)
        return false;
      return r;
    }
}

int main(){
  std::string str;
  while(getline(std::cin, str)){
    if(str.empty() || str[0] == 'q' || str[0] == 'Q')
      break;

    std::vector<double> v;
    if(client::parse_numbers(str.begin(), str.end(), v)){
      std::cout << "Parsing succeeded\n";

      for(std::vector<double>::size_type i = 0; i < v.size(); ++i)
        std::cout << i << ": " << v[i] << std::endl;
    }
    else{
      std::cout << "Parsing failed\n";
    }
  }

  return 0;
}


#pragma once
#include <boost/format.hpp>
#include <catch2/catch.hpp>
#include <mitama/dimensional/arithmetic.hpp>
#include <mitama/dimensional/io.hpp>
#include <mitama/dimensional/systems/si/prefix.hpp>
#include <mitama/dimensional/quantity.hpp>
#include <mitama/dimensional/systems/si/all.hpp>
#include <test_util.hpp>

using namespace mitama;
using namespace mitama::systems::si;
using namespace mitama::systems::nonsi;

inline auto fmt = [](auto const &a) {
  return (boost::format("%1%") % a).str();
};
using namespace std::literals;


/**
 * @file serialization_test.cpp
 * @author Ryan Curtin
 *
 * Test serialization of mlpack objects.
 */
#include <boost/serialization/serialization.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <mlpack/core.hpp>

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

#include <mlpack/core/dists/regression_distribution.hpp>
#include <mlpack/core/tree/ballbound.hpp>
#include <mlpack/core/tree/hrectbound.hpp>
#include <mlpack/core/metrics/mahalanobis_distance.hpp>
#include <mlpack/core/tree/binary_space_tree.hpp>

#include <mlpack/methods/perceptron/perceptron.hpp>
#include <mlpack/methods/logistic_regression/logistic_regression.hpp>
#include <mlpack/methods/neighbor_search/neighbor_search.hpp>
#include <mlpack/methods/softmax_regression/softmax_regression.hpp>
#include <mlpack/methods/det/dtree.hpp>

using namespace mlpack;
using namespace mlpack::distribution;
using namespace mlpack::regression;
using namespace mlpack::bound;
using namespace mlpack::metric;
using namespace mlpack::tree;
using namespace mlpack::perceptron;
using namespace mlpack::regression;
using namespace arma;
using namespace boost;
using namespace boost::archive;
using namespace boost::serialization;
using namespace std;

BOOST_AUTO_TEST_SUITE(SerializationTest);

// Test function for loading and saving Armadillo objects.
template<typename MatType,
         typename IArchiveType,
         typename OArchiveType>
void TestArmadilloSerialization(MatType& x)
{
  // First save it.
  ofstream ofs("test");
  OArchiveType o(ofs);

  bool success = true;
  try
  {
    o << BOOST_SERIALIZATION_NVP(x);
  }
  catch (archive_exception& e)
  {
    success = false;
  }

  BOOST_REQUIRE_EQUAL(success, true);
  ofs.close();

  // Now load it.
  MatType orig(x);
  success = true;
  ifstream ifs("test");
  IArchiveType i(ifs);

  try
  {
    i >> BOOST_SERIALIZATION_NVP(x);
  }
  catch (archive_exception& e)
  {
    success = false;
  }

  BOOST_REQUIRE_EQUAL(success, true);

  BOOST_REQUIRE_EQUAL(x.n_rows, orig.n_rows);
  BOOST_REQUIRE_EQUAL(x.n_cols, orig.n_cols);
  BOOST_REQUIRE_EQUAL(x.n_elem, orig.n_elem);

  for (size_t i = 0; i < x.n_cols; ++i)
    for (size_t j = 0; j < x.n_rows; ++j)
      if (double(orig(j, i)) == 0.0)
        BOOST_REQUIRE_SMALL(double(x(j, i)), 1e-8);
      else
        BOOST_REQUIRE_CLOSE(double(orig(j, i)), double(x(j, i)), 1e-8);

  remove("test");
}

// Test all serialization strategies.
template<typename MatType>
void TestAllArmadilloSerialization(MatType& x)
{
  TestArmadilloSerialization<MatType, xml_iarchive, xml_oarchive>(x);
  TestArmadilloSerialization<MatType, text_iarchive, text_oarchive>(x);
  TestArmadilloSerialization<MatType, binary_iarchive, binary_oarchive>(x);
}

/**
 * Can we load and save an Armadillo matrix?
 */
BOOST_AUTO_TEST_CASE(MatrixSerializeXMLTest)
{
  arma::mat m;
  m.randu(50, 50);
  TestAllArmadilloSerialization(m);
}

/**
 * How about columns?
 */
BOOST_AUTO_TEST_CASE(ColSerializeXMLTest)
{
  arma::vec m;
  m.randu(50, 1);
  TestAllArmadilloSerialization(m);
}

/**
 * How about rows?
 */
BOOST_AUTO_TEST_CASE(RowSerializeXMLTest)
{
  arma::rowvec m;
  m.randu(1, 50);
  TestAllArmadilloSerialization(m);
}

// A quick test with an empty matrix.
BOOST_AUTO_TEST_CASE(EmptyMatrixSerializeTest)
{
  arma::mat m;
  TestAllArmadilloSerialization(m);
}

/**
 * Can we load and save a sparse Armadillo matrix?
 */
BOOST_AUTO_TEST_CASE(SparseMatrixSerializeXMLTest)
{
  arma::sp_mat m;
  m.sprandu(50, 50, 0.3);
  TestAllArmadilloSerialization(m);
}

/**
 * How about columns?
 */
BOOST_AUTO_TEST_CASE(SparseColSerializeXMLTest)
{
  arma::sp_vec m;
  m.sprandu(50, 1, 0.3);
  TestAllArmadilloSerialization(m);
}

/**
 * How about rows?
 */
BOOST_AUTO_TEST_CASE(SparseRowSerializeXMLTest)
{
  arma::sp_rowvec m;
  m.sprandu(1, 50, 0.3);
  TestAllArmadilloSerialization(m);
}

// A quick test with an empty matrix.
BOOST_AUTO_TEST_CASE(EmptySparseMatrixSerializeTest)
{
  arma::sp_mat m;
  TestAllArmadilloSerialization(m);
}

// Save and load an mlpack object.
// The re-loaded copy is placed in 'newT'.
template<typename T, typename IArchiveType, typename OArchiveType>
void SerializeObject(T& t, T& newT)
{
  ofstream ofs("test");
  OArchiveType o(ofs);

  bool success = true;
  try
  {
    o << data::CreateNVP(t, "t");
  }
  catch (archive_exception& e)
  {
    success = false;
  }
  ofs.close();

  BOOST_REQUIRE_EQUAL(success, true);

  ifstream ifs("test");
  IArchiveType i(ifs);

  try
  {
    i >> data::CreateNVP(newT, "t");
  }
  catch (archive_exception& e)
  {
    success = false;
  }
  ifs.close();

  BOOST_REQUIRE_EQUAL(success, true);
}

// Test mlpack serialization with all three archive types.
template<typename T>
void SerializeObjectAll(T& t, T& xmlT, T& textT, T& binaryT)
{
  SerializeObject<T, text_iarchive, text_oarchive>(t, textT);
  SerializeObject<T, binary_iarchive, binary_oarchive>(t, binaryT);
  SerializeObject<T, xml_iarchive, xml_oarchive>(t, xmlT);
}

// Save and load a non-default-constructible mlpack object.
template<typename T, typename IArchiveType, typename OArchiveType>
void SerializePointerObject(T* t, T*& newT)
{
  ofstream ofs("test");
  OArchiveType o(ofs);

  bool success = true;
  try
  {
    o << data::CreateNVP(*t, "t");
  }
  catch (archive_exception& e)
  {
    success = false;
  }
  ofs.close();

  BOOST_REQUIRE_EQUAL(success, true);

  ifstream ifs("test");
  IArchiveType i(ifs);

  try
  {
    newT = new T(i);
  }
  catch (std::exception& e)
  {
    success = false;
  }
  ifs.close();

  BOOST_REQUIRE_EQUAL(success, true);
}

template<typename T>
void SerializePointerObjectAll(T* t, T*& xmlT, T*& textT, T*& binaryT)
{
  SerializePointerObject<T, text_iarchive, text_oarchive>(t, textT);
  SerializePointerObject<T, binary_iarchive, binary_oarchive>(t, binaryT);
  SerializePointerObject<T, xml_iarchive, xml_oarchive>(t, xmlT);
}

// Utility function to check the equality of two Armadillo matrices.
void CheckMatrices(const mat& x,
                   const mat& xmlX,
                   const mat& textX,
                   const mat& binaryX)
{
  // First check dimensions.
  BOOST_REQUIRE_EQUAL(x.n_rows, xmlX.n_rows);
  BOOST_REQUIRE_EQUAL(x.n_rows, textX.n_rows);
  BOOST_REQUIRE_EQUAL(x.n_rows, binaryX.n_rows);

  BOOST_REQUIRE_EQUAL(x.n_cols, xmlX.n_cols);
  BOOST_REQUIRE_EQUAL(x.n_cols, textX.n_cols);
  BOOST_REQUIRE_EQUAL(x.n_cols, binaryX.n_cols);

  BOOST_REQUIRE_EQUAL(x.n_elem, xmlX.n_elem);
  BOOST_REQUIRE_EQUAL(x.n_elem, textX.n_elem);
  BOOST_REQUIRE_EQUAL(x.n_elem, binaryX.n_elem);

  // Now check elements.
  for (size_t i = 0; i < x.n_elem; ++i)
  {
    const double val = x[i];
    if (val == 0.0)
    {
      BOOST_REQUIRE_SMALL(xmlX[i], 1e-8);
      BOOST_REQUIRE_SMALL(textX[i], 1e-8);
      BOOST_REQUIRE_SMALL(binaryX[i], 1e-8);
    }
    else
    {
      BOOST_REQUIRE_CLOSE(val, xmlX[i], 1e-8);
      BOOST_REQUIRE_CLOSE(val, textX[i], 1e-8);
      BOOST_REQUIRE_CLOSE(val, binaryX[i], 1e-8);
    }
  }
}

void CheckMatrices(const Mat<size_t>& x,
                   const Mat<size_t>& xmlX,
                   const Mat<size_t>& textX,
                   const Mat<size_t>& binaryX)
{
  // First check dimensions.
  BOOST_REQUIRE_EQUAL(x.n_rows, xmlX.n_rows);
  BOOST_REQUIRE_EQUAL(x.n_rows, textX.n_rows);
  BOOST_REQUIRE_EQUAL(x.n_rows, binaryX.n_rows);

  BOOST_REQUIRE_EQUAL(x.n_cols, xmlX.n_cols);
  BOOST_REQUIRE_EQUAL(x.n_cols, textX.n_cols);
  BOOST_REQUIRE_EQUAL(x.n_cols, binaryX.n_cols);

  BOOST_REQUIRE_EQUAL(x.n_elem, xmlX.n_elem);
  BOOST_REQUIRE_EQUAL(x.n_elem, textX.n_elem);
  BOOST_REQUIRE_EQUAL(x.n_elem, binaryX.n_elem);

  // Now check elements.
  for (size_t i = 0; i < x.n_elem; ++i)
  {
    BOOST_REQUIRE_EQUAL(x[i], xmlX[i]);
    BOOST_REQUIRE_EQUAL(x[i], textX[i]);
    BOOST_REQUIRE_EQUAL(x[i], binaryX[i]);
  }
}

// Now, test mlpack objects.
BOOST_AUTO_TEST_CASE(DiscreteDistributionTest)
{
  // I assume that I am properly saving vectors, so, this should be
  // straightforward.
  vec prob;
  prob.randu(12);
  DiscreteDistribution t(prob);

  DiscreteDistribution xmlT, textT, binaryT;

  // Load and save with all serializers.
  SerializeObjectAll(t, xmlT, textT, binaryT);

  for (size_t i = 0; i < 12; ++i)
  {
    vec obs(1);
    obs[0] = i;
    const double prob = t.Probability(obs);
    if (prob == 0.0)
    {
      BOOST_REQUIRE_SMALL(xmlT.Probability(obs), 1e-8);
      BOOST_REQUIRE_SMALL(textT.Probability(obs), 1e-8);
      BOOST_REQUIRE_SMALL(binaryT.Probability(obs), 1e-8);
    }
    else
    {
      BOOST_REQUIRE_CLOSE(prob, xmlT.Probability(obs), 1e-8);
      BOOST_REQUIRE_CLOSE(prob, textT.Probability(obs), 1e-8);
      BOOST_REQUIRE_CLOSE(prob, binaryT.Probability(obs), 1e-8);
    }
  }
}

BOOST_AUTO_TEST_CASE(GaussianDistributionTest)
{
  vec mean(10);
  mean.randu();
  // Generate a covariance matrix.
  mat cov;
  cov.randu(10, 10);
  cov = (cov * cov.t());

  GaussianDistribution g(mean, cov);
  GaussianDistribution xmlG, textG, binaryG;

  SerializeObjectAll(g, xmlG, textG, binaryG);

  BOOST_REQUIRE_EQUAL(g.Dimensionality(), xmlG.Dimensionality());
  BOOST_REQUIRE_EQUAL(g.Dimensionality(), textG.Dimensionality());
  BOOST_REQUIRE_EQUAL(g.Dimensionality(), binaryG.Dimensionality());

  // First, check the means.
  CheckMatrices(g.Mean(), xmlG.Mean(), textG.Mean(), binaryG.Mean());

  // Now, check the covariance.
  CheckMatrices(g.Covariance(), xmlG.Covariance(), textG.Covariance(),
      binaryG.Covariance());

  // Lastly, run some observations through and make sure the probability is the
  // same.  This should test anything cached internally.
  arma::mat randomObs;
  randomObs.randu(10, 500);

  for (size_t i = 0; i < 500; ++i)
  {
    const double prob = g.Probability(randomObs.unsafe_col(i));

    if (prob == 0.0)
    {
      BOOST_REQUIRE_SMALL(xmlG.Probability(randomObs.unsafe_col(i)), 1e-8);
      BOOST_REQUIRE_SMALL(textG.Probability(randomObs.unsafe_col(i)), 1e-8);
      BOOST_REQUIRE_SMALL(binaryG.Probability(randomObs.unsafe_col(i)), 1e-8);
    }
    else
    {
      BOOST_REQUIRE_CLOSE(prob, xmlG.Probability(randomObs.unsafe_col(i)),
          1e-8);
      BOOST_REQUIRE_CLOSE(prob, textG.Probability(randomObs.unsafe_col(i)),
          1e-8);
      BOOST_REQUIRE_CLOSE(prob, binaryG.Probability(randomObs.unsafe_col(i)),
          1e-8);
    }
  }
}

BOOST_AUTO_TEST_CASE(LaplaceDistributionTest)
{
  vec mean(20);
  mean.randu();

  LaplaceDistribution l(mean, 2.5);
  LaplaceDistribution xmlL, textL, binaryL;

  SerializeObjectAll(l, xmlL, textL, binaryL);

  BOOST_REQUIRE_CLOSE(l.Scale(), xmlL.Scale(), 1e-8);
  BOOST_REQUIRE_CLOSE(l.Scale(), textL.Scale(), 1e-8);
  BOOST_REQUIRE_CLOSE(l.Scale(), binaryL.Scale(), 1e-8);

  CheckMatrices(l.Mean(), xmlL.Mean(), textL.Mean(), binaryL.Mean());
}

BOOST_AUTO_TEST_CASE(MahalanobisDistanceTest)
{
  MahalanobisDistance<> d;
  d.Covariance().randu(50, 50);

  MahalanobisDistance<> xmlD, textD, binaryD;

  SerializeObjectAll(d, xmlD, textD, binaryD);

  // Check the covariance matrices.
  CheckMatrices(d.Covariance(),
                xmlD.Covariance(),
                textD.Covariance(),
                binaryD.Covariance());
}

BOOST_AUTO_TEST_CASE(LinearRegressionTest)
{
  // Generate some random data.
  mat data;
  data.randn(15, 800);
  vec responses;
  responses.randn(800, 1);

  LinearRegression lr(data, responses, 0.05); // Train the model.
  LinearRegression xmlLr, textLr, binaryLr;

  SerializeObjectAll(lr, xmlLr, textLr, binaryLr);

  BOOST_REQUIRE_CLOSE(lr.Lambda(), xmlLr.Lambda(), 1e-8);
  BOOST_REQUIRE_CLOSE(lr.Lambda(), textLr.Lambda(), 1e-8);
  BOOST_REQUIRE_CLOSE(lr.Lambda(), binaryLr.Lambda(), 1e-8);

  CheckMatrices(lr.Parameters(), xmlLr.Parameters(), textLr.Parameters(),
      binaryLr.Parameters());
}

BOOST_AUTO_TEST_CASE(RegressionDistributionTest)
{
  // Generate some random data.
  mat data;
  data.randn(15, 800);
  vec responses;
  responses.randn(800, 1);

  RegressionDistribution rd(data, responses);
  RegressionDistribution xmlRd, textRd, binaryRd;

  // Okay, now save it and load it.
  SerializeObjectAll(rd, xmlRd, textRd, binaryRd);

  // Check the gaussian distribution.
  CheckMatrices(rd.Err().Mean(),
                xmlRd.Err().Mean(),
                textRd.Err().Mean(),
                binaryRd.Err().Mean());
  CheckMatrices(rd.Err().Covariance(),
                xmlRd.Err().Covariance(),
                textRd.Err().Covariance(),
                binaryRd.Err().Covariance());

  // Check the regression function.
  if (rd.Rf().Lambda() == 0.0)
  {
    BOOST_REQUIRE_SMALL(xmlRd.Rf().Lambda(), 1e-8);
    BOOST_REQUIRE_SMALL(textRd.Rf().Lambda(), 1e-8);
    BOOST_REQUIRE_SMALL(binaryRd.Rf().Lambda(), 1e-8);
  }
  else
  {
    BOOST_REQUIRE_CLOSE(rd.Rf().Lambda(), xmlRd.Rf().Lambda(), 1e-8);
    BOOST_REQUIRE_CLOSE(rd.Rf().Lambda(), textRd.Rf().Lambda(), 1e-8);
    BOOST_REQUIRE_CLOSE(rd.Rf().Lambda(), binaryRd.Rf().Lambda(), 1e-8);
  }

  CheckMatrices(rd.Rf().Parameters(),
                xmlRd.Rf().Parameters(),
                textRd.Rf().Parameters(),
                binaryRd.Rf().Parameters());
}

BOOST_AUTO_TEST_CASE(BallBoundTest)
{
  BallBound<> b(100);
  b.Center().randu();
  b.Radius() = 14.0;

  BallBound<> xmlB, textB, binaryB;

  SerializeObjectAll(b, xmlB, textB, binaryB);

  // Check the dimensionality.
  BOOST_REQUIRE_EQUAL(b.Dim(), xmlB.Dim());
  BOOST_REQUIRE_EQUAL(b.Dim(), textB.Dim());
  BOOST_REQUIRE_EQUAL(b.Dim(), binaryB.Dim());

  // Check the radius.
  BOOST_REQUIRE_CLOSE(b.Radius(), xmlB.Radius(), 1e-8);
  BOOST_REQUIRE_CLOSE(b.Radius(), textB.Radius(), 1e-8);
  BOOST_REQUIRE_CLOSE(b.Radius(), binaryB.Radius(), 1e-8);

  // Now check the vectors.
  CheckMatrices(b.Center(), xmlB.Center(), textB.Center(), binaryB.Center());
}

BOOST_AUTO_TEST_CASE(MahalanobisBallBoundTest)
{
  BallBound<arma::vec, MahalanobisDistance<>> b(100);
  b.Center().randu();
  b.Radius() = 14.0;
  b.Metric().Covariance().randu(100, 100);

  BallBound<arma::vec, MahalanobisDistance<>> xmlB, textB, binaryB;

  SerializeObjectAll(b, xmlB, textB, binaryB);

  // Check the radius.
  BOOST_REQUIRE_CLOSE(b.Radius(), xmlB.Radius(), 1e-8);
  BOOST_REQUIRE_CLOSE(b.Radius(), textB.Radius(), 1e-8);
  BOOST_REQUIRE_CLOSE(b.Radius(), binaryB.Radius(), 1e-8);

  // Check the vectors.
  CheckMatrices(b.Center(), xmlB.Center(), textB.Center(), binaryB.Center());
  CheckMatrices(b.Metric().Covariance(),
                xmlB.Metric().Covariance(),
                textB.Metric().Covariance(),
                binaryB.Metric().Covariance());
}

BOOST_AUTO_TEST_CASE(HRectBoundTest)
{
  HRectBound<> b(2);

  arma::mat points("0.0, 1.1; 5.0, 2.2");
  points = points.t();
  b |= points; // [0.0, 5.0]; [1.1, 2.2];

  HRectBound<> xmlB, textB, binaryB;

  SerializeObjectAll(b, xmlB, textB, binaryB);

  // Check the dimensionality.
  BOOST_REQUIRE_EQUAL(b.Dim(), xmlB.Dim());
  BOOST_REQUIRE_EQUAL(b.Dim(), textB.Dim());
  BOOST_REQUIRE_EQUAL(b.Dim(), binaryB.Dim());

  // Check the bounds.
  for (size_t i = 0; i < b.Dim(); ++i)
  {
    BOOST_REQUIRE_CLOSE(b[i].Lo(), xmlB[i].Lo(), 1e-8);
    BOOST_REQUIRE_CLOSE(b[i].Hi(), xmlB[i].Hi(), 1e-8);
    BOOST_REQUIRE_CLOSE(b[i].Lo(), textB[i].Lo(), 1e-8);
    BOOST_REQUIRE_CLOSE(b[i].Hi(), textB[i].Hi(), 1e-8);
    BOOST_REQUIRE_CLOSE(b[i].Lo(), binaryB[i].Lo(), 1e-8);
    BOOST_REQUIRE_CLOSE(b[i].Hi(), binaryB[i].Hi(), 1e-8);
  }

  // Check the minimum width.
  BOOST_REQUIRE_CLOSE(b.MinWidth(), xmlB.MinWidth(), 1e-8);
  BOOST_REQUIRE_CLOSE(b.MinWidth(), textB.MinWidth(), 1e-8);
  BOOST_REQUIRE_CLOSE(b.MinWidth(), binaryB.MinWidth(), 1e-8);
}

template<typename TreeType>
void CheckTrees(TreeType& tree,
                TreeType& xmlTree,
                TreeType& textTree,
                TreeType& binaryTree)
{
  const typename TreeType::Mat* dataset = &tree.Dataset();

  // Make sure that the data matrices are the same.
  if (tree.Parent() == NULL)
  {
    CheckMatrices(*dataset,
                  xmlTree.Dataset(),
                  textTree.Dataset(),
                  binaryTree.Dataset());

    // Also ensure that the other parents are null too.
    BOOST_REQUIRE_EQUAL(xmlTree.Parent(), (TreeType*) NULL);
    BOOST_REQUIRE_EQUAL(textTree.Parent(), (TreeType*) NULL);
    BOOST_REQUIRE_EQUAL(binaryTree.Parent(), (TreeType*) NULL);
  }

  // Make sure the number of children is the same.
  BOOST_REQUIRE_EQUAL(tree.NumChildren(), xmlTree.NumChildren());
  BOOST_REQUIRE_EQUAL(tree.NumChildren(), textTree.NumChildren());
  BOOST_REQUIRE_EQUAL(tree.NumChildren(), binaryTree.NumChildren());

  // Make sure the number of descendants is the same.
  BOOST_REQUIRE_EQUAL(tree.NumDescendants(), xmlTree.NumDescendants());
  BOOST_REQUIRE_EQUAL(tree.NumDescendants(), textTree.NumDescendants());
  BOOST_REQUIRE_EQUAL(tree.NumDescendants(), binaryTree.NumDescendants());

  // Make sure the number of points is the same.
  BOOST_REQUIRE_EQUAL(tree.NumPoints(), xmlTree.NumPoints());
  BOOST_REQUIRE_EQUAL(tree.NumPoints(), textTree.NumPoints());
  BOOST_REQUIRE_EQUAL(tree.NumPoints(), binaryTree.NumPoints());

  // Check that each point is the same.
  for (size_t i = 0; i < tree.NumPoints(); ++i)
  {
    BOOST_REQUIRE_EQUAL(tree.Point(i), xmlTree.Point(i));
    BOOST_REQUIRE_EQUAL(tree.Point(i), textTree.Point(i));
    BOOST_REQUIRE_EQUAL(tree.Point(i), binaryTree.Point(i));
  }

  // Check that the parent distance is the same.
  BOOST_REQUIRE_CLOSE(tree.ParentDistance(), xmlTree.ParentDistance(), 1e-8);
  BOOST_REQUIRE_CLOSE(tree.ParentDistance(), textTree.ParentDistance(), 1e-8);
  BOOST_REQUIRE_CLOSE(tree.ParentDistance(), binaryTree.ParentDistance(), 1e-8);

  // Check that the furthest descendant distance is the same.
  BOOST_REQUIRE_CLOSE(tree.FurthestDescendantDistance(),
      xmlTree.FurthestDescendantDistance(), 1e-8);
  BOOST_REQUIRE_CLOSE(tree.FurthestDescendantDistance(),
      textTree.FurthestDescendantDistance(), 1e-8);
  BOOST_REQUIRE_CLOSE(tree.FurthestDescendantDistance(),
      binaryTree.FurthestDescendantDistance(), 1e-8);

  // Check that the minimum bound distance is the same.
  BOOST_REQUIRE_CLOSE(tree.MinimumBoundDistance(),
      xmlTree.MinimumBoundDistance(), 1e-8);
  BOOST_REQUIRE_CLOSE(tree.MinimumBoundDistance(),
      textTree.MinimumBoundDistance(), 1e-8);
  BOOST_REQUIRE_CLOSE(tree.MinimumBoundDistance(),
      binaryTree.MinimumBoundDistance(), 1e-8);

  // Recurse into the children.
  for (size_t i = 0; i < tree.NumChildren(); ++i)
  {
    // Check that the child dataset is the same.
    BOOST_REQUIRE_EQUAL(&xmlTree.Dataset(), &xmlTree.Child(i).Dataset());
    BOOST_REQUIRE_EQUAL(&textTree.Dataset(), &textTree.Child(i).Dataset());
    BOOST_REQUIRE_EQUAL(&binaryTree.Dataset(), &binaryTree.Child(i).Dataset());

    // Make sure the parent link is right.
    BOOST_REQUIRE_EQUAL(xmlTree.Child(i).Parent(), &xmlTree);
    BOOST_REQUIRE_EQUAL(textTree.Child(i).Parent(), &textTree);
    BOOST_REQUIRE_EQUAL(binaryTree.Child(i).Parent(), &binaryTree);

    CheckTrees(tree.Child(i), xmlTree.Child(i), textTree.Child(i),
        binaryTree.Child(i));
  }
}

BOOST_AUTO_TEST_CASE(BinarySpaceTreeTest)
{
  arma::mat data;
  data.randu(3, 100);
  typedef KDTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
  TreeType tree(data);

  TreeType* xmlTree;
  TreeType* textTree;
  TreeType* binaryTree;

  SerializePointerObjectAll(&tree, xmlTree, textTree, binaryTree);

  CheckTrees(tree, *xmlTree, *textTree, *binaryTree);

  delete xmlTree;
  delete textTree;
  delete binaryTree;
}

BOOST_AUTO_TEST_CASE(BinarySpaceTreeOverwriteTest)
{
  arma::mat data;
  data.randu(3, 100);
  typedef KDTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
  TreeType tree(data);

  TreeType xmlTree(tree);
  TreeType textTree(tree);
  TreeType binaryTree(tree);

  SerializeObjectAll(tree, xmlTree, textTree, binaryTree);

  CheckTrees(tree, xmlTree, textTree, binaryTree);
}

BOOST_AUTO_TEST_CASE(PerceptronTest)
{
  // Create a perceptron.  Train it randomly.  Then check that it hasn't
  // changed.
  arma::mat data;
  data.randu(3, 100);
  arma::Row<size_t> labels(100);
  for (size_t i = 0; i < labels.n_elem; ++i)
  {
    if (data(1, i) > 0.5)
      labels[i] = 0;
    else
      labels[i] = 1;
  }

  Perceptron<> p(data, labels, 2, 15);

  Perceptron<> pXml(2, 3), pText(2, 3), pBinary(2, 3);
  SerializeObjectAll(p, pXml, pText, pBinary);

  // Now check that things are the same.
  CheckMatrices(p.Weights(), pXml.Weights(), pText.Weights(),
      pBinary.Weights());
  CheckMatrices(p.Biases(), pXml.Biases(), pText.Biases(), pBinary.Biases());

  BOOST_REQUIRE_EQUAL(p.MaxIterations(), pXml.MaxIterations());
  BOOST_REQUIRE_EQUAL(p.MaxIterations(), pText.MaxIterations());
  BOOST_REQUIRE_EQUAL(p.MaxIterations(), pBinary.MaxIterations());
}

BOOST_AUTO_TEST_CASE(LogisticRegressionTest)
{
  arma::mat data;
  data.randu(3, 100);
  arma::Row<size_t> responses;
  responses.randu(100);

  LogisticRegression<> lr(data, responses, 0.5);

  LogisticRegression<> lrXml(data, responses + 3, 0.3);
  LogisticRegression<> lrText(data, responses + 1);
  LogisticRegression<> lrBinary(3, 0.0);

  SerializeObjectAll(lr, lrXml, lrText, lrBinary);

  CheckMatrices(lr.Parameters(), lrXml.Parameters(), lrText.Parameters(),
      lrBinary.Parameters());

  BOOST_REQUIRE_CLOSE(lr.Lambda(), lrXml.Lambda(), 1e-5);
  BOOST_REQUIRE_CLOSE(lr.Lambda(), lrText.Lambda(), 1e-5);
  BOOST_REQUIRE_CLOSE(lr.Lambda(), lrBinary.Lambda(), 1e-5);
}

BOOST_AUTO_TEST_CASE(AllkNNTest)
{
  using neighbor::AllkNN;
  arma::mat dataset = arma::randu<arma::mat>(5, 2000);

  AllkNN allknn(dataset, false, false);

  AllkNN knnXml, knnText, knnBinary;

  SerializeObjectAll(allknn, knnXml, knnText, knnBinary);

  // Now run nearest neighbor and make sure the results are the same.
  arma::mat querySet = arma::randu<arma::mat>(5, 1000);

  arma::mat distances, xmlDistances, textDistances, binaryDistances;
  arma::Mat<size_t> neighbors, xmlNeighbors, textNeighbors, binaryNeighbors;

  allknn.Search(querySet, 5, neighbors, distances);
  knnXml.Search(querySet, 5, xmlNeighbors, xmlDistances);
  knnText.Search(querySet, 5, textNeighbors, textDistances);
  knnBinary.Search(querySet, 5, binaryNeighbors, binaryDistances);

  CheckMatrices(distances, xmlDistances, textDistances, binaryDistances);
  CheckMatrices(neighbors, xmlNeighbors, textNeighbors, binaryNeighbors);
}

BOOST_AUTO_TEST_CASE(SoftmaxRegressionTest)
{
  using regression::SoftmaxRegression;

  arma::mat dataset = arma::randu<arma::mat>(5, 1000);
  arma::Row<size_t> labels(1000);
  for (size_t i = 0; i < 500; ++i)
    labels[i] = 0;
  for (size_t i = 500; i < 1000; ++i)
    labels[i] = 1;

  SoftmaxRegression<> sr(dataset, labels, 2);

  SoftmaxRegression<> srXml(dataset.n_rows, 2);
  SoftmaxRegression<> srText(dataset.n_rows, 2);
  SoftmaxRegression<> srBinary(dataset.n_rows, 2);

  SerializeObjectAll(sr, srXml, srText, srBinary);

  CheckMatrices(sr.Parameters(), srXml.Parameters(), srText.Parameters(),
      srBinary.Parameters());
}

BOOST_AUTO_TEST_CASE(DETTest)
{
  using det::DTree;

  // Create a density estimation tree on a random dataset.
  arma::mat dataset = arma::randu<arma::mat>(25, 5000);

  DTree tree(dataset);

  arma::mat otherDataset = arma::randu<arma::mat>(5, 100);
  DTree xmlTree, binaryTree, textTree(otherDataset);

  SerializeObjectAll(tree, xmlTree, binaryTree, textTree);

  std::stack<DTree*> stack, xmlStack, binaryStack, textStack;
  stack.push(&tree);
  xmlStack.push(&xmlTree);
  binaryStack.push(&binaryTree);
  textStack.push(&textTree);

  while (!stack.empty())
  {
    // Get the top node from the stack.
    DTree* node = stack.top();
    DTree* xmlNode = xmlStack.top();
    DTree* binaryNode = binaryStack.top();
    DTree* textNode = textStack.top();

    stack.pop();
    xmlStack.pop();
    binaryStack.pop();
    textStack.pop();

    // Check that all the members are the same.
    BOOST_REQUIRE_EQUAL(node->Start(), xmlNode->Start());
    BOOST_REQUIRE_EQUAL(node->Start(), binaryNode->Start());
    BOOST_REQUIRE_EQUAL(node->Start(), textNode->Start());

    BOOST_REQUIRE_EQUAL(node->End(), xmlNode->End());
    BOOST_REQUIRE_EQUAL(node->End(), binaryNode->End());
    BOOST_REQUIRE_EQUAL(node->End(), textNode->End());

    BOOST_REQUIRE_EQUAL(node->SplitDim(), xmlNode->SplitDim());
    BOOST_REQUIRE_EQUAL(node->SplitDim(), binaryNode->SplitDim());
    BOOST_REQUIRE_EQUAL(node->SplitDim(), textNode->SplitDim());

    if (std::abs(node->SplitValue()) < 1e-5)
    {
      BOOST_REQUIRE_SMALL(xmlNode->SplitValue(), 1e-5);
      BOOST_REQUIRE_SMALL(binaryNode->SplitValue(), 1e-5);
      BOOST_REQUIRE_SMALL(textNode->SplitValue(), 1e-5);
    }
    else
    {
      BOOST_REQUIRE_CLOSE(node->SplitValue(), xmlNode->SplitValue(), 1e-5);
      BOOST_REQUIRE_CLOSE(node->SplitValue(), binaryNode->SplitValue(), 1e-5);
      BOOST_REQUIRE_CLOSE(node->SplitValue(), textNode->SplitValue(), 1e-5);
    }

    if (std::abs(node->LogNegError()) < 1e-5)
    {
      BOOST_REQUIRE_SMALL(xmlNode->LogNegError(), 1e-5);
      BOOST_REQUIRE_SMALL(binaryNode->LogNegError(), 1e-5);
      BOOST_REQUIRE_SMALL(textNode->LogNegError(), 1e-5);
    }
    else
    {
      BOOST_REQUIRE_CLOSE(node->LogNegError(), xmlNode->LogNegError(), 1e-5);
      BOOST_REQUIRE_CLOSE(node->LogNegError(), binaryNode->LogNegError(), 1e-5);
      BOOST_REQUIRE_CLOSE(node->LogNegError(), textNode->LogNegError(), 1e-5);
    }

    if (std::abs(node->SubtreeLeavesLogNegError()) < 1e-5)
    {
      BOOST_REQUIRE_SMALL(xmlNode->SubtreeLeavesLogNegError(), 1e-5);
      BOOST_REQUIRE_SMALL(binaryNode->SubtreeLeavesLogNegError(), 1e-5);
      BOOST_REQUIRE_SMALL(textNode->SubtreeLeavesLogNegError(), 1e-5);
    }
    else
    {
      BOOST_REQUIRE_CLOSE(node->SubtreeLeavesLogNegError(),
          xmlNode->SubtreeLeavesLogNegError(), 1e-5);
      BOOST_REQUIRE_CLOSE(node->SubtreeLeavesLogNegError(),
          binaryNode->SubtreeLeavesLogNegError(), 1e-5);
      BOOST_REQUIRE_CLOSE(node->SubtreeLeavesLogNegError(),
          textNode->SubtreeLeavesLogNegError(), 1e-5);
    }

    BOOST_REQUIRE_EQUAL(node->SubtreeLeaves(), xmlNode->SubtreeLeaves());
    BOOST_REQUIRE_EQUAL(node->SubtreeLeaves(), binaryNode->SubtreeLeaves());
    BOOST_REQUIRE_EQUAL(node->SubtreeLeaves(), textNode->SubtreeLeaves());

    if (std::abs(node->Ratio()) < 1e-5)
    {
      BOOST_REQUIRE_SMALL(xmlNode->Ratio(), 1e-5);
      BOOST_REQUIRE_SMALL(binaryNode->Ratio(), 1e-5);
      BOOST_REQUIRE_SMALL(textNode->Ratio(), 1e-5);
    }
    else
    {
      BOOST_REQUIRE_CLOSE(node->Ratio(), xmlNode->Ratio(), 1e-5);
      BOOST_REQUIRE_CLOSE(node->Ratio(), binaryNode->Ratio(), 1e-5);
      BOOST_REQUIRE_CLOSE(node->Ratio(), textNode->Ratio(), 1e-5);
    }

    if (std::abs(node->LogVolume()) < 1e-5)
    {
      BOOST_REQUIRE_SMALL(xmlNode->LogVolume(), 1e-5);
      BOOST_REQUIRE_SMALL(binaryNode->LogVolume(), 1e-5);
      BOOST_REQUIRE_SMALL(textNode->LogVolume(), 1e-5);
    }
    else
    {
      BOOST_REQUIRE_CLOSE(node->LogVolume(), xmlNode->LogVolume(), 1e-5);
      BOOST_REQUIRE_CLOSE(node->LogVolume(), binaryNode->LogVolume(), 1e-5);
      BOOST_REQUIRE_CLOSE(node->LogVolume(), textNode->LogVolume(), 1e-5);
    }

    if (node->Left() == NULL)
    {
      BOOST_REQUIRE(xmlNode->Left() == NULL);
      BOOST_REQUIRE(binaryNode->Left() == NULL);
      BOOST_REQUIRE(textNode->Left() == NULL);
    }
    else
    {
      BOOST_REQUIRE(xmlNode->Left() != NULL);
      BOOST_REQUIRE(binaryNode->Left() != NULL);
      BOOST_REQUIRE(textNode->Left() != NULL);

      // Push children onto stack.
      stack.push(node->Left());
      xmlStack.push(xmlNode->Left());
      binaryStack.push(binaryNode->Left());
      textStack.push(textNode->Left());
    }

    if (node->Right() == NULL)
    {
      BOOST_REQUIRE(xmlNode->Right() == NULL);
      BOOST_REQUIRE(binaryNode->Right() == NULL);
      BOOST_REQUIRE(textNode->Right() == NULL);
    }
    else
    {
      BOOST_REQUIRE(xmlNode->Right() != NULL);
      BOOST_REQUIRE(binaryNode->Right() != NULL);
      BOOST_REQUIRE(textNode->Right() != NULL);

      // Push children onto stack.
      stack.push(node->Right());
      xmlStack.push(xmlNode->Right());
      binaryStack.push(binaryNode->Right());
      textStack.push(textNode->Right());
    }

    BOOST_REQUIRE_EQUAL(node->Root(), xmlNode->Root());
    BOOST_REQUIRE_EQUAL(node->Root(), binaryNode->Root());
    BOOST_REQUIRE_EQUAL(node->Root(), textNode->Root());

    if (std::abs(node->AlphaUpper()) < 1e-5)
    {
      BOOST_REQUIRE_SMALL(xmlNode->AlphaUpper(), 1e-5);
      BOOST_REQUIRE_SMALL(binaryNode->AlphaUpper(), 1e-5);
      BOOST_REQUIRE_SMALL(textNode->AlphaUpper(), 1e-5);
    }
    else
    {
      BOOST_REQUIRE_CLOSE(node->AlphaUpper(), xmlNode->AlphaUpper(), 1e-5);
      BOOST_REQUIRE_CLOSE(node->AlphaUpper(), binaryNode->AlphaUpper(), 1e-5);
      BOOST_REQUIRE_CLOSE(node->AlphaUpper(), textNode->AlphaUpper(), 1e-5);
    }

    BOOST_REQUIRE_EQUAL(node->MaxVals().n_elem, xmlNode->MaxVals().n_elem);
    BOOST_REQUIRE_EQUAL(node->MaxVals().n_elem, binaryNode->MaxVals().n_elem);
    BOOST_REQUIRE_EQUAL(node->MaxVals().n_elem, textNode->MaxVals().n_elem);
    for (size_t i = 0; i < node->MaxVals().n_elem; ++i)
    {
      if (std::abs(node->MaxVals()[i]) < 1e-5)
      {
        BOOST_REQUIRE_SMALL(xmlNode->MaxVals()[i], 1e-5);
        BOOST_REQUIRE_SMALL(binaryNode->MaxVals()[i], 1e-5);
        BOOST_REQUIRE_SMALL(textNode->MaxVals()[i], 1e-5);
      }
      else
      {
        BOOST_REQUIRE_CLOSE(node->MaxVals()[i], xmlNode->MaxVals()[i], 1e-5);
        BOOST_REQUIRE_CLOSE(node->MaxVals()[i], binaryNode->MaxVals()[i], 1e-5);
        BOOST_REQUIRE_CLOSE(node->MaxVals()[i], textNode->MaxVals()[i], 1e-5);
      }
    }

    BOOST_REQUIRE_EQUAL(node->MinVals().n_elem, xmlNode->MinVals().n_elem);
    BOOST_REQUIRE_EQUAL(node->MinVals().n_elem, binaryNode->MinVals().n_elem);
    BOOST_REQUIRE_EQUAL(node->MinVals().n_elem, textNode->MinVals().n_elem);
    for (size_t i = 0; i < node->MinVals().n_elem; ++i)
    {
      if (std::abs(node->MinVals()[i]) < 1e-5)
      {
        BOOST_REQUIRE_SMALL(xmlNode->MinVals()[i], 1e-5);
        BOOST_REQUIRE_SMALL(binaryNode->MinVals()[i], 1e-5);
        BOOST_REQUIRE_SMALL(textNode->MinVals()[i], 1e-5);
      }
      else
      {
        BOOST_REQUIRE_CLOSE(node->MinVals()[i], xmlNode->MinVals()[i], 1e-5);
        BOOST_REQUIRE_CLOSE(node->MinVals()[i], binaryNode->MinVals()[i], 1e-5);
        BOOST_REQUIRE_CLOSE(node->MinVals()[i], textNode->MinVals()[i], 1e-5);
      }
    }
  }
}

BOOST_AUTO_TEST_SUITE_END();


// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2018-2021 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle

// Use, modification and distribution is 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_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP

#include <iterator>
#include <type_traits>

#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator.hpp>
#include <boost/range/value_type.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>

#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/dummy_geometries.hpp>

#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/static_assert.hpp>
#include <boost/geometry/core/tags.hpp>

#include <boost/geometry/geometries/concepts/check.hpp>

#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/line_interpolate/cartesian.hpp>
#include <boost/geometry/strategies/line_interpolate/geographic.hpp>
#include <boost/geometry/strategies/line_interpolate/spherical.hpp>

namespace boost { namespace geometry
{

#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace line_interpolate
{

struct convert_and_push_back
{
    template <typename Range, typename Point>
    static inline void apply(Point const& p, Range& range)
    {
        typename boost::range_value<Range>::type p2;
        geometry::detail::conversion::convert_point_to_point(p, p2);
        range::push_back(range, p2);
    }
};

struct convert_and_assign
{
    template <typename Point1, typename Point2>
    static inline void apply(Point1 const& p1, Point2& p2)
    {
        geometry::detail::conversion::convert_point_to_point(p1, p2);
    }

};

/*!
\brief Internal, calculates interpolation point of a linestring using iterator pairs and
    specified strategy
*/
template <typename Policy>
struct interpolate_range
{
    template
    <
        typename Range,
        typename Distance,
        typename PointLike,
        typename Strategies
    >
    static inline void apply(Range const& range,
                             Distance const& max_distance,
                             PointLike & pointlike,
                             Strategies const& strategies)
    {
        typedef typename boost::range_iterator<Range const>::type iterator_t;
        typedef typename boost::range_value<Range const>::type point_t;

        iterator_t it = boost::begin(range);
        iterator_t end = boost::end(range);

        if (it == end) // empty(range)
        {
            BOOST_THROW_EXCEPTION(empty_input_exception());
            return;
        }
        if (max_distance <= 0) //non positive distance
        {
            Policy::apply(*it, pointlike);
            return;
        }

        auto const pp_strategy = strategies.distance(dummy_point(), dummy_point());
        auto const strategy = strategies.line_interpolate(range);

        typedef decltype(pp_strategy.apply(
                    std::declval<point_t>(), std::declval<point_t>())) distance_type;

        iterator_t prev = it++;
        distance_type repeated_distance = max_distance;
        distance_type prev_distance = 0;
        distance_type current_distance = 0;
        point_t start_p = *prev;

        for ( ; it != end ; ++it)
        {
            distance_type dist = pp_strategy.apply(*prev, *it);
            current_distance = prev_distance + dist;

            while (current_distance >= repeated_distance)
            {
                point_t p;
                distance_type diff_distance = current_distance - prev_distance;
                BOOST_ASSERT(diff_distance != distance_type(0));
                strategy.apply(start_p, *it,
                               (repeated_distance - prev_distance)/diff_distance,
                               p,
                               diff_distance);
                Policy::apply(p, pointlike);
                if (std::is_same<PointLike, point_t>::value)
                {
                    return;
                }
                start_p = p;
                prev_distance = repeated_distance;
                repeated_distance += max_distance;
            }
            prev_distance = current_distance;
            prev = it;
            start_p = *prev;
        }

        // case when max_distance is larger than linestring's length
        // return the last point in range (range is not empty)
        if (repeated_distance == max_distance)
        {
            Policy::apply(*(end-1), pointlike);
        }
    }
};

template <typename Policy>
struct interpolate_segment
{
    template <typename Segment, typename Distance, typename Pointlike, typename Strategy>
    static inline void apply(Segment const& segment,
                             Distance const& max_distance,
                             Pointlike & point,
                             Strategy const& strategy)
    {
        interpolate_range<Policy>().apply(segment_view<Segment>(segment),
                                          max_distance, point, strategy);
    }
};

}} // namespace detail::line_interpolate
#endif // DOXYGEN_NO_DETAIL

#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{

template
<
    typename Geometry,
    typename Pointlike,
    typename Tag1 = typename tag<Geometry>::type,
    typename Tag2 = typename tag<Pointlike>::type
>
struct line_interpolate
{
    BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
        "Not implemented for this Geometry type.",
        Geometry, Pointlike);
};

template <typename Geometry, typename Pointlike>
struct line_interpolate<Geometry, Pointlike, linestring_tag, point_tag>
    : detail::line_interpolate::interpolate_range
        <
            detail::line_interpolate::convert_and_assign
        >
{};

template <typename Geometry, typename Pointlike>
struct line_interpolate<Geometry, Pointlike, linestring_tag, multi_point_tag>
    : detail::line_interpolate::interpolate_range
        <
            detail::line_interpolate::convert_and_push_back
        >
{};

template <typename Geometry, typename Pointlike>
struct line_interpolate<Geometry, Pointlike, segment_tag, point_tag>
    : detail::line_interpolate::interpolate_segment
        <
            detail::line_interpolate::convert_and_assign
        >
{};

template <typename Geometry, typename Pointlike>
struct line_interpolate<Geometry, Pointlike, segment_tag, multi_point_tag>
    : detail::line_interpolate::interpolate_segment
        <
            detail::line_interpolate::convert_and_push_back
        >
{};

} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

namespace resolve_strategy {

template
<
    typename Strategies,
    bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
>
struct line_interpolate
{
    template <typename Geometry, typename Distance, typename Pointlike>
    static inline void apply(Geometry const& geometry,
                             Distance const& max_distance,
                             Pointlike & pointlike,
                             Strategies const& strategies)
    {
        dispatch::line_interpolate
            <
                Geometry, Pointlike
            >::apply(geometry, max_distance, pointlike, strategies);
    }
};

template <typename Strategy>
struct line_interpolate<Strategy, false>
{
    template <typename Geometry, typename Distance, typename Pointlike>
    static inline void apply(Geometry const& geometry,
                             Distance const& max_distance,
                             Pointlike & pointlike,
                             Strategy const& strategy)
    {
        using strategies::line_interpolate::services::strategy_converter;

        dispatch::line_interpolate
            <
                Geometry, Pointlike
            >::apply(geometry, max_distance, pointlike,
                     strategy_converter<Strategy>::get(strategy));
    }
};

template <>
struct line_interpolate<default_strategy, false>
{
    template <typename Geometry, typename Distance, typename Pointlike>
    static inline void apply(Geometry const& geometry,
                             Distance const& max_distance,
                             Pointlike & pointlike,
                             default_strategy)
    {
        typedef typename strategies::line_interpolate::services::default_strategy
            <
                Geometry
            >::type strategy_type;

        dispatch::line_interpolate
            <
                Geometry, Pointlike
            >::apply(geometry, max_distance, pointlike, strategy_type());
    }
};

} // namespace resolve_strategy

namespace resolve_variant {

template <typename Geometry>
struct line_interpolate
{
    template <typename Distance, typename Pointlike, typename Strategy>
    static inline void apply(Geometry const& geometry,
                             Distance const& max_distance,
                             Pointlike & pointlike,
                             Strategy const& strategy)
    {
        return resolve_strategy::line_interpolate
                <
                    Strategy
                >::apply(geometry, max_distance, pointlike, strategy);
    }
};

template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct line_interpolate<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
    template <typename Pointlike, typename Strategy>
    struct visitor: boost::static_visitor<void>
    {
        Pointlike const& m_pointlike;
        Strategy const& m_strategy;

        visitor(Pointlike const& pointlike, Strategy const& strategy)
            : m_pointlike(pointlike)
            , m_strategy(strategy)
        {}

        template <typename Geometry, typename Distance>
        void operator()(Geometry const& geometry, Distance const& max_distance) const
        {
            line_interpolate<Geometry>::apply(geometry, max_distance,
                                              m_pointlike, m_strategy);
        }
    };

    template <typename Distance, typename Pointlike, typename Strategy>
    static inline void
    apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
          Distance const& max_distance,
          Pointlike & pointlike,
          Strategy const& strategy)
    {
        boost::apply_visitor(
            visitor<Pointlike, Strategy>(pointlike, strategy),
            geometry,
            max_distance
        );
    }
};

} // namespace resolve_variant

/*!
\brief     Returns one or more points interpolated along a LineString \brief_strategy
\ingroup line_interpolate
\tparam Geometry Any type fulfilling a LineString concept
\tparam Distance A numerical distance measure
\tparam Pointlike Any type fulfilling Point or Multipoint concept
\tparam Strategy A type fulfilling a LineInterpolatePointStrategy concept
\param geometry Input geometry
\param max_distance Distance threshold (in units depending on coordinate system)
representing the spacing between the points
\param pointlike Output: either a Point (exactly one point will be constructed) or
a MultiPoint (depending on the max_distance one or more points will be constructed)
\param strategy line_interpolate strategy to be used for interpolation of
points

\qbk{[include reference/algorithms/line_interpolate.qbk]}

\qbk{distinguish,with strategy}

\qbk{
[heading Available Strategies]
\* [link geometry.reference.strategies.strategy_line_interpolate_cartesian Cartesian]
\* [link geometry.reference.strategies.strategy_line_interpolate_spherical Spherical]
\* [link geometry.reference.strategies.strategy_line_interpolate_geographic Geographic]

[heading Example]
[line_interpolate_strategy]
[line_interpolate_strategy_output]

[heading See also]
\* [link geometry.reference.algorithms.densify densify]
}
 */
template
<
    typename Geometry,
    typename Distance,
    typename Pointlike,
    typename Strategy
>
inline void line_interpolate(Geometry const& geometry,
                             Distance const& max_distance,
                             Pointlike & pointlike,
                             Strategy const& strategy)
{
    concepts::check<Geometry const>();

    // detail::throw_on_empty_input(geometry);

    return resolve_variant::line_interpolate<Geometry>
                          ::apply(geometry, max_distance, pointlike, strategy);
}

/*!
\brief     Returns one or more points interpolated along a LineString.
\ingroup line_interpolate
\tparam Geometry Any type fulfilling a LineString concept
\tparam Distance A numerical distance measure
\tparam Pointlike Any type fulfilling Point or Multipoint concept
\param geometry Input geometry
\param max_distance Distance threshold (in units depending on coordinate system)
representing the spacing between the points
\param pointlike Output: either a Point (exactly one point will be constructed) or
a MultiPoint (depending on the max_distance one or more points will be constructed)

\qbk{[include reference/algorithms/line_interpolate.qbk]

[heading Example]
[line_interpolate]
[line_interpolate_output]

[heading See also]
\* [link geometry.reference.algorithms.densify densify]
}
 */
template<typename Geometry, typename Distance, typename Pointlike>
inline void line_interpolate(Geometry const& geometry,
                             Distance const& max_distance,
                             Pointlike & pointlike)
{
    concepts::check<Geometry const>();

    // detail::throw_on_empty_input(geometry);

    return resolve_variant::line_interpolate<Geometry>
                          ::apply(geometry, max_distance, pointlike, default_strategy());
}

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP


#pragma once

#include <boost/pending/disjoint_sets.hpp>
#include "nifty/graph/edge_contraction_graph.hxx"
#include "nifty/graph/opt/multicut/multicut_base.hxx"
#include "nifty/tools/changable_priority_queue.hxx"

namespace nifty{
namespace graph{
namespace opt{
namespace multicut{

namespace detail_multicut_greedy_fixation{

    template<class WEIGHT_TYPE>
    class DynamicGraph
    {
    public:
        DynamicGraph(size_t n) :
            n_nodes_(n), vertices_(n), cut_edges_(n)
        {}

        inline bool edgeExists(size_t a, size_t b) const
        {
            return !vertices_[a].empty() && vertices_[a].find(b) != vertices_[a].end();
        }

        inline std::unordered_map<size_t, WEIGHT_TYPE> const& getAdjacentVertices(size_t v) const
        {
            return vertices_[v];
        }

        inline WEIGHT_TYPE getEdgeWeight(size_t a, size_t b) const
        {
            return vertices_[a].at(b);
        }

        inline bool haveConstraint(size_t a, size_t b) const
        {
            return !cut_edges_[a].empty() && cut_edges_[a].find(b) != cut_edges_[a].end();
        }

        inline void addConstraint(size_t a, size_t b)
        {
            cut_edges_[a].insert(b);
            cut_edges_[b].insert(a);
        }

        inline void removeVertex(size_t v)
        {
            for (auto& p : vertices_[v])
            {
                vertices_[p.first].erase(v);
                cut_edges_[p.first].erase(v);
            }

            vertices_[v].clear();
            cut_edges_[v].clear();
            --n_nodes_;
        }

        inline void setEdgeWeight(size_t a, size_t b, WEIGHT_TYPE w)
        {
            vertices_[a][b] = w;
            vertices_[b][a] = w;
        }

        inline std::size_t numberOfNodes() {
            return n_nodes_;
        }

    private:
        std::size_t n_nodes_;
        std::vector<std::unordered_set<size_t>> cut_edges_;
        std::vector<std::unordered_map<size_t, WEIGHT_TYPE>> vertices_;
    };

    template<class WEIGHT_TYPE>
    struct Edge
    {
        Edge(size_t _a, size_t _b, WEIGHT_TYPE _w)
        {
            if (_a > _b)
                std::swap(_a, _b);

            a = _a;
            b = _b;

            w = _w;
        }

        size_t a;
        size_t b;
        size_t edition;
        WEIGHT_TYPE w;

        inline bool operator <(Edge const& other) const
        {
            return std::abs(w) < std::abs(other.w);
        }
    };

} // end namespace detail_multicut_greedy_fixation

    // greedy fixation implementation based on
    // https://github.com/bjoern-andres/graph/blob/master/include/andres/graph/multicut/greedy-fixation.hxx
    // I tried to implement it based on edgeContraction graph, but didn't manage to get a working version
    // too many abstractions and std::priority_queue + boost ufd are doing a totally fine job here
    template<class OBJECTIVE>
    class MulticutGreedyFixation : public MulticutBase<OBJECTIVE>
    {
        public:

        struct SettingsType{
            double weightStopCond{0.0};
            double nodeNumStopCond{-1};
            int visitNth{1};
        };

        typedef OBJECTIVE ObjectiveType;
        typedef typename ObjectiveType::GraphType GraphType;
        typedef MulticutBase<OBJECTIVE> BaseType;
        typedef typename BaseType::VisitorBaseType VisitorBaseType;
        typedef typename BaseType::NodeLabelsType NodeLabelsType;
        typedef typename ObjectiveType::WeightType WeightType;
        typedef detail_multicut_greedy_fixation::DynamicGraph<WeightType> DynamicGraphType;
        typedef detail_multicut_greedy_fixation::Edge<WeightType> EdgeType;

        virtual ~MulticutGreedyFixation(){}
        MulticutGreedyFixation(const ObjectiveType & objective, const SettingsType & settings=SettingsType());

        virtual void optimize(NodeLabelsType & nodeLabels, VisitorBaseType * visitor);
        virtual const ObjectiveType & objective() const;

        void reset();
        void changeSettings(const SettingsType & settings);

        virtual void weightsChanged(){
            this->reset();
        }

        virtual const NodeLabelsType & currentBestNodeLabels( ){
            for(auto node : graph_.nodes()){
                currentBest_->operator[](node) = partition_.find_set(node);
            }
            return *currentBest_;
        }

        virtual std::string name() const {
            return std::string("MulticutGreedyFixation");
        }

        private:

        inline bool done(const WeightType weight) {
            const auto nnsc = settings_.nodeNumStopCond;
            // exit if weight stop cond kicks in
            if(std::abs(weight) <= settings_.weightStopCond){
                return true;
            }
            if(nnsc > 0.0){
                uint64_t ns;
                if(nnsc >= 1.0){
                    ns = static_cast<uint64_t>(nnsc);
                }
                else{
                    ns = static_cast<uint64_t>(double(graph_.numberOfNodes())*nnsc +0.5);
                }
                if(dynamicGraph_.numberOfNodes() <= ns){
                    return true;
                }
            }
            if(dynamicGraph_.numberOfNodes() <= 1){
                return true;
            }
            if(pq_.empty()){
                return true;
            }
            return false;
        }

        inline void mergeNodes(std::size_t a, std::size_t b) {
            partition_.link(a, b);

            auto stable_vertex = a;
            auto merge_vertex = b;
            if(partition_.find_set(stable_vertex) != stable_vertex) {
                std::swap(stable_vertex, merge_vertex);
            }

            for (auto& p : dynamicGraph_.getAdjacentVertices(merge_vertex))
            {
                if (p.first == stable_vertex)
                    continue;

                WeightType t = 0;

                if (dynamicGraph_.edgeExists(stable_vertex, p.first))
                    t = dynamicGraph_.getEdgeWeight(stable_vertex, p.first);

                if (dynamicGraph_.haveConstraint(merge_vertex, p.first))
                    dynamicGraph_.addConstraint(stable_vertex, p.first);

                dynamicGraph_.setEdgeWeight(stable_vertex, p.first, p.second + t);

                auto e = EdgeType(stable_vertex, p.first, p.second + t);
                e.edition = ++edge_editions_[e.a][e.b];

                pq_.push(e);
            }

            dynamicGraph_.removeVertex(merge_vertex);
        }

        SettingsType settings_;
        const ObjectiveType & objective_;
        const GraphType & graph_;
        NodeLabelsType * currentBest_;
        DynamicGraphType dynamicGraph_;
        std::priority_queue<EdgeType> pq_;

        // union find
        std::vector<size_t> ranks_;
        std::vector<size_t> parents_;
        boost::disjoint_sets<std::size_t*, std::size_t*> partition_;

        std::vector<std::unordered_map<size_t, size_t>> edge_editions_;
    };

    template<class OBJECTIVE>
    MulticutGreedyFixation<OBJECTIVE>::
    MulticutGreedyFixation(
        const ObjectiveType & objective,
        const SettingsType & settings
    )
    :   settings_(settings),
        objective_(objective),
        graph_(objective.graph()),
        currentBest_(nullptr),
        dynamicGraph_(objective.graph().numberOfNodes()),
        ranks_(objective.graph().numberOfNodes()),
        parents_(objective.graph().numberOfNodes()),
        partition_(&ranks_[0], &parents_[0]),
        edge_editions_(objective.graph().numberOfNodes())
    {
        this->reset();
    }

    template<class OBJECTIVE>
    void MulticutGreedyFixation<OBJECTIVE>::
    optimize(
        NodeLabelsType & nodeLabels,  VisitorBaseType * visitor
    ){

        if(graph_.numberOfEdges() == 0) {
            return;
        }

        if(visitor!=nullptr){
            visitor->addLogNames({"#nodes","topWeight"});
            visitor->begin(this);
        }

        currentBest_ = &nodeLabels;
        std::size_t c = 1;

        while(true)
        {
            auto edge = pq_.top();
            pq_.pop();

            if(done(edge.w)) {
                break;
            }

            // skip edges that are not part of the graph any more
            if (!dynamicGraph_.edgeExists(edge.a, edge.b) || edge.edition < edge_editions_[edge.a][edge.b]) {
                continue;
            }

            const bool haveConstraint = dynamicGraph_.haveConstraint(edge.a, edge.b);
            // std::cout << "Edge " << edge.a << "<->" << edge.b << " weight: " << edge.w << " constraint: " << haveConstraint << std::endl;

            if(!haveConstraint) {  // only do stuff if we don't have a cannott link constraint

                if (edge.w > 0)  // attractiv edge -> merge nodes
                {
                    mergeNodes(edge.a, edge.b);
                }
                else if (edge.w < 0) {  // repulsive edge -> add cannot link constraint
                    dynamicGraph_.addConstraint(edge.a, edge.b);
                }
            }

            if(c % settings_.visitNth == 0){

                if(visitor!=nullptr){
                   visitor->setLogValue(0, dynamicGraph_.numberOfNodes());
                   visitor->setLogValue(1, edge.w);
                   if(!visitor->visit(this)){
                        std::cout<<"end by visitor\n";
                       break;
                   }
                }
            }
            ++c;
        }

        for(auto node : graph_.nodes()){
            nodeLabels[node] = partition_.find_set(node);
        }

        if(visitor!=nullptr) {
            visitor->end(this);
        }
    }

    template<class OBJECTIVE>
    const typename MulticutGreedyFixation<OBJECTIVE>::ObjectiveType &
    MulticutGreedyFixation<OBJECTIVE>::
    objective()const{
        return objective_;
    }

    template<class OBJECTIVE>
    void MulticutGreedyFixation<OBJECTIVE>::
    reset(
    ){
        // initialise ufd
        for(auto node : graph_.nodes()) {
            partition_.make_set(node);
        }

        const auto & edge_values = objective_.weights();

        // fill pq
        for (size_t i = 0; i < graph_.numberOfEdges(); ++i)
        {
            auto uv = graph_.uv(i);
            auto u = uv.first;
            auto v = uv.second;

            dynamicGraph_.setEdgeWeight(u, v, edge_values[i]);

            auto e = EdgeType(u, v, edge_values[i]);
            e.edition = ++edge_editions_[u][v];

            pq_.push(e);
        }
    }

    template<class OBJECTIVE>
    inline void
    MulticutGreedyFixation<OBJECTIVE>::
    changeSettings(
        const SettingsType & settings
    ){
        settings_ = settings;
    }

} // namespace nifty::graph::opt::multicut
} // namespace nifty::graph::opt
} // namespace nifty::graph
} // namespace nifty


#if COMPILATION_INSTRUCTIONS
(echo "#include<" $0 ">" > $0x.cpp) && time clang++ - O3 - std = c++ 1z - Wall `# - Wfatal
        - errors` - I..- D_TEST_SPARSE_COO_MATRIX $0x.cpp - lstdc++ fs - lboost_system - lboost_timer - o $0x.x
    && time $0x.x $ @ && rm - f $0x.cpp;
exit
#endif

////////////////////////////////////////////////////////////////////////////////
// File developed by:
// Alfredo Correa, correaa@llnl.gov
//    Lawrence Livermore National Laboratory
//
// File created by:
// Alfredo Correa, correaa@llnl.gov
//    Lawrence Livermore National Laboratory
////////////////////////////////////////////////////////////////////////////////

#ifndef SPARSE_COO_MATRIX_HPP
#define SPARSE_COO_MATRIX_HPP

#include <array>
#include <cassert>
#include <cstddef> // ptrdiff_t
#include <vector>
#include <tuple>

    namespace ma
{
  namespace sparse
  {
  using size_type = std::size_t;

  template<class T, class index, class Alloc = std::allocator<T>>
  class coo_matrix
  {
  protected:
    using alloc_ts        = std::allocator_traits<Alloc>;
    using index_allocator = typename alloc_ts::template rebind_alloc<index>;
    std::vector<index, index_allocator> is_;
    std::vector<index, index_allocator> js_;
    std::vector<T, Alloc> vs_;
    size_type cols_;
    size_type rows_;

  public:
    using element                            = T;
    coo_matrix(coo_matrix const&)            = default;
    coo_matrix(coo_matrix&&)                 = default;
    bool operator==(coo_matrix const&) const = delete;
    coo_matrix(std::tuple<index, index> const& arr                                    = std::tuple<index, index>{0, 0},
               std::initializer_list<std::pair<std::tuple<index, index>, element>> il = {})
        : cols_(std::get<0>(arr)), rows_(std::get<1>(arr))
    {
      for (auto e : il)
        emplace(e.first, e.second);
    }
    void reserve(size_type s)
    {
      is_.reserve(s);
      js_.reserve(s);
      vs_.reserve(s);
    }
    auto size() const { return rows_; }
    auto num_elements() const { return size() * cols_; }
    std::array<index, 2> shape() const { return {{size(), cols_}}; }
    auto num_non_zero_elements() const { return vs_.size(); }
    T* non_zero_values_data() { return vs_.data(); }
    index* non_zero_indices1_data() { return (index*)is_.data(); }
    index* non_zero_indices2_data() const { return (index*)js_.data(); }
    decltype(auto) move_non_zero_values() && { return std::move(vs_); }
    decltype(auto) move_non_zero_indices1() && { return std::move(is_); }
    decltype(auto) move_non_zero_indices2() && { return std::move(js_); }
    void clear()
    {
      is_.clear();
      js_.clear();
      vs_.clear();
      cols_ = 0;
      rows_ = 0;
    }
    template<class Pair = std::array<index, 2>, class TT>
    void emplace(Pair&& indices, TT&& tt)
    {
      using std::get;
      is_.emplace_back(get<0>(std::forward<Pair>(indices)));
      js_.emplace_back(get<1>(std::forward<Pair>(indices)));
      vs_.emplace_back(std::forward<TT>(tt));
    }

  protected:
    struct row_reference
    {
      coo_matrix& self_;
      index i_;
      struct element_reference
      {
        row_reference& self_;
        index j_;
        template<class TT>
        element_reference&& operator=(TT&& tt) &&
        {
          self_.self_.emplace({{self_.i_, j_}}, std::forward<TT>(tt));
          return std::move(*this);
        }
      };
      using reference = element_reference;
      reference operator[](index i) && { return reference{*this, i}; }
    };

  public:
    using reference = row_reference;
    reference operator[](index i) { return reference{*this, i}; }
    friend decltype(auto) size(coo_matrix const& s) { return s.size(); }
    friend decltype(auto) shape(coo_matrix const& s) { return s.shape(); }
    friend decltype(auto) clear(coo_matrix& s) { s.clear(); }
  };
  /*
template<class... Ts>
std::array<index, 2> index_bases(coo_matrix<Ts...> const&){return {{0,0}};}
template<class... Ts>
auto num_non_zero_elements(coo_matrix<Ts...> const& s){
	return s.num_non_zero_elements();
}
template<class... Ts>
auto non_zero_values_data(coo_matrix<Ts...>& s){return s.non_zero_values_data();}
template<class... Ts>
auto non_zero_indices1_data(coo_matrix<Ts...>& s){
	return s.non_zero_indices1_data();
}
template<class... Ts>
auto non_zero_indices2_data(coo_matrix<Ts...>& s){
	return s.non_zero_indices2_data();
}
*/
  } // namespace sparse
}

#ifdef _TEST_SPARSE_COO_MATRIX

#include "iterator/zipper.hpp"
#include "timer/timed.hpp"

#include <boost/timer/timer.hpp>

#include <algorithm> // std::sort
#include <cassert>
#include <iostream>
#include <random>

using std::cerr;
using std::cout;
using std::get;

int main()
{
  using ma::sparse::coo_matrix;

  auto const M          = 40000;
  auto const N          = 40000;
  double const sparsity = 0.01;

  // generate tuples for reference
  auto const csource = [&]() {
    std::vector<std::tuple<int, int, double>> source;
    source.reserve(M * N * sparsity);
    std::default_random_engine gen;
    std::uniform_real_distribution<double> dist;
    std::uniform_real_distribution<double> dist2(0, 10);
    for (auto i = M; i != 0; --i)
      for (auto j = N; j != 0; --j)
        if (dist(gen) < sparsity)
          source.emplace_back(i - 1, j - 1, dist2(gen));
    return source;
  }();

  cerr << "value size " << csource.size() * sizeof(double) / 1000000 << " MB\n";
  {
    coo_matrix<double> coom({M, N});
    {
      boost::timer::auto_cpu_timer t("ugly syntax: %t seconds\n");
      for (auto& s : csource)
        coom.emplace({{get<0>(s), get<1>(s)}}, get<2>(s));
    }
  }
  {
    coo_matrix<double> coom({M, N});
    {
      boost::timer::auto_cpu_timer t("generic syntax: %t seconds\n");
      for (auto& s : csource)
        coom[get<0>(s)][get<1>(s)] = get<2>(s);
    }
  }

  coo_matrix<double> small({4, 4}, {{{3, 3}, 1}, {{2, 1}, 3}, {{0, 1}, 9}});
}

#endif
#endif


/**********************************
*    = Header File Inclusion =
**********************************/

#include <list>
#include <boost/lexical_cast.hpp>
#include <Wt/WImage>
#include <Wt/WMemoryResource>
#include <Magick++.h>
#include "captcha.hpp"
#include "system.hpp"

/**********************************
*    = PreProcessor Directives =
**********************************/

/**********************************
*    = Importing NameSpaces =
**********************************/

using namespace std;
using namespace boost;
using namespace Wt;
using namespace Magick;
using namespace SamsungDForumIr;

/**********************************
*    = Constants =
**********************************/

/**********************************
*    = Enumerations =
**********************************/

/**********************************
*    = Properties =
**********************************/

/**********************************
*    = Fields =
**********************************/

/**********************************
*    = Constructos =
**********************************/

Captcha::Captcha()
{
    Result = 0;
}

/**********************************
*    = Destructor =
**********************************/

/**********************************
*    = Public Methods =
**********************************/

WImage *Captcha::GenCap()
{
    size_t n1 = (rand() % 10) + 1;
    size_t n2 = (rand() % 10) + 1;
    int rotate = (rand() % 7 - 3);
    int skew = (rand() % 9 - 4);

    Result = n1 * n2;

    string captcha(lexical_cast<string>(n1));
    captcha += " X ";
    captcha += lexical_cast<string>(n2);

    Image img(Geometry(115, 35), Color("white"));
    list<Drawable> drawList;

    drawList.push_back(DrawableTextAntialias(true));
    drawList.push_back(DrawableFont("../fnt/HAZELN.TTF"));
    drawList.push_back(DrawablePointSize(32));
    drawList.push_back(DrawableStrokeColor(Color("black")));
    drawList.push_back(DrawableFillColor(Color(0, 0, 0, MaxRGB)));
    drawList.push_back(DrawableTextDecoration(UnderlineDecoration));
    drawList.push_back(DrawableGravity(CenterGravity));

    drawList.push_back(DrawableRotation(rotate));
    drawList.push_back(DrawableRotation(skew));
    drawList.push_back(DrawableText(0, 0, captcha));

    img.draw(drawList);

    string capPath;

    do {
        capPath = "../tmp/captcha-";
        capPath += lexical_cast<string>(rand());
        capPath += ".png";
    } while (System::FileExists(capPath));

    img.write(capPath);

    WMemoryResource *capResource = new WMemoryResource("image/png");

    char *buffer = NULL;
    size_t size = 0;
    System::ReadFile(capPath, size, &buffer);

    capResource->setData(reinterpret_cast<const unsigned char*>(buffer),
                         static_cast<int>(size));

    delete buffer;

    System::EraseFile(capPath);

    WImage *capImage = new WImage(capResource, "Captcha");
    capImage->setStyleClass("captcha");

    return capImage;
}

/**********************************
*    = Event Handlers =
**********************************/

/**********************************
*    = Private Methods =
**********************************/

/**********************************
*    = Base Class Overrides =
**********************************/

/**********************************
*    = Utility Methods =
**********************************/

/**********************************
*    = Debug Methods =
**********************************/


/**
 * \file boost/numeric/ublasx/operation/isfinite.hpp
 *
 * \brief Apply the \c std::isfinite function to a vector or matrix expression.
 *
 * Copyright (c) 2011, Marco Guazzone
 *
 * 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)
 *
 * \author Marco Guazzone, marco.guazzone@gmail.com
 */

#ifndef BOOST_NUMERIC_UBLASX_OPERATION_ISFINITE_HPP
#define BOOST_NUMERIC_UBLASX_OPERATION_ISFINITE_HPP

#include <boost/numeric/ublas/traits.hpp>
#include <boost/numeric/ublasx/expression/matrix_unary_functor.hpp>
#include <boost/numeric/ublasx/expression/vector_unary_functor.hpp>
#include <boost/type_traits/is_complex.hpp>
#include <boost/utility/enable_if.hpp>
#include <cmath>
#include <complex>

namespace boost { namespace numeric { namespace ublasx {

using namespace ::boost::numeric::ublas;

namespace detail {

template <typename VectorExprT>
struct vector_isfinite_functor_traits
{
	typedef VectorExprT input_expression_type;
	typedef typename vector_traits<input_expression_type>::value_type signature_argument_type;
	typedef int signature_result_type;
	typedef vector_unary_functor_traits<
				input_expression_type,
				signature_result_type (signature_argument_type const&)
			> unary_functor_expression_type;
	typedef typename unary_functor_expression_type::result_type result_type;
	typedef typename unary_functor_expression_type::expression_type expression_type;
};

template <typename MatrixExprT>
struct matrix_isfinite_functor_traits
{
	typedef MatrixExprT input_expression_type;
	typedef typename matrix_traits<input_expression_type>::value_type signature_argument_type;
	typedef int signature_result_type;
	typedef matrix_unary_functor_traits<
				input_expression_type,
				signature_result_type (signature_argument_type const&)
			> unary_functor_expression_type;
	typedef typename unary_functor_expression_type::result_type result_type;
	typedef typename unary_functor_expression_type::expression_type expression_type;
};

namespace /*<unnamed>*/ {

/// Wrapper for ::std::isfinite.
template <typename T>
BOOST_UBLAS_INLINE
typename ::boost::disable_if<
			::boost::is_complex<T>,
			int
>::type isfinite_impl(T x)
{
	return ::std::isfinite(x);
}

/// Auxiliary function used to replace ::std::isfinite when that is not available.
template <typename T>
BOOST_UBLAS_INLINE
typename ::boost::enable_if<
			::boost::is_complex<T>,
			int
>::type isfinite_impl(T x)
{
	// Use the complex infinity definition found at Wolfram Mathworld
	// (http://mathworld.wolfram.com/ComplexInfinity.html)

	return ::std::isfinite(x.real()) && ::std::isnan(x.imag());
}

} // Namespace <unnamed>

} // Namespace detail

/**
 * \brief Applies the \c std::isfinite function to a given vector expression.
 *
 * \tparam VectorExprT The type of the input vector expression.
 *
 * \param ve The input vector expression.
 * \return A vector expression representing the application of \c std::isfinite to
 *  each element of \a ve.
 *
 * \author Marco Guazzone, marco.guazzone@gmail.com
 */
template <typename VectorExprT>
BOOST_UBLAS_INLINE
typename detail::vector_isfinite_functor_traits<VectorExprT>::result_type isfinite(vector_expression<VectorExprT> const& ve)
{
	typedef typename detail::vector_isfinite_functor_traits<VectorExprT>::expression_type expression_type;
	typedef typename detail::vector_isfinite_functor_traits<VectorExprT>::signature_argument_type signature_argument_type;

	return expression_type(ve(), detail::isfinite_impl<signature_argument_type const&>);
}

/**
 * \brief Applies the \c std::isfinite function to a given matrix expression.
 *
 * \tparam MatrixExprT The type of the input matrix expression.
 *
 * \param me The input matrix expression.
 * \return A matrix expression representing the application of \c std::isfinite to
 *  each element of \a me.
 *
 * \author Marco Guazzone, marco.guazzone@gmail.com
 */
template <typename MatrixExprT>
BOOST_UBLAS_INLINE
typename detail::matrix_isfinite_functor_traits<MatrixExprT>::result_type isfinite(matrix_expression<MatrixExprT> const& me)
{
	typedef typename detail::matrix_isfinite_functor_traits<MatrixExprT>::expression_type expression_type;
	typedef typename detail::matrix_isfinite_functor_traits<MatrixExprT>::signature_argument_type signature_argument_type;

	return expression_type(me(), detail::isfinite_impl<signature_argument_type>);
}

}}} // Namespace boost::numeric::ublasx

#endif // BOOST_NUMERIC_UBLASX_OPERATION_ISFINITE_HPP