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

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.

// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.

// 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)

#include <iostream>
#include <string>

#include <geometry_test_common.hpp>

#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/io/wkt/read.hpp>
#include <boost/geometry/strategies/strategies.hpp>

#include <test_common/test_point.hpp>

#include <algorithms/test_relate.hpp>

template <typename G1, typename G2>
void test_disjoint(std::string const& id,
            std::string const& wkt1,
            std::string const& wkt2, bool expected)
{
    G1 g1;
    bg::read_wkt(wkt1, g1);

    G2 g2;
    bg::read_wkt(wkt2, g2);

    bool detected = bg::disjoint(g1, g2);
    BOOST_CHECK_MESSAGE(detected == expected,
        "disjoint: " << id
        << " -> Expected: " << expected
        << " detected: " << detected);
}

template <typename P>
void test_all()
{
    typedef bg::model::box<P> box;

    test_disjoint<P, P>("pp1", "point(1 1)", "point(1 1)", false);
    test_disjoint<P, P>("pp2", "point(1 1)", "point(1.001 1)", true);

    // left-right
    test_disjoint<box, box>("bb1", "box(1 1, 2 2)", "box(3 1, 4 2)", true);
    test_disjoint<box, box>("bb2", "box(1 1, 2 2)", "box(2 1, 3 2)", false);
    test_disjoint<box, box>("bb3", "box(1 1, 2 2)", "box(2 2, 3 3)", false);
    test_disjoint<box, box>("bb4", "box(1 1, 2 2)", "box(2.001 2, 3 3)", true);

    // up-down
    test_disjoint<box, box>("bb5", "box(1 1, 2 2)", "box(1 3, 2 4)", true);
    test_disjoint<box, box>("bb6", "box(1 1, 2 2)", "box(1 2, 2 3)", false);
    // right-left
    test_disjoint<box, box>("bb7", "box(1 1, 2 2)", "box(0 1, 1 2)", false);
    test_disjoint<box, box>("bb8", "box(1 1, 2 2)", "box(0 1, 1 2)", false);

    // point-box
    test_disjoint<P, box>("pb1", "point(1 1)", "box(0 0, 2 2)", false);
    test_disjoint<P, box>("pb2", "point(2 2)", "box(0 0, 2 2)", false);
    test_disjoint<P, box>("pb3", "point(2.0001 2)", "box(1 1, 2 2)", true);
    test_disjoint<P, box>("pb4", "point(0.9999 2)", "box(1 1, 2 2)", true);

    // box-point (to test reverse compiling)
    test_disjoint<box, P>("bp1", "box(1 1, 2 2)", "point(2 2)", false);

    // Test triangles for polygons/rings, boxes
    // Note that intersections are tested elsewhere, they don't need
    // thorough test at this place
    typedef bg::model::polygon<P> polygon;
    typedef bg::model::ring<P> ring;

    // Four times same test with other types
    test_disjoint<polygon, polygon>("disjoint_simplex_pp", disjoint_simplex[0], disjoint_simplex[1], true);
    test_disjoint<ring, polygon>("disjoint_simplex_rp", disjoint_simplex[0], disjoint_simplex[1], true);
    test_disjoint<ring, ring>("disjoint_simplex_rr", disjoint_simplex[0], disjoint_simplex[1], true);
    test_disjoint<polygon, ring>("disjoint_simplex_pr", disjoint_simplex[0], disjoint_simplex[1], true);

    // Testing touch
    test_disjoint<polygon, polygon>("touch_simplex_pp", touch_simplex[0], touch_simplex[1], false);

    // Testing overlap (and test compiling with box)
    test_disjoint<polygon, polygon>("overlaps_box_pp", overlaps_box[0], overlaps_box[1], false);
    test_disjoint<box, polygon>("overlaps_box_bp", overlaps_box[0], overlaps_box[1], false);
    test_disjoint<box, ring>("overlaps_box_br", overlaps_box[0], overlaps_box[1], false);
    test_disjoint<polygon, box>("overlaps_box_pb", overlaps_box[1], overlaps_box[0], false);
    test_disjoint<ring, box>("overlaps_box_rb", overlaps_box[1], overlaps_box[0], false);

    // Test if within(a,b) returns false for disjoint
    test_disjoint<ring, ring>("within_simplex_rr1", within_simplex[0], within_simplex[1], false);
    test_disjoint<ring, ring>("within_simplex_rr2", within_simplex[1], within_simplex[0], false);

    // Linear
    typedef bg::model::linestring<P> ls;
    typedef bg::model::segment<P> segment;
    test_disjoint<ls, ls>("ls/ls 1", "linestring(0 0,1 1)", "linestring(1 0,0 1)", false);
    test_disjoint<ls, ls>("ls/ls 2", "linestring(0 0,1 1)", "linestring(1 0,2 1)", true);
    test_disjoint<segment, segment>("s/s 1", "linestring(0 0,1 1)", "linestring(1 0,0 1)", false);
    test_disjoint<segment, segment>("s/s 2", "linestring(0 0,1 1)", "linestring(1 0,2 1)", true);

    // Collinear opposite
    test_disjoint<ls, ls>("ls/ls co", "linestring(0 0,2 2)", "linestring(1 1,0 0)", false);
    // Collinear opposite and equal
    test_disjoint<ls, ls>("ls/ls co-e", "linestring(0 0,1 1)", "linestring(1 1,0 0)", false);

    // Problem described by Volker/Albert 2012-06-01
    test_disjoint<polygon, box>("volker_albert_1",
        "POLYGON((1992 3240,1992 1440,3792 1800,3792 3240,1992 3240))",
        "BOX(1941 2066, 2055 2166)", false);

    test_disjoint<polygon, box>("volker_albert_2",
        "POLYGON((1941 2066,2055 2066,2055 2166,1941 2166))",
        "BOX(1941 2066, 2055 2166)", false);

    // Degenerate linestrings
    {
        // Submitted by Zachary on the Boost.Geometry Mailing List, on 2012-01-29
        std::string const a = "linestring(100 10, 0 10)";
        std::string const b = "linestring(50 10, 50 10)"; // one point only, with same y-coordinate
        std::string const c = "linestring(100 10, 100 10)"; // idem, at left side
        test_disjoint<ls, ls>("dls/dls 1", a, b, false);
        test_disjoint<ls, ls>("dls/dls 2", b, a, false);
        test_disjoint<segment, segment>("ds/ds 1", a, b, false);
        test_disjoint<segment, segment>("ds/ds 2", b, a, false);
        test_disjoint<ls, ls>("dls/dls 1", a, c, false);
    }

    // Linestrings making angles normally ignored
    {
        // These (non-disjoint) cases
        // correspond to the test "segment_intersection_collinear"

        // Collinear ('a')
        //       a1---------->a2
        // b1--->b2
        test_disjoint<ls, ls>("n1", "linestring(2 0,0 6)", "linestring(0 0,2 0)", false);

        //       a1---------->a2
        //                    b1--->b2
        test_disjoint<ls, ls>("n7", "linestring(2 0,6 0)", "linestring(6 0,8 0)", false);

        // Collinear - opposite ('f')
        //       a1---------->a2
        // b2<---b1
        test_disjoint<ls, ls>("o1", "linestring(2 0,6 0)", "linestring(2 0,0 0)", false);
    }

    {
        // Starting in the middle ('s')
        //           b2
        //           ^
        //           |
        //           |
        // a1--------b1----->a2
        test_disjoint<ls, ls>("case_s", "linestring(0 0,4 0)", "linestring(2 0,2 2)", false);

        // Collinear, but disjoint
        test_disjoint<ls, ls>("c-d", "linestring(2 0,6 0)", "linestring(7 0,8 0)", true);

        // Parallel, disjoint
        test_disjoint<ls, ls>("c-d", "linestring(2 0,6 0)", "linestring(2 1,6 1)", true);

        // Error still there until 1.48 (reported "error", was reported to disjoint, so that's why it did no harm)
        test_disjoint<ls, ls>("case_recursive_boxes_1",
            "linestring(10 7,10 6)", "linestring(10 10,10 9)", true);

    }

    // TODO test_disjoint<segment, ls>("s/ls 1", "linestring(0 0,1 1)", "linestring(1 0,0 1)", false);
    // TODO test_disjoint<segment, ls>("s/ls 2", "linestring(0 0,1 1)", "linestring(1 0,2 1)", true);
    // TODO test_disjoint<ls, segment>("ls/s 1", "linestring(0 0,1 1)", "linestring(1 0,0 1)", false);
    // TODO test_disjoint<ls, segment>("ls/s 2", "linestring(0 0,1 1)", "linestring(1 0,2 1)", true);

}

int test_main(int, char* [])
{
    test_all<bg::model::d2::point_xy<float> >();
    test_all<bg::model::d2::point_xy<double> >();

#ifdef HAVE_TTMATH
    test_all<bg::model::d2::point_xy<ttmath_big> >();
#endif

    return 0;
}


#ifndef _3FENGINE_SRC_UTILS_F_VERTICES_HPP_
#define _3FENGINE_SRC_UTILS_F_VERTICES_HPP_

#include <vector>
#include <Eigen/Dense>

namespace fengine
{
	template<typename T, int base>
	class FVertices
	{
	public:
		FVertices() = default;
		~FVertices() = default;

		using Vector = std::vector <T>;
		using Vertex = Eigen::Matrix<T, base, 1>;

		FVertices(const Vector& in_vertices)
		{
			static_assert(base != 0, "Base size cannot be zero.");
			this->Add(in_vertices);
		}

		void Add(const Vector& to_insert)
		{
			auto to_insert_size = to_insert.size();
			assert(to_insert_size % base == 0);

			this->vec_.reserve(this->vec_.size() + to_insert_size);
			this->vec_.insert(this->vec_.end(), to_insert.cbegin(), to_insert.cend());

			this->points_count_ = vec_.size() / base;
		}

		const Vector& vec() const noexcept { return vec_; }

		int points_count() const noexcept { return points_count_; }

		Vertex GetVerticeByIndex(int index) const
		{
			auto verticesSize = vec_.size();
			if (index < 0 || index >= verticesSize)
			{
				LOG(FATAL) << "Index out of range";
			}
			auto fromIndex = index * base;

			Vertex result;
			for (auto i = 0; i < base; i++) {
				result(i) = vec_.at(fromIndex + i);
			}
			return result;
		}

	private:
		Vector vec_;
		size_t points_count_;
	};

}

#endif // _3FENGINE_SRC_UTILS_F_VERTICES_HPP_


#pragma once
#ifndef WTL_EIGEN_HPP_
#define WTL_EIGEN_HPP_

#include <cstdint>
#include <vector>
#include <valarray>
#include <string>
#include <istream>
#include <Eigen/Core>

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
namespace wtl { namespace eigen {
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

template <class T> inline
std::vector<typename T::value_type> vector(const T& vec) {
    return std::vector<typename T::value_type>(vec.data(), vec.data() + vec.size());
}

template <class T> inline
std::valarray<typename T::value_type> valarray(const T& vec) {
    return std::valarray<typename T::value_type>(vec.data(), vec.size());
}

template <class T> inline
Eigen::Array<typename T::value_type, Eigen::Dynamic, 1> ArrayX(const T& vec) {
    return Eigen::Array<typename T::value_type, Eigen::Dynamic, 1>::Map(vec.data(), vec.size());
}

template <class T> inline
Eigen::Matrix<typename T::value_type, Eigen::Dynamic, 1> VectorX(const T& vec) {
    return Eigen::Matrix<typename T::value_type, Eigen::Dynamic, 1>::Map(vec.data(), vec.size());
}

template <class T> inline
Eigen::Matrix<typename T::value_type, 1, Eigen::Dynamic> RowVectorX(const T& vec) {
    return Eigen::Matrix<typename T::value_type, 1, Eigen::Dynamic>::Map(vec.data(), vec.size());
}

template <class T> inline
Eigen::Array<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
ArrayXX(const std::vector<std::string>& rows) {
    const size_t nrow = rows.size();
    const size_t ncol = rows[0].length();
    Eigen::Array<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> array(nrow, ncol);
    for (size_t i=0; i<nrow; ++i) {
        const std::string& s = rows[i];
        const auto bytes = std::vector<uint8_t>(s.begin(), s.end());
        array.row(i) = RowVectorX(bytes).cast<T>();
    }
    // ASCII: char(0, 1) <=> int(48, 49)
    return array -= 48;
}

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

template <class Vector> inline
std::vector<size_t> which(const Vector& predicate) {
    std::vector<size_t> indices;
    const size_t n = predicate.size();
    indices.reserve(n);
    for (size_t i=0; i<n; ++i) {
        if (predicate[i] > 0) {indices.push_back(i);}
    }
    return indices;
}

template <class T, class Vector> inline
T slice(const Eigen::DenseBase<T>& orig, const Vector& indices) {
    const size_t n = indices.size();
    T result(n, orig.cols());
    for (size_t i=0; i<n; ++i) {
        result.row(i) = orig.row(indices[i]);
    }
    return result;
}

template <class T, class Vector> inline
T slice_cols(const Eigen::DenseBase<T>& orig, const Vector& indices) {
    const size_t n = indices.size();
    T result(orig.rows(), n);
    for (size_t i=0; i<n; ++i) {
        result.col(i) = orig.col(indices[i]);
    }
    return result;
}

template <class T, class Vector> inline
T filter(const Eigen::DenseBase<T>& orig, const Vector& predicate) {
    return slice(orig, which(predicate));
}

template <class T, class Vector> inline
T select(const Eigen::DenseBase<T>& orig, const Vector& predicate) {
    return slice_cols(orig, which(predicate));
}

inline Eigen::IOFormat tsv(const int precision=Eigen::StreamPrecision, const std::string& sep="\t") {
    return {precision, Eigen::DontAlignCols, sep, "\n"};
}

template <class T> inline
std::vector<Eigen::Array<typename T::value_type, Eigen::Dynamic, 1, Eigen::ColMajor>>
columns(const Eigen::DenseBase<T>& matrix) {
    const size_t n = matrix.cols();
    std::vector<Eigen::Array<typename T::value_type, Eigen::Dynamic, 1, Eigen::ColMajor>> result;
    result.reserve(n);
    for (size_t i=0; i<n; ++i) {
        result.push_back(matrix.col(i));
    }
    return result;
}

template <class T> inline
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
read_matrix(std::istream& fin, size_t ncol) {
    std::vector<T> vec{std::istream_iterator<T>(fin), std::istream_iterator<T>()};
    if (vec.size() % ncol > 0) {
        std::string msg = std::string(__PRETTY_FUNCTION__);
        throw std::runtime_error(msg + ": vec.size() % ncol > 0");
    }
    return Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>::Map(vec.data(), vec.size() / ncol, ncol);
}

template <class T> inline
Eigen::Array<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
read_array(std::istream& fin, size_t ncol) {
    std::vector<T> vec{std::istream_iterator<T>(fin), std::istream_iterator<T>()};
    if (vec.size() % ncol > 0) {
        std::string msg = std::string(__PRETTY_FUNCTION__);
        throw std::runtime_error(msg + ": vec.size() % ncol > 0");
    }
    return Eigen::Array<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>::Map(vec.data(), vec.size() / ncol, ncol);
}

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
}} // namespace wtl::eigen
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

#endif // WTL_EIGEN_HPP_


#pragma once

#ifndef BOOST_TEST_MODULE
#error BOOST_TEST_MODULE is not defined when exprtest.hpp is included!
#endif

#include "matheval.hpp"
#include <boost/test/included/unit_test.hpp>
#include <boost/math/constants/constants.hpp>
#include <string>

#define EXPRTEST(casename, expr, expected)                             \
BOOST_AUTO_TEST_CASE( casename )                                       \
{                                                                      \
    std::string const s = expr;                                        \
    std::map<std::string, double> st;                        \
    double result;                                                     \
    BOOST_CHECK_NO_THROW(result = matheval::parse(s, st));     \
    BOOST_CHECK_CLOSE(result, (expected),                              \
                      std::numeric_limits<double>::epsilon());         \
}

#define SYMEXPRTEST(casename, expr, st, expected)                      \
BOOST_AUTO_TEST_CASE( casename )                                       \
{                                                                      \
    std::string const s = expr;                                        \
    double result;                                                     \
    BOOST_CHECK_NO_THROW(result = matheval::parse(s, st));     \
    BOOST_CHECK_CLOSE(result, (expected),                              \
                      std::numeric_limits<double>::epsilon());         \
}

#define THROWTEST(casename, expr, expected)			       \
BOOST_AUTO_TEST_CASE( casename )				       \
{                                                                      \
    std::string const s = expr;					       \
    std::map<std::string, double> st;				       \
    BOOST_REQUIRE_THROW(matheval::parse(s, st), expected);	       \
}


#include <cmath>
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <algorithm>
#include <stdlib.h>
#include <boost/range/algorithm.hpp>
#include <boost/integer/common_factor_rt.hpp>

using namespace std;

int P, Q, R;

int main() {

    while (cin >> P >> Q >> R) {
        cout << (P + Q + R - max(max(P, Q), R)) << endl;
    }

    return 0;
}


/* boost random/linear_congruential.hpp header file
 *
 * Copyright Jens Maurer 2000-2001
 * 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)
 *
 * See http://www.boost.org for most recent version including documentation.
 *
 * $Id$
 *
 * Revision history
 *  2001-02-18  moved to individual header files
 */

#ifndef BOOST_RANDOM_LINEAR_CONGRUENTIAL_HPP
#define BOOST_RANDOM_LINEAR_CONGRUENTIAL_HPP

#include <iostream>
#include <stdexcept>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/limits.hpp>
#include <boost/static_assert.hpp>
#include <boost/integer/static_log2.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
#include <boost/random/detail/config.hpp>
#include <boost/random/detail/const_mod.hpp>
#include <boost/random/detail/seed.hpp>
#include <boost/random/detail/seed_impl.hpp>
#include <boost/detail/workaround.hpp>

#include <boost/random/detail/disable_warnings.hpp>

namespace boost {
namespace random {

/**
 * Instantiations of class template linear_congruential_engine model a
 * \pseudo_random_number_generator. Linear congruential pseudo-random
 * number generators are described in:
 *
 *  @blockquote
 *  "Mathematical methods in large-scale computing units", D. H. Lehmer,
 *  Proc. 2nd Symposium on Large-Scale Digital Calculating Machines,
 *  Harvard University Press, 1951, pp. 141-146
 *  @endblockquote
 *
 * Let x(n) denote the sequence of numbers returned by some pseudo-random
 * number generator. Then for the linear congruential generator,
 * x(n+1) := (a * x(n) + c) mod m. Parameters for the generator are
 * x(0), a, c, m. The template parameter IntType shall denote an integral
 * type. It must be large enough to hold values a, c, and m. The template
 * parameters a and c must be smaller than m.
 *
 * Note: The quality of the generator crucially depends on the choice of
 * the parameters. User code should use one of the sensibly parameterized
 * generators such as minstd_rand instead.
 */
template<class IntType, IntType a, IntType c, IntType m>
class linear_congruential_engine
{
public:
    typedef IntType result_type;

    // Required for old Boost.Random concept
    BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);

    BOOST_STATIC_CONSTANT(IntType, multiplier = a);
    BOOST_STATIC_CONSTANT(IntType, increment = c);
    BOOST_STATIC_CONSTANT(IntType, modulus = m);
    BOOST_STATIC_CONSTANT(IntType, default_seed = 1);

    BOOST_STATIC_ASSERT(std::numeric_limits<IntType>::is_integer);
    BOOST_STATIC_ASSERT(m == 0 || a < m);
    BOOST_STATIC_ASSERT(m == 0 || c < m);

    /**
     * Constructs a @c linear_congruential_engine, using the default seed
     */
    linear_congruential_engine() { seed(); }

    /**
     * Constructs a @c linear_congruential_engine, seeding it with @c x0.
     */
    BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(linear_congruential_engine,
                                               IntType, x0)
    { seed(x0); }

    /**
     * Constructs a @c linear_congruential_engine, seeding it with values
     * produced by a call to @c seq.generate().
     */
    BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(linear_congruential_engine,
                                             SeedSeq, seq)
    { seed(seq); }

    /**
     * Constructs a @c linear_congruential_engine  and seeds it
     * with values taken from the itrator range [first, last)
     * and adjusts first to point to the element after the last one
     * used.  If there are not enough elements, throws @c std::invalid_argument.
     *
     * first and last must be input iterators.
     */
    template<class It>
    linear_congruential_engine(It& first, It last)
    {
        seed(first, last);
    }

    // compiler-generated copy constructor and assignment operator are fine

    /**
     * Calls seed(default_seed)
     */
    void seed() { seed(default_seed); }

    /**
     * If c mod m is zero and x0 mod m is zero, changes the current value of
     * the generator to 1. Otherwise, changes it to x0 mod m. If c is zero,
     * distinct seeds in the range [1,m) will leave the generator in distinct
     * states. If c is not zero, the range is [0,m).
     */
    BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(linear_congruential_engine, IntType, x0)
    {
        // wrap _x if it doesn't fit in the destination
        if(modulus == 0) {
            _x = x0;
        } else {
            _x = x0 % modulus;
        }
        // handle negative seeds
        if(_x <= 0 && _x != 0) {
            _x += modulus;
        }
        // adjust to the correct range
        if(increment == 0 && _x == 0) {
            _x = 1;
        }
        BOOST_ASSERT(_x >= (min)());
        BOOST_ASSERT(_x <= (max)());
    }

    /**
     * Seeds a @c linear_congruential_engine using values from a SeedSeq.
     */
    BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(linear_congruential_engine, SeedSeq, seq)
    { seed(detail::seed_one_int<IntType, m>(seq)); }

    /**
     * seeds a @c linear_congruential_engine with values taken
     * from the itrator range [first, last) and adjusts @c first to
     * point to the element after the last one used.  If there are
     * not enough elements, throws @c std::invalid_argument.
     *
     * @c first and @c last must be input iterators.
     */
    template<class It>
    void seed(It& first, It last)
    { seed(detail::get_one_int<IntType, m>(first, last)); }

    /**
     * Returns the smallest value that the @c linear_congruential_engine
     * can produce.
     */
    static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
    { return c == 0 ? 1 : 0; }
    /**
     * Returns the largest value that the @c linear_congruential_engine
     * can produce.
     */
    static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
    { return modulus-1; }

    /** Returns the next value of the @c linear_congruential_engine. */
    IntType operator()()
    {
        _x = const_mod<IntType, m>::mult_add(a, _x, c);
        return _x;
    }

    /** Fills a range with random values */
    template<class Iter>
    void generate(Iter first, Iter last)
    { detail::generate_from_int(*this, first, last); }

    /** Advances the state of the generator by @c z. */
    void discard(boost::uintmax_t z)
    {
        typedef const_mod<IntType, m> mod_type;
        IntType b_inv = mod_type::invert(a-1);
        IntType b_gcd = mod_type::mult(a-1, b_inv);
        if(b_gcd == 1) {
            IntType a_z = mod_type::pow(a, z);
            _x = mod_type::mult_add(a_z, _x,
                mod_type::mult(mod_type::mult(c, b_inv), a_z - 1));
        } else {
            // compute (a^z - 1)*c % (b_gcd * m) / (b / b_gcd) * inv(b / b_gcd)
            // we're storing the intermediate result / b_gcd
            IntType a_zm1_over_gcd = 0;
            IntType a_km1_over_gcd = (a - 1) / b_gcd;
            boost::uintmax_t exponent = z;
            while(exponent != 0) {
                if(exponent % 2 == 1) {
                    a_zm1_over_gcd =
                        mod_type::mult_add(
                            b_gcd,
                            mod_type::mult(a_zm1_over_gcd, a_km1_over_gcd),
                            mod_type::add(a_zm1_over_gcd, a_km1_over_gcd));
                }
                a_km1_over_gcd = mod_type::mult_add(
                    b_gcd,
                    mod_type::mult(a_km1_over_gcd, a_km1_over_gcd),
                    mod_type::add(a_km1_over_gcd, a_km1_over_gcd));
                exponent /= 2;
            }

            IntType a_z = mod_type::mult_add(b_gcd, a_zm1_over_gcd, 1);
            IntType num = mod_type::mult(c, a_zm1_over_gcd);
            b_inv = mod_type::invert((a-1)/b_gcd);
            _x = mod_type::mult_add(a_z, _x, mod_type::mult(b_inv, num));
        }
    }

    friend bool operator==(const linear_congruential_engine& x,
                           const linear_congruential_engine& y)
    { return x._x == y._x; }
    friend bool operator!=(const linear_congruential_engine& x,
                           const linear_congruential_engine& y)
    { return !(x == y); }

#if !defined(BOOST_RANDOM_NO_STREAM_OPERATORS)
    /** Writes a @c linear_congruential_engine to a @c std::ostream. */
    template<class CharT, class Traits>
    friend std::basic_ostream<CharT,Traits>&
    operator<<(std::basic_ostream<CharT,Traits>& os,
               const linear_congruential_engine& lcg)
    {
        return os << lcg._x;
    }

    /** Reads a @c linear_congruential_engine from a @c std::istream. */
    template<class CharT, class Traits>
    friend std::basic_istream<CharT,Traits>&
    operator>>(std::basic_istream<CharT,Traits>& is,
               linear_congruential_engine& lcg)
    {
        lcg.read(is);
        return is;
    }
#endif

private:

    /// \cond show_private

    template<class CharT, class Traits>
    void read(std::basic_istream<CharT, Traits>& is) {
        IntType x;
        if(is >> x) {
            if(x >= (min)() && x <= (max)()) {
                _x = x;
            } else {
                is.setstate(std::ios_base::failbit);
            }
        }
    }

    /// \endcond

    IntType _x;
};

#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
//  A definition is required even for integral static constants
template<class IntType, IntType a, IntType c, IntType m>
const bool linear_congruential_engine<IntType, a, c, m>::has_fixed_range;
template<class IntType, IntType a, IntType c, IntType m>
const IntType linear_congruential_engine<IntType,a,c,m>::multiplier;
template<class IntType, IntType a, IntType c, IntType m>
const IntType linear_congruential_engine<IntType,a,c,m>::increment;
template<class IntType, IntType a, IntType c, IntType m>
const IntType linear_congruential_engine<IntType,a,c,m>::modulus;
template<class IntType, IntType a, IntType c, IntType m>
const IntType linear_congruential_engine<IntType,a,c,m>::default_seed;
#endif

/// \cond show_deprecated

// provided for backwards compatibility
template<class IntType, IntType a, IntType c, IntType m, IntType val = 0>
class linear_congruential : public linear_congruential_engine<IntType, a, c, m>
{
    typedef linear_congruential_engine<IntType, a, c, m> base_type;
public:
    linear_congruential(IntType x0 = 1) : base_type(x0) {}
    template<class It>
    linear_congruential(It& first, It last) : base_type(first, last) {}
};

/// \endcond

/**
 * The specialization \minstd_rand0 was originally suggested in
 *
 *  @blockquote
 *  A pseudo-random number generator for the System/360, P.A. Lewis,
 *  A.S. Goodman, J.M. Miller, IBM Systems Journal, Vol. 8, No. 2,
 *  1969, pp. 136-146
 *  @endblockquote
 *
 * It is examined more closely together with \minstd_rand in
 *
 *  @blockquote
 *  "Random Number Generators: Good ones are hard to find",
 *  Stephen K. Park and Keith W. Miller, Communications of
 *  the ACM, Vol. 31, No. 10, October 1988, pp. 1192-1201
 *  @endblockquote
 */
typedef linear_congruential_engine<uint32_t, 16807, 0, 2147483647> minstd_rand0;

/** The specialization \minstd_rand was suggested in
 *
 *  @blockquote
 *  "Random Number Generators: Good ones are hard to find",
 *  Stephen K. Park and Keith W. Miller, Communications of
 *  the ACM, Vol. 31, No. 10, October 1988, pp. 1192-1201
 *  @endblockquote
 */
typedef linear_congruential_engine<uint32_t, 48271, 0, 2147483647> minstd_rand;

#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T)
/**
 * Class @c rand48 models a \pseudo_random_number_generator. It uses
 * the linear congruential algorithm with the parameters a = 0x5DEECE66D,
 * c = 0xB, m = 2**48. It delivers identical results to the @c lrand48()
 * function available on some systems (assuming lcong48 has not been called).
 *
 * It is only available on systems where @c uint64_t is provided as an
 * integral type, so that for example static in-class constants and/or
 * enum definitions with large @c uint64_t numbers work.
 */
class rand48
{
public:
    typedef boost::uint32_t result_type;

    BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
    /**
     * Returns the smallest value that the generator can produce
     */
    static uint32_t min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; }
    /**
     * Returns the largest value that the generator can produce
     */
    static uint32_t max BOOST_PREVENT_MACRO_SUBSTITUTION ()
    { return 0x7FFFFFFF; }

    /** Seeds the generator with the default seed. */
    rand48() : lcf(cnv(static_cast<uint32_t>(1))) {}
    /**
     * Constructs a \rand48 generator with x(0) := (x0 << 16) | 0x330e.
     */
    BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(rand48, result_type, x0)
    { seed(x0); }
    /**
     * Seeds the generator with values produced by @c seq.generate().
     */
    BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(rand48, SeedSeq, seq)
    { seed(seq); }
    /**
     * Seeds the generator using values from an iterator range,
     * and updates first to point one past the last value consumed.
     */
    template<class It> rand48(It& first, It last) : lcf(first, last) { }

    // compiler-generated copy ctor and assignment operator are fine

    /** Seeds the generator with the default seed. */
    void seed() { seed(static_cast<uint32_t>(1)); }
    /**
     * Changes the current value x(n) of the generator to (x0 << 16) | 0x330e.
     */
    BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(rand48, result_type, x0)
    { lcf.seed(cnv(x0)); }
    /**
     * Seeds the generator using values from an iterator range,
     * and updates first to point one past the last value consumed.
     */
    template<class It> void seed(It& first, It last) { lcf.seed(first,last); }
    /**
     * Seeds the generator with values produced by @c seq.generate().
     */
    BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(rand48, SeedSeq, seq)
    { lcf.seed(seq); }

    /**  Returns the next value of the generator. */
    uint32_t operator()() { return static_cast<uint32_t>(lcf() >> 17); }

    /** Advances the state of the generator by @c z. */
    void discard(boost::uintmax_t z) { lcf.discard(z); }

    /** Fills a range with random values */
    template<class Iter>
    void generate(Iter first, Iter last)
    {
        for(; first != last; ++first) {
            *first = (*this)();
        }
    }

#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
    /**  Writes a @c rand48 to a @c std::ostream. */
    template<class CharT,class Traits>
    friend std::basic_ostream<CharT,Traits>&
    operator<<(std::basic_ostream<CharT,Traits>& os, const rand48& r)
    { os << r.lcf; return os; }

    /** Reads a @c rand48 from a @c std::istream. */
    template<class CharT,class Traits>
    friend std::basic_istream<CharT,Traits>&
    operator>>(std::basic_istream<CharT,Traits>& is, rand48& r)
    { is >> r.lcf; return is; }
#endif

    /**
     * Returns true if the two generators will produce identical
     * sequences of values.
     */
    friend bool operator==(const rand48& x, const rand48& y)
    { return x.lcf == y.lcf; }
    /**
     * Returns true if the two generators will produce different
     * sequences of values.
     */
    friend bool operator!=(const rand48& x, const rand48& y)
    { return !(x == y); }
private:
    /// \cond show_private
    typedef random::linear_congruential_engine<uint64_t,
        // xxxxULL is not portable
        uint64_t(0xDEECE66DUL) | (uint64_t(0x5) << 32),
        0xB, uint64_t(1)<<48> lcf_t;
    lcf_t lcf;

    static boost::uint64_t cnv(boost::uint32_t x)
    { return (static_cast<uint64_t>(x) << 16) | 0x330e; }
    /// \endcond
};
#endif /* !BOOST_NO_INT64_T && !BOOST_NO_INTEGRAL_INT64_T */

} // namespace random

using random::minstd_rand0;
using random::minstd_rand;
using random::rand48;

} // namespace boost

#include <boost/random/detail/enable_warnings.hpp>

#endif // BOOST_RANDOM_LINEAR_CONGRUENTIAL_HPP


/*!
 * @file
 * @brief
 * @copyright alphya 2021
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#ifndef NYARUGA_UTIL_ALGEBRA_HPP
#define NYARUGA_UTIL_ALGEBRA_HPP

#pragma once

#include <functional>
#include <iostream>
#include <concepts>
#include <ranges>
#include <ratio>
#include <complex>
#include <type_traits>
#include <array>
#include <algorithm>
#include <utility>
#include <boost/hana/functional/arg.hpp>

#include <nyaruga_util/config.hpp>

#ifdef NYARUGA_UTIL_HAS_TCBRINDLER_RATIONAL
#    include <tcb/rational.hpp> // https://github.com/tcbrindle/rational.git
#endif

namespace nyaruga {

namespace util {

namespace detail {

template <std::unsigned_integral  T = unsigned int>
struct N {
    using value_type = T;
    T value;
    friend constexpr auto operator<=>(const N&, const N&) noexcept = default;
    constexpr operator T() const noexcept { return value; }
    constexpr N(T&& v) noexcept : value(std::forward<decltype(v)>(v)) {}
};

template <std::floating_point T = double>
struct R {
    using value_type = T;
    T value;
    friend constexpr auto operator<=>(const R&, const R&) noexcept = default;
    constexpr operator T() const noexcept { return value; }
    constexpr R(T&& v) noexcept : value(std::forward<decltype(v)>(v)) {}
};

template <std::integral T = int>
struct Z {
    using value_type = T;
    T value;
    friend constexpr auto operator<=>(const Z&, const Z&) noexcept = default;
    constexpr operator T() const noexcept { return value; }
    constexpr Z(T&& v) noexcept : value(std::forward<decltype(v)>(v)) {}
};

template <typename T>
concept  arithmetic = std::is_arithmetic_v<T>;

} // namespace detail

// Number

using detail::N;

using detail::Z;

using detail::R;

#ifdef NYARUGA_UTIL_HAS_TCBRINDLER_RATIONAL
template <std::integral T = int>
using Q = tcb::rational<T>;
#endif

template <detail::arithmetic T = double>
using C = std::complex<T>;

namespace detail {

// 足し算ができる
template <class T, class U>
concept weak_addable = requires (const std::remove_reference_t<T>& a, const std::remove_reference_t<U>& b) {
  {a + b} -> std::common_with<T>;
  {b + a} -> std::common_with<T>;
  {a + b} -> std::common_with<U>;
  {b + a} -> std::common_with<U>;
};

// 引き算ができる
template <class T, class U>
concept weak_subtractable = requires (const std::remove_reference_t<T>& a, const std::remove_reference_t<U>& b) {
  {a - b} -> std::common_with<T>;
  {b - a} -> std::common_with<T>;
  {a - b} -> std::common_with<U>;
  {b - a} -> std::common_with<U>;
};

// 掛け算ができる
template <class T, class U>
concept weak_multipliable = requires (const std::remove_reference_t<T>& a, const std::remove_reference_t<U>& b) {
  {a * b} -> std::common_with<T>;
  {b * a} -> std::common_with<T>;
  {a * b} -> std::common_with<U>;
  {b * a} -> std::common_with<U>;
};

//割り算ができる
template <class T, class U>
concept weak_dividable = requires (const std::remove_reference_t<T>& a, const std::remove_reference_t<U>& b){
  {a / b} -> std::common_with<T>;
  {b / a} -> std::common_with<T>;
  {a / b} -> std::common_with<U>;
  {b / a} -> std::common_with<U>;
};

} // namespace detail

// concept

template <typename T>
concept addable = detail::weak_addable<T,T>;

template <typename T>
concept subtractable = detail::weak_subtractable<T,T>;

template <typename T>
concept multipliable = detail::weak_multipliable<T,T>;

template <typename T>
concept dividable = detail::weak_dividable<T,T>;

template <class T, class U>
concept addable_with =
  addable<T> &&
  addable<U> &&
  std::common_reference_with<
    const std::remove_reference_t<T>&,
    const std::remove_reference_t<U>&> &&
  addable<
    std::common_reference_t<
      const std::remove_reference_t<T>&,
      const std::remove_reference_t<U>&>> &&
  detail::weak_addable<T, U>;

template <class T, class U>
concept subtractable_with =
  subtractable<T> &&
  subtractable<U> &&
  std::common_reference_with<
    const std::remove_reference_t<T>&,
    const std::remove_reference_t<U>&> &&
  subtractable<
    std::common_reference_t<
      const std::remove_reference_t<T>&,
      const std::remove_reference_t<U>&>> &&
  detail::weak_subtractable<T, U>;

template <class T, class U>
concept multipliable_with =
  multipliable<T> &&
  multipliable<U> &&
  std::common_reference_with<
    const std::remove_reference_t<T>&,
    const std::remove_reference_t<U>&> &&
  multipliable<
    std::common_reference_t<
      const std::remove_reference_t<T>&,
      const std::remove_reference_t<U>&>> &&
  detail::weak_multipliable<T, U>;

template <class T, class U>
concept dividable_with =
  dividable<T> &&
  dividable<U> &&
  std::common_reference_with<
    const std::remove_reference_t<T>&,
    const std::remove_reference_t<U>&> &&
  dividable<
    std::common_reference_t<
      const std::remove_reference_t<T>&,
      const std::remove_reference_t<U>&>> &&
  detail::weak_dividable<T, U>;

template <typename T>
concept group = // std::equality_comparable<T> && // 等しさの検証が難しい対象もあるため ex) 関数環
                                 addable<T> &&
                                 subtractable<T>;

template <typename T>
concept abelian_group =  // C++ 上で普通の群と見分ける方法なし
                                 // std::equality_comparable<T> &&
                                 addable<T> &&
                                 subtractable<T>;

template <typename T>
concept ring = // std::equality_comparable<T> &&
                             addable<T> &&
                             subtractable<T> &&
                             multipliable<T>;

template <typename T>
concept commutative_ring =  // C++ 上で普通の環と見分ける方法なし
                             // std::equality_comparable<T> &&
                             addable<T> &&
                             subtractable<T> &&
                             multipliable<T>;

template <typename T>
concept field = // std::equality_comparable<T> &&
                              addable<T> &&
                              subtractable<T> &&
                              multipliable<T> &&
                              dividable<T>;

namespace detail {

template <ring A = R<double>, size_t rank = 1>
struct module : std::array<A, rank>
{
    using std::array<A,rank>::array;
    constexpr module() noexcept = default;
    constexpr module(const std::array<A,rank>& a) : std::array<A,rank>::array(a) {};
    constexpr module(std::array<A,rank>&& a) : std::array<A,rank>::array(std::move(a)) {};
    template <std::same_as<A> ... T>
    constexpr module(T ... list) : std::array<A,rank>::array({list...}) {};
    friend constexpr auto operator<=>(const module&, const module&) noexcept = default;

};

template <typename ... T>
module(T ... list) -> module<std::remove_cvref_t<decltype(boost::hana::arg<1>(list...))> ,sizeof...(list)>;

namespace my_detail {

template <typename T, size_t N, size_t... I>
constexpr std::array<std::remove_cv_t<T>, N>
    array_plus_impl(const std::array<T,N>& a, const std::array<T,N>& b, std::index_sequence<I...>)
{
    return { {(a[I]+b[I])...} };
}

template <typename T, size_t N, size_t... I>
constexpr std::array<std::remove_cv_t<T>, N>
    array_mult_impl(const T& a, const std::array<T,N>& b, std::index_sequence<I...>)
{
    return { {(a*b[I])...} };
}

}

template <typename T, size_t N>
constexpr module<T,N>  operator+(std::array<T,N>& a, std::array<T,N>& b)
{
    return my_detail::array_plus_impl(a, b,std::make_index_sequence<N>{});
}

template <typename T, size_t N>
constexpr module<T,N>  operator*(const T& a, std::array<T,N>& b)
{
    return my_detail::array_mult_impl(a, b,std::make_index_sequence<N>{});
}

} // namespace detail

// 加群
template <ring A, size_t rank>
using module_t = detail::module<A, rank>;

template <typename A, typename G>
concept module = ring<A> && abelian_group<G> &&
requires(const std::remove_reference_t<A>& a, const std::remove_reference_t<A>& b,
const std::remove_reference_t<G>& g, const std::remove_reference_t<G>&  h)
{
     {a*g} -> std::common_with<G>;
     {g+h} -> std::common_with<G>;
     {g-h} -> std::common_with<G>;
     {a+b} -> std::common_with<A>;
     {a*b}-> std::common_with<A>;
     // { (a + b)(g + h) == (a+b)*g+(a+b)*h };
};

// 多元環または代数(algebra) 係数環の可換性を確かめられないので、C++上だと加群と変わらず
template <commutative_ring A, size_t rank>
using algebra_t = detail::module<A, rank>;

template <typename A, typename G>
concept algebra = module<A,G>;

} // namespace util

} // namespace nyaruga

#endif // #ifndef NYARUGA_UTIL_ALGEBRA_HPP


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

  Program:   Visualization Toolkit
  Module:    vtkRansacPlaneModel.cxx
  Author: Pierre Guilbert

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.  See the above copyright notice for more information.

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

// LOCAL
#include "vtkRansacPlaneModel.h"

#include "vtkConversions.h"

// STD
#include <iostream>
#include <fstream>
#include <sstream>
#include <cmath>

// VTK
#include <vtkCellArray.h>
#include <vtkCellData.h>
#include <vtkDataArray.h>
#include <vtkFloatArray.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkMath.h>
#include <vtkNew.h>
#include <vtkObjectFactory.h>
#include <vtkPointData.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyLine.h>
#include <vtkSmartPointer.h>
#include <vtkStreamingDemandDrivenPipeline.h>
#include <vtkTransform.h>
#include <vtkTupleInterpolator.h>
#include <vtkUnsignedCharArray.h>
#include <vtkUnsignedIntArray.h>
#include <vtkUnsignedShortArray.h>

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

// Eigen
#include <Eigen/Dense>

//----------------------------------------------------------------------------
struct RansacSampleInfo
{
public:
  RansacSampleInfo() {}

  RansacSampleInfo(unsigned int nInliers, unsigned int index1,
                   unsigned int index2, unsigned int index3)
  {
    this->NInliers = nInliers;
    this->Index1 = index1;
    this->Index2 = index2;
    this->Index3 = index3;
  }

  unsigned int NInliers;
  unsigned int Index1;
  unsigned int Index2;
  unsigned int Index3;
};

//----------------------------------------------------------------------------
void RefineRansac(std::vector<Eigen::Matrix<double, 3, 1> >& Points, vtkPolyData* output,
                  RansacSampleInfo sampleInfo, double threshold, double PlaneParam[4])
{
  // Create inliers / outliers array information
  vtkNew<vtkUnsignedIntArray> inliersArray;
  inliersArray->SetName("ransac_plane_inliers");

  // compute plane PlaneParameters
  Eigen::Matrix<double, 3, 1> pointPlane = Points[sampleInfo.Index1];
  Eigen::Matrix<double, 3, 1> normalPlane = (Points[sampleInfo.Index3] - pointPlane).cross(Points[sampleInfo.Index2] - pointPlane);
  normalPlane.normalize();

  // compute inliers
  std::vector<Eigen::Matrix<double, 3, 1> > inliersPoints;
  for (unsigned int k = 0; k < Points.size(); ++k)
  {
    if (std::abs((Points[k] - pointPlane).dot(normalPlane)) < threshold)
    {
      inliersPoints.push_back(Points[k]);
      inliersArray->InsertNextValue(1);
    }
    else
    {
      inliersArray->InsertNextValue(0);
    }
  }

  // Now, compute the best plane using all inliers
  Eigen::MatrixXd centeredSamples(3, inliersPoints.size());
  Eigen::Matrix<double, 3, 1> center = Eigen::Matrix<double, 3, 1>::Zero();
  for (unsigned int k = 0; k < inliersPoints.size(); ++k)
  {
    centeredSamples.col(k) = inliersPoints[k];
    center += inliersPoints[k];
  }
  center /= static_cast<double>(inliersPoints.size());
  for (unsigned int k = 0; k < inliersPoints.size(); ++k)
  {
    centeredSamples.col(k) -= center;
  }
  Eigen::Matrix<double, 3, 3> varianceCovariance = centeredSamples * centeredSamples.transpose();
  varianceCovariance /= static_cast<double>(inliersPoints.size());

  // since the variance covariance matrix is a real
  // symmetric matrix it can be diagonalized in a orthonormal
  // basis. We will use the AutoAdjoint eigen solver
  Eigen::SelfAdjointEigenSolver<Eigen::Matrix<double, 3, 3> > eigenSolver(varianceCovariance);

  // PlaneParameters
  normalPlane = eigenSolver.eigenvectors().col(0);
  pointPlane = center;
  PlaneParam[0] = normalPlane(0);
  PlaneParam[1] = normalPlane(1);
  PlaneParam[2] = normalPlane(2);
  PlaneParam[3] = -normalPlane.dot(pointPlane);

  output->GetPointData()->AddArray(inliersArray.Get());
}

//----------------------------------------------------------------------------
unsigned int ComputeNumberOfInlier(std::vector<Eigen::Matrix<double, 3, 1> >& Points, Eigen::Matrix<double, 3, 1> planePoint,
                                   Eigen::Matrix<double, 3, 1> planeNormal, double threshold)
{
  unsigned int nInliers = 0;
  for (unsigned int k = 0; k < Points.size(); ++k)
  {
    if (std::abs((Points[k] - planePoint).dot(planeNormal)) < threshold)
    {
      nInliers++;
    }
  }

  return nInliers;
}

// Implementation of the New function
vtkStandardNewMacro(vtkRansacPlaneModel)

//----------------------------------------------------------------------------
vtkRansacPlaneModel::vtkRansacPlaneModel()
{
  // 500 maximal ransac iteration
  this->MaxRansacIteration = 500;

  // 50 cm distance to plane threshold
  this->Threshold = 0.5;

  // 30% of inliers required
  this->RatioInliersRequired = 0.30;

  // fill PlaneParams with 0 values
  std::fill(this->PlaneParam, this->PlaneParam + 4, 0);

  this->AlignOutput = false;
  this->TemporalAveraging = true;
  this->MaxTemporalAngleChange = 45.0;
  this->PreviousEstimationWeight = 0.9;
}

//----------------------------------------------------------------------------
vtkRansacPlaneModel::~vtkRansacPlaneModel()
{
}

//-----------------------------------------------------------------------------
void vtkRansacPlaneModel::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

//-----------------------------------------------------------------------------
int vtkRansacPlaneModel::RequestData(vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector, vtkInformationVector *outputVector)
{
  // Save the previous plane estimate
  double prevPlaneEst[4];
  std::copy(this->PlaneParam, this->PlaneParam + 4, prevPlaneEst);

  // Get the input
  vtkPolyData * input = vtkPolyData::GetData(inputVector[0]->GetInformationObject(0));

  // Get the output
  vtkPolyData *output = vtkPolyData::GetData(outputVector->GetInformationObject(0));
  output->ShallowCopy(input);

  // Convert the point cloud in Eigen data structure point cloud
  std::vector<Eigen::Vector3d> Points = vtkPointsToEigenVector(input->GetPoints());

  // Create a random order of points index
  std::vector<double> randomIndex(input->GetNumberOfPoints(), 0);
  for (unsigned int k = 0; k < randomIndex.size(); ++k)
  {
    randomIndex[k] = k;
  }
  std::random_shuffle(randomIndex.begin(), randomIndex.end());

  // information variable about ransac iterations
  bool shouldStopRansac = false;
  unsigned int iterationMade = 0;
  unsigned int iterationPointer = 0;

  // keep information of iterations
  std::vector<RansacSampleInfo> samplesInfo;
  unsigned int maxInliers = 0;
  unsigned int indexMaxInliers = 0;

  // Affine plane PlaneParameters
  Eigen::Matrix<double, 3, 1> planeNormal, planePoint;

  // indicate if ransac has "converged"
  bool hasConverged = false;

  // Ransac loop
  while (!shouldStopRansac)
  {
    // if we went throught the all random index we need
    // to random shuffle again
    if ((iterationPointer + 2) >= randomIndex.size())
    {
      std::random_shuffle(randomIndex.begin(), randomIndex.end());
      iterationPointer = 0;
    }

    // Compute current sample plane PlaneParameters
    planePoint = Points[randomIndex[iterationPointer]];
    planeNormal = (Points[randomIndex[iterationPointer + 2]] - planePoint).cross(Points[randomIndex[iterationPointer + 1]] - planePoint);
    planeNormal.normalize();

    // Compute the number of inliers / outliers
    unsigned int nInliers = ComputeNumberOfInlier(Points, planePoint, planeNormal, this->Threshold);

    // keep info
    RansacSampleInfo info(nInliers, randomIndex[iterationPointer], randomIndex[iterationPointer + 1], randomIndex[iterationPointer + 2]);
    samplesInfo.push_back(info);

    if (nInliers > maxInliers)
    {
      maxInliers = nInliers;
      indexMaxInliers = iterationMade;
    }

    // Check that the number of inliers is enought to
    // break the ransac algorithm loop
    if (nInliers > input->GetNumberOfPoints() * this->RatioInliersRequired)
    {
      shouldStopRansac = true;
      hasConverged = true;
    }

    // check if the maximum iteration has been reached
    if (iterationMade > this->MaxRansacIteration)
    {
      shouldStopRansac = true;
    }

    // Updates iterations index
    iterationMade++;
    iterationPointer += 3;
  }

  // Now refine using all inliers
  RefineRansac(Points, output, samplesInfo[indexMaxInliers], this->Threshold, this->PlaneParam);

  // output info
  std::cout << "ransac algorithm has converged: " << hasConverged << std::endl;
  std::cout << "number of iteration made: " << iterationMade << std::endl;
  std::cout << "number of inliers: " << maxInliers << ", " << samplesInfo[indexMaxInliers].NInliers << std::endl;
  std::cout << "plane PlaneParams: [" << this->PlaneParam[0] << "," << this->PlaneParam[1] << "," << this->PlaneParam[2] << "," << this->PlaneParam[3] << "]" << std::endl;

  // flip normal if needed
  if (this->PlaneParam[2] < 0)
  {
    this->PlaneParam[0] *= -1.0;
    this->PlaneParam[1] *= -1.0;
    this->PlaneParam[2] *= -1.0;
    this->PlaneParam[3] *= -1.0;
  }

  double d = this->PlaneParam[3];
  Eigen::Vector3d n(this->PlaneParam[0], this->PlaneParam[1], this->PlaneParam[2]);
  n.normalize();

  // previous normal and bias estimation
  Eigen::Vector3d nPrev(prevPlaneEst[0], prevPlaneEst[1], prevPlaneEst[2]);
  double dPrev = prevPlaneEst[3];

  double newEstimationWeight = 1.0 - this->PreviousEstimationWeight;  // how much do we trust the new plane estimate

  if (this->TemporalAveraging && std::abs(nPrev.norm() - 1) < 1e-3)   // if the previous estimate is valid
  {
    // if the angle between the new normal estimate and the previous is larger than the threshold,
    // the current normal is discarded
    if (std::asin(n.cross(nPrev).norm()) > vtkMath::RadiansFromDegrees(MaxTemporalAngleChange))
    {
      n = nPrev;
      d = dPrev;
    }
    else
    {
      // update the plane estimate with the current one
      n = newEstimationWeight * n + this->PreviousEstimationWeight * nPrev;
      d = newEstimationWeight * d + this->PreviousEstimationWeight * dPrev;
    }
  }
  n.normalize();

  this->PlaneParam[0] = n[0];
  this->PlaneParam[1] = n[1];
  this->PlaneParam[2] = n[2];
  this->PlaneParam[3] = d;

  // transform output if enabled
  if (this->AlignOutput)
  {
    Eigen::Vector3d v = n.cross(Eigen::Vector3d::UnitZ());
    double angle = std::asin(v.norm());
    Eigen::AngleAxisd rot(angle, v.normalized());
    Eigen::Vector3d shift(0.0, 0.0, d);

    // transform points
    for (auto& pt : Points)
    {
      pt =  rot * pt + shift;
    }
    // copy points to output
    output->SetPoints(eigenVectorToVTKPoints(Points));
  }

  return 1;
}


// This file has been modified from the source file that is from NetKet proejct
// that is under Apache 2.0 Lisence. The original file header follows.
// Copyright 2018 The Simons Foundation, Inc. - All Rights Reserved.
//
// 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.

#ifndef YANNQ_FULLCONNLAYER_HH
#define YANNQ_FULLCONNLAYER_HH

#include <Eigen/Dense>
#include <complex>
#include <fstream>
#include <random>
#include <string>
#include <vector>
#include <nlohmann/json.hpp>

#include <Utilities/Utility.hpp>
#include "AbstractLayer.hpp"

namespace yannq {

template<typename T>
class FullyConnected : public AbstractLayer<T>
{
public:
	using Scalar = T;
	using Vector = typename AbstractLayer<T>::Vector;
	using Matrix = typename AbstractLayer<T>::Matrix;
	using VectorRef = typename AbstractLayer<T>::VectorRef;
	using VectorConstRef = typename AbstractLayer<T>::VectorConstRef;

private:
	bool useBias_;

	uint32_t inputDim_;        // input size
	uint32_t outputDim_;       // output size
	uint32_t npar_;           // number of parameters in layer

	Matrix weight_;  // Weight parameters, W(in_size x out_size)
	Vector bias_;    // Bias parameters, b(out_size x 1)
	// Note that input of this layer is also the output of
	// previous layer

public:
	/// Constructor
	FullyConnected(const uint32_t inputDim, const uint32_t outputDim,
			const bool useBias = false)
		: useBias_(useBias), inputDim_(inputDim), outputDim_(outputDim)
	{
		weight_.resize(inputDim_, outputDim_);

		npar_ = inputDim_ * outputDim_;

		if (useBias_) {
			npar_ += outputDim_;
			bias_.resize(outputDim_);
		}
		bias_.setZero();
	}

	FullyConnected(const FullyConnected& ) = default;
	FullyConnected(FullyConnected&& ) = default;

	FullyConnected& operator=(const FullyConnected&) = default;
	FullyConnected& operator=(FullyConnected&&) = default;

	bool operator==(const FullyConnected& rhs) const
	{
		return (weight_ == rhs.weight_) && (bias_ == rhs.bias_);
	}

	bool operator!=(const FullyConnected& rhs) const
	{
		return !(*this == rhs);
	}

	std::string name() const override { return "Fully Connected Layer"; }

	nlohmann::json desc() const override
	{
		nlohmann::json res;
		res["name"] = name();
		res["use_bias"] = useBias_;
		res["input_dim"] = inputDim_;
		res["output_dim"] = outputDim_;
		return res;
	}

	template<class RandomEngine>
	void randomizeParams(RandomEngine&& re, remove_complex_t<Scalar> sigma)
	{
		setParams(randomVector<T>(std::forward<RandomEngine>(re), sigma, npar_));
	}

	uint32_t paramDim() const override { return npar_; }

	uint32_t inputDim() const { return inputDim_; }

	uint32_t outputDim(uint32_t inputDim) const override {
		(void)inputDim;
		assert(inputDim == inputDim_);
		return outputDim_;
	}

	Vector getParams() const override
	{
		Vector res(npar_);
		res.head(inputDim_*outputDim_) = Eigen::Map<const Vector>(weight_.data(), inputDim_*outputDim_);

		if (useBias_)
		{
			res.tail(outputDim_) = Eigen::Map<const Vector>(bias_.data(), outputDim_);
		}
		return res;
	}

	void setParams(VectorConstRef pars) override
	{
		Eigen::Map<Vector>(weight_.data(), inputDim_*outputDim_) =
			pars.head(inputDim_*outputDim_);
		if (useBias_)
		{
			bias_ = pars.segment(inputDim_*outputDim_, outputDim_);
		}
	}

	void updateParams(VectorConstRef ups) override
	{
		Eigen::Map<Vector>(weight_.data(), inputDim_*outputDim_) +=
			ups.head(inputDim_*outputDim_);
		if (useBias_)
		{
			bias_ += ups.segment(inputDim_*outputDim_, outputDim_);
		}
	}

	// Feedforward
	void forward(const VectorConstRef& input, VectorRef output) override
	{
		if(useBias_)
			output = bias_;
		else
			output.setZero();
		output.noalias() += weight_.transpose() * input;
	}

	// Computes derivative.
	void backprop(const VectorConstRef& prev_layer_output,
			const VectorConstRef& /*this_layer_output*/,
			const VectorConstRef& dout,
			VectorRef din, VectorRef der) override
	{
		// dout = d(L) / d(z)
		// Derivative for bias, d(L) / d(b) = d(L) / d(z)
		//
		// Derivative for weights, d(L) / d(W) = [d(L) / d(z)] * in'
		Eigen::Map<Matrix> der_w{der.data(), inputDim_, outputDim_};

		der_w.noalias() = prev_layer_output * dout.transpose();

		if (useBias_) {
			der.tail(outputDim_) = dout;
		}

		// Compute d(L) / d_in = W * [d(L) / d(z)]
		din.noalias() = weight_ * dout;
	}

	uint32_t fanIn() override
	{
		return inputDim_;
	}
	uint32_t fanOut() override
	{
		return outputDim_;
	}
};

}  // namespace yannq

#endif


/*

Copyright (c) 2005-2018, University of Oxford.
All rights reserved.

University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.

This file is part of Chaste.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
 * Neither the name of the University of Oxford nor the names of its
   contributors may be used to endorse or promote products derived from this
   software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef CELLWISESOURCEELLIPTICPDE_HPP_
#define CELLWISESOURCEELLIPTICPDE_HPP_

#include "ChasteSerialization.hpp"
#include <boost/serialization/base_object.hpp>

#include "AbstractCellPopulation.hpp"
#include "AbstractLinearEllipticPde.hpp"

/**
 * An elliptic PDE to be solved numerically using the finite element method, for
 * coupling to a cell-based simulation.
 *
 * The PDE takes the form
 *
 * Grad.(Grad(u)) + k*u*rho(x) = 0,
 *
 * where the scalar k is specified by the member mSourceCoefficient, whose value must
 * be set in the constructor.
 *
 * For a node of the finite element mesh with location x, the function rho(x)
 * equals one if there is a non-apoptotic cell associated with x, and
 * zero otherwise. Here, 'associated with' takes a different meaning for each
 * cell population class, and is encoded in the method IsPdeNodeAssociatedWithNonApoptoticCell().
 *
 * \todo make member names and methods consistent with those of CellwiseSourceParabolicPde
 */
template<unsigned DIM>
class CellwiseSourceEllipticPde : public AbstractLinearEllipticPde<DIM,DIM>
{
    friend class TestCellBasedEllipticPdes;

private:

    /** Needed for serialization.*/
    friend class boost::serialization::access;
    /**
     * Serialize the PDE and its member variables.
     *
     * @param archive the archive
     * @param version the current version of this class
     */
    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
       archive & boost::serialization::base_object<AbstractLinearEllipticPde<DIM, DIM> >(*this);
       archive & mSourceCoefficient;
    }

protected:

    /** The cell population member. */
    AbstractCellPopulation<DIM, DIM>& mrCellPopulation;

    /** Coefficient of the source term. */
    double mSourceCoefficient;

public:

    /**
     * Constructor.
     *
     * @param rCellPopulation reference to the cell population
     * @param sourceCoefficient the source term coefficient (defaults to 0.0)
     */
    CellwiseSourceEllipticPde(AbstractCellPopulation<DIM, DIM>& rCellPopulation, double sourceCoefficient=0.0);

    /**
     * @return const reference to the cell population (used in archiving).
     */
    const AbstractCellPopulation<DIM>& rGetCellPopulation() const;

    /**
     * @return mSourceCoefficient (used in archiving).
     */
    double GetCoefficient() const;

    /**
     * Overridden ComputeConstantInUSourceTerm() method.
     *
     * @param rX The point in space
     * @param pElement The element
     *
     * @return the constant in u part of the source term, i.e g(x) in
     *  Div(D Grad u)  +  f(x)u + g(x) = 0.
     */
    virtual double ComputeConstantInUSourceTerm(const ChastePoint<DIM>& rX, Element<DIM,DIM>* pElement);

    /**
     * Overridden ComputeLinearInUCoeffInSourceTerm() method.
     *
     * @param rX The point in space
     * @param pElement the element
     *
     * @return the coefficient of u in the linear part of the source term, i.e f(x) in
     *  Div(D Grad u)  +  f(x)u + g(x) = 0.
     */
    virtual double ComputeLinearInUCoeffInSourceTerm(const ChastePoint<DIM>& rX, Element<DIM,DIM>* pElement);

    /**
     * Overridden ComputeLinearInUCoeffInSourceTermAtNode() method.
     *
     * @param rNode reference to the node
     * @return the coefficient of u in the linear part of the source term, i.e f(x) in
     *  Div(D Grad u)  +  f(x)u + g(x) = 0.
     */
    virtual double ComputeLinearInUCoeffInSourceTermAtNode(const Node<DIM>& rNode);

    /**
     * Overridden ComputeDiffusionTerm() method.
     *
     * @param rX The point in space at which the diffusion term is computed
     *
     * @return a matrix.
     */
    virtual c_matrix<double,DIM,DIM> ComputeDiffusionTerm(const ChastePoint<DIM>& rX);
};

#include "SerializationExportWrapper.hpp"
EXPORT_TEMPLATE_CLASS_SAME_DIMS(CellwiseSourceEllipticPde)

namespace boost
{
namespace serialization
{
/**
 * Serialize information required to construct a CellwiseSourceEllipticPde.
 */
template<class Archive, unsigned DIM>
inline void save_construct_data(
    Archive & ar, const CellwiseSourceEllipticPde<DIM>* t, const unsigned int file_version)
{
    // Save data required to construct instance
    const AbstractCellPopulation<DIM, DIM>* p_cell_population = &(t->rGetCellPopulation());
    ar & p_cell_population;
}

/**
 * De-serialize constructor parameters and initialise a CellwiseSourceEllipticPde.
 */
template<class Archive, unsigned DIM>
inline void load_construct_data(
    Archive & ar, CellwiseSourceEllipticPde<DIM>* t, const unsigned int file_version)
{
    // Retrieve data from archive required to construct new instance
    AbstractCellPopulation<DIM, DIM>* p_cell_population;
    ar >> p_cell_population;

    // Invoke inplace constructor to initialise instance
    ::new(t)CellwiseSourceEllipticPde<DIM>(*p_cell_population);
}
}
} // namespace ...

#endif /*CELLWISESOURCEELLIPTICPDE_HPP_*/


//
// Copyright 2019 Olzhas Zhumabek <anonymous.from.applecity@gmail.com>
//
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include <boost/gil/detail/math.hpp>
#include <boost/gil/image_processing/numeric.hpp>

#include <boost/core/lightweight_test.hpp>

#include <algorithm>

namespace gil = boost::gil;

void test_dx_sobel_kernel()
{
    const auto kernel = gil::generate_dx_sobel(1);
    BOOST_TEST(std::equal(kernel.begin(), kernel.end(), gil::dx_sobel.begin()));
}

void test_dx_scharr_kernel()
{
    const auto kernel = gil::generate_dx_scharr(1);
    BOOST_TEST(std::equal(kernel.begin(), kernel.end(), gil::dx_scharr.begin()));
}

void test_dy_sobel_kernel()
{
    const auto kernel = gil::generate_dy_sobel(1);
    BOOST_TEST(std::equal(kernel.begin(), kernel.end(), gil::dy_sobel.begin()));
}

void test_dy_scharr_kernel()
{
    const auto kernel = gil::generate_dy_scharr(1);
    BOOST_TEST(std::equal(kernel.begin(), kernel.end(), gil::dy_scharr.begin()));
}

int main()
{
    test_dx_sobel_kernel();
    test_dx_scharr_kernel();
    test_dy_sobel_kernel();
    test_dy_scharr_kernel();
    return boost::report_errors();
}


// #define TIME

#include "core.h"

#include <cstdlib>
#include <cstring>
#include <ctime>
#include <Eigen/SVD>
#include <enhancer/enhancerwidget.hpp>
#include <imagedistance.hpp>
#include <mathtoolbox/classical-mds.hpp>
#include "mainwindow.h"
#include "image.h"
#include "eigenutility.h"
#include "metriclearning.h"

using std::vector;
using std::pair;
using std::string;
using std::shared_ptr;
using Eigen::VectorXd;
using Eigen::MatrixXd;

Core::Core() :
    featureDim(5),
    nReferencePhotos(10),
    currentIndex(0),
    isBaselineMode(false),
    uiSize(0),
    useVisualization(true),
    useOptimization(false),
    useInitialOptimization(false),
    useSortingPhotos(false),
    nIterations(1),
    gradationResolution(40)
{
    srand(time(NULL));
}

void Core::setParameters(const std::vector<double>& parameters)
{
    parameters_ = parameters;
    previewWidget->setParameters(parameters_);
}

void Core::setReferencePhotos()
{
    vector<shared_ptr<QImage>> referenceImages;

    // If this is the baseline mode, show reference images in the original order
    if (isBaselineMode)
    {
        for (int i = enhancedImages.size() - 1; i >= 0; -- i) referenceImages.push_back(enhancedImages[i]);
        mainWindow->setReferencePhotos(referenceImages);
        return;
    }

    // If this is the standard mode, sort the images by using the distances
    vector<pair<double, unsigned>> distances(currentIndex);
    const unsigned n = std::min<unsigned>(nReferencePhotos, enhancedImages.size());
    for (unsigned i = 0; i < currentIndex; ++ i)
    {
        const double d = (images[i]->getFeatureVector() - images[currentIndex]->getFeatureVector()).squaredNorm();
        distances[i] = pair<double, unsigned>(d, i);
    }
    partial_sort(distances.begin(), distances.begin() + n, distances.end());
    for (unsigned i = 0; i < n; ++ i)
    {
        referenceImages.push_back(enhancedImages[distances[i].second]);
    }
    mainWindow->setReferencePhotos(referenceImages);
}

namespace
{

inline vector<double> computeDistanceBetweenImages(const shared_ptr<Image> a, const shared_ptr<Image> b)
{
    const Eigen::VectorXd distance_vector = imagedistance::CalcDistances(*(a->getHistogram()), *(b->getHistogram()));

    assert(distance_vector.size() == 38);

    vector<double> d(38);
    std::memcpy(d.data(), distance_vector.data(), sizeof(double) * 38);

    return d;
}

inline Core::Distance computeImageDistances(const vector<shared_ptr<Image>>& images)
{
    const unsigned n = images.size();
    Core::Distance D_images(n);
    for (unsigned i = 0; i < n; ++ i)
    {
        D_images[i].resize(n);
        for (unsigned j = 0; j < n; ++ j)
        {
            D_images[i][j] = computeDistanceBetweenImages(images[i], images[j]);
        }
    }
    return D_images;
}

inline MatrixXd computeParameterDistances(const vector<VectorXd>& params)
{
    const unsigned n = params.size();
    MatrixXd D(n, n);
    for (unsigned i = 0; i < n; ++ i) for (unsigned j = i; j < n; ++ j)
    {
        const double d = (params[i] - params[j]).norm();
        D(i, j) = d;
        D(j, i) = d;
    }
    return D;
}

MatrixXd correctRotation(const MatrixXd& X, const vector<shared_ptr<Image>>& images)
{
    // Find the optimal rotation
    MatrixXd A = MatrixXd::Zero(X.rows(), X.rows());
    for (unsigned i = 0; i < X.cols() - 1; ++ i)
    {
        VectorXd p = images[i]->getFeatureVector();
        VectorXd q = X.col(i);
        A += p * q.transpose();
    }
    Eigen::JacobiSVD<MatrixXd> svd(A, Eigen::ComputeFullU);
    MatrixXd R = svd.matrixU();
    return R * X;
}

}

void Core::computeMDS()
{
    // set the distance matrix
    unsigned n = currentIndex + 1;
    D.resize(n, n);
    for (unsigned i = 0; i < n; ++ i)
    {
        for (unsigned j = i; j < n; ++ j)
        {
            const double d  = computeDistance(alpha, distance, i, j);
            const double d2 = d * d;

            // Note: D needs to have the squared norms for MDS
            D(i, j) = d2;
            D(j, i) = d2;
        }
    }

    // Compute the MDS algorithm
#ifdef TIME
    const auto t1 = system_clock::now();
#endif
    const MatrixXd X = mathtoolbox::ComputeClassicalMds(D, std::min<unsigned>(featureDim, D.rows()));
#ifdef TIME
    const auto t2 = system_clock::now();
    std::cout << "Metric MDS: " << duration_cast<milliseconds>(t2 - t1).count() << " [ms]" << std::endl;
#endif

    // Correct the rotation (optional)
    const MatrixXd Y = (featureDim == 2 && n > 2) ? correctRotation(X, images) : X;

    // set the results to the images
    for (unsigned i = 0; i < n; ++ i)
    {
        images[i]->setFeatureVector(Y.col(i));
    }
}

void Core::computeMetricLearning()
{
    // If this is the first time to compute, initialize the alpha
    if (alpha.rows() != 38)
    {
        alpha = VectorXd::Zero(38);
    }

    // Prepare distances
    const MatrixXd D_params = computeParameterDistances(goodnessFunction.pList); // TODO: This can be incrementally updated

    // Compute the metric learning
    alpha = MetricLearning::computeMetricLearning(distance, D_params, alpha, goodnessFunction.pList.size());
}

void Core::initialize(const string& dirPath)
{
    // Prepare working directories
    generateDirectories();

    // Import photos
    importPhotos(dirPath);

    // Compute (unlearned) distances between photos
    distance = computeImageDistances(images);
    exportRawDistance();

    // Set the first photo to the UI
    previewWidget->setImage(*images[currentIndex]->getScaledQImage());

    // Prepare data for study (for the first time only)
    studyData.resize(images.size());

    // Start study
    const VectorXd x = EigenUtility::std2eigen(parameters_);
    getCurrentStudyData().confidence         = confidence;
    getCurrentStudyData().autoParameter      = x;
    getCurrentStudyData().naiveAutoParameter = x;
    getCurrentStudyData().index              = currentIndex;
    getCurrentStudyData().targetImage        = images[currentIndex];
    getCurrentStudyData().parameterSequence.push_back(x);
    time_point = std::chrono::system_clock::now();
}

VectorXd Core::getCurrentFeatureVector() const
{
    return images[currentIndex]->getFeatureVector();
}

double Core::computeConfidence(unsigned index) const
{
    const VectorXd&         feature      = images[index]->getFeatureVector();
    const vector<VectorXd>& prevFeatures = goodnessFunction.getFeatureList();

    if (prevFeatures.size() < 2)
    {
        return 0.0;
    }

    // compute distances
    vector<double> distances;
    for (const VectorXd& f : prevFeatures)
    {
        distances.push_back((feature - f).norm());
    }

    // sort them
    partial_sort(distances.begin(), distances.begin() + 1, distances.end());

    // compute confidence
    return pow(1.0 / (1.0 + distances[0]), 3.0);
}

bool Core::goNext()
{
    const VectorXd x = EigenUtility::std2eigen(parameters_);
    const shared_ptr<Image> currentImage = images[currentIndex];

    // for study
    getCurrentStudyData().elapsedTime    = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - time_point).count();
    getCurrentStudyData().userParameter  = x;
    getCurrentStudyData().visualized     = useVisualization;
    getCurrentStudyData().optimized      = useOptimization;
    getCurrentStudyData().print();
    getCurrentStudyData().exportModifiedScaledPhoto(workingDirectoryPath);

    // Finish the task
    if (currentIndex + 1 == images.size())
    {
        return finishTask();
    }

    // Go next
    currentIndex ++;

#ifdef TIME
    auto t1 = std::chrono::system_clock::now();
#endif

    // Note: The parameters should be added before metric learning
    goodnessFunction.pList.push_back(x);

    // preference learning
    if (currentIndex > 1)
    {
        computeMetricLearning();
        computeMDS();
    }

    // Update the data points in the goodness function
    // Note: the parameters are already added
    goodnessFunction.fList.clear();
    for (unsigned i = 0; i < currentIndex; ++ i)
    {
        goodnessFunction.fList.push_back(images[i]->getFeatureVector());
    }

    // Compute the adaptive kernel density estimation
    goodnessFunction.computeCovariance();
    goodnessFunction.regularizeCovariance();

#ifdef TIME
    auto t2 = std::chrono::system_clock::now();
    std::cout << "Self-Reinforcement Process: " << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count() << " [ms]" << std::endl;
#endif

    // sort the rest of photos
    if (useSortingPhotos)
    {
        unsigned optimalIndex = currentIndex;
        double   optimalConf  = computeConfidence(optimalIndex);
        for (unsigned i = currentIndex + 1; i < images.size(); ++ i)
        {
            const double conf = computeConfidence(i);
            if (conf > optimalConf)
            {
                optimalConf  = conf;
                optimalIndex = i;
            }
        }
        const auto tmp = images[currentIndex];
        images[currentIndex] = images[optimalIndex];
        images[optimalIndex] = tmp;
    }

    const shared_ptr<Image> nextImage = images[currentIndex];

    // confidence
    confidence = computeConfidence(currentIndex);
    mainWindow->updateConfidenceValueInUI(confidence);

    // compute local/global best/worst values
    localMax  = goodnessFunction.getValue(goodnessFunction.getBestParameterSet(getCurrentFeatureVector()), getCurrentFeatureVector());
    localMin  = goodnessFunction.getValue(goodnessFunction.getBestParameterSet(getCurrentFeatureVector(), true), getCurrentFeatureVector());

    // Compute optimal parameters for the next photo
    const VectorXd opt = goodnessFunction.getBestParameterSet(getCurrentFeatureVector());
    if (useInitialOptimization)
    {
        setParameters(EigenUtility::eigen2std(opt));
    }
    else
    {
        setParameters(vector<double>(parameterDim, 0.5));
    }

    // Update preview
    previewWidget->setImage(*nextImage->getScaledQImage());

    // Store the enhanced photo
    enhancedImages.push_back(currentImage->getModifiedScaledQImage(x));

    // Update the reference photos
    setReferencePhotos();

    // For study
    getCurrentStudyData().confidence         = confidence;
    getCurrentStudyData().autoParameter      = opt;
    getCurrentStudyData().naiveAutoParameter = goodnessFunction.getAverageParameterSet();
    getCurrentStudyData().index              = currentIndex;
    getCurrentStudyData().targetImage        = images[currentIndex];
    getCurrentStudyData().parameterSequence.push_back(x);
    time_point = std::chrono::system_clock::now();

    // Export embedded map
    exportMap();

    return true;
}

void Core::optimizeParameters(int exclusiveParameter)
{
    // Just return when there is no sufficient data
    if (currentIndex < 2) return;

    const double   scale     = confidence / (localMax - localMin);
    const VectorXd p_current = EigenUtility::std2eigen(parameters_);
    const VectorXd f         = images[currentIndex]->getFeatureVector();

    VectorXd p_new     = goodnessFunction.applyGradientAscent(p_current, f, scale);
    p_new(exclusiveParameter) = parameters_[exclusiveParameter];
    setParameters(EigenUtility::eigen2std(p_new));
}

//////////////////////////////////////////////
// user interface
//////////////////////////////////////////////

int Core::getSizeOfFont() const
{
    const static int sizes[] = { 13, 18, 24, 32 };
    return sizes[uiSize];
}

int Core::getSizeOfVisualizationHeight() const
{
    const static int heights[] = { 30, 36, 42, 50 };
    return heights[uiSize];
}

int Core::getSizeOfButtonHeight() const
{
    const static int heights[] = { 32, 42, 46, 54 };
    return heights[uiSize];
}

int Core::getSizeOfTextBoxWidth() const
{
    const static int widths[] = { 36, 48, 60, 76 };
    return widths[uiSize];
}

int Core::getSizeOfTextBoxHeight() const
{
    const static int heights[] = { 24, 28, 32, 40 };
    return heights[uiSize];
}

int Core::getSizeOfScrollAreaWidth() const
{
    const static int widths[] = { 340, 400, 480, 560 };
    return widths[uiSize];
}


#include <iostream>
#include <boost/numeric/mtl/mtl.hpp>

int main(int, char**)
{
    using namespace mtl; using mtl::iall;

    typedef std::complex<double>      cdouble;
    const unsigned                    xd= 2, yd= 5, n= xd * yd;
    dense2D<cdouble>                  A(n, n);
    mat::laplacian_setup(A, xd, yd);

    // Fill imaginary part of the matrix
    A*= cdouble(1, -1);
    std::cout << "A is\n" << with_format(A, 7, 1) << "\n";

    std::cout << "sub_matrix(A, 2, 4, 1, 7) is\n"
	      << with_format(sub_matrix(A, 2, 4, 1, 7), 7, 1) << "\n";

    //col-vector from matrix
    dense_vector<cdouble>   v_c(A[iall][0]);

    std::cout << "col-vector v_c is\n" << v_c << "\n";

    //row-vector from matrix
    dense_vector<cdouble, mtl::vec::parameters<tag::row_major> > v_r(A[0][iall]);

    std::cout << "row-vector v_r is\n" << v_r << "\n";

    //row-vector in matrix
    RowInMatrix<dense2D<cdouble> >::type v_r2(A[0][iall]);

    std::cout << "row-vector v_r2 is\n" << v_r2 << "\n";

    //submatrix from matrix per begin and end of row and column
    dense2D<cdouble> B= sub_matrix(A, 2, 4, 1, 7);
    B[1][2]= 88;

    std::cout << "B is\n" << B << "\n";

    //submatrix from matrix per irange
    using mtl::irange;
    irange row(2, 4), col(1, 7);
    dense2D<cdouble> B1= A[row][col];

    std::cout << "B1 is\n" << B1 << "\n";

    //scalar from matrix
    cdouble C= A[1][1];

    std::cout << "C is\n" << C << "\n";

    return 0;
}


// Define this to enable debugging
// #define BOOST_SPIRIT_QI_DEBUG

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/optional.hpp>

#include <iostream>
#include <string>

namespace ast
{
    struct Nil;

    struct Signed;

    struct Expression;

    struct RightAssocExpr;

    struct Arg;

    struct FunctionCall;

    typedef boost::variant<
            Nil
          , double
          , boost::recursive_wrapper< Signed >
          , boost::recursive_wrapper< Expression >
          , boost::recursive_wrapper< RightAssocExpr >
          , boost::recursive_wrapper< Arg >
          , boost::recursive_wrapper< FunctionCall >
        >
    Operand;

    struct Nil
    {
    };

    inline std::ostream & operator<<( std::ostream & out, Nil ) { out << "nil"; return out; }

    struct Signed
    {
        char sign_;
        Operand operand_;
    };

    struct Arg
    {
        char digit_;
    };

    struct RightAssocExpr
    {
        Operand left_;
        boost::optional< Operand > right_;
    };

    struct FunctionCall
    {
        std::string name_;
        Operand arg_;
    };

    struct Operation
    {
        std::string operator_;
        Operand operand_;
    };

    struct Expression
    {
        Operand head_;
        std::list< Operation > tail_;
    };

}

BOOST_FUSION_ADAPT_STRUCT(
    ast::Signed,
    ( char, sign_ )
    ( ast::Operand, operand_ )
)

BOOST_FUSION_ADAPT_STRUCT(
    ast::Arg,
    ( char, digit_ )
)

BOOST_FUSION_ADAPT_STRUCT(
    ast::RightAssocExpr,
    ( ast::Operand, left_ )
    ( boost::optional< ast::Operand >, right_ )
)

BOOST_FUSION_ADAPT_STRUCT(
    ast::FunctionCall,
    ( std::string, name_ )
    ( ast::Operand, arg_ )
)

BOOST_FUSION_ADAPT_STRUCT(
    ast::Operation,
    ( std::string, operator_ )
    ( ast::Operand, operand_ )
)

BOOST_FUSION_ADAPT_STRUCT(
    ast::Expression,
    ( ast::Operand, head_ )
    ( std::list< ast::Operation >, tail_ )
)

namespace ast
{
    struct Calc
    {
    public:

        typedef double result_type;

    private:

        template< typename... TDoubles >
        void assign( double * args, int index, double head, TDoubles &&... tail )
        {
            args[ index ] = head;
            assign( args, index+1, std::forward< TDoubles >( tail )... );
        }

        void assign( double * args, int index )
        {
        }

    public:

        template< typename... Doubles >
        Calc( Doubles &&... ds )
        {
            static_assert( sizeof...( Doubles ) < 10, "sizeof...(Doubles) has to be less then 10" );
            args_[ 0 ] = sizeof...( Doubles );

            assign( & args_[ 0 ], 1, std::forward< Doubles >( ds )... );
        }

        double operator()( Nil ) const
        {
            BOOST_ASSERT( 0 ); return 0;
        }

        double operator()( double n ) const
        {
            return n;
        }

        double operator()( Operation const & x, double lhs ) const
        {
            if( x.operator_ == "&&" )
            {
                if( fabs( lhs ) < 0.000001 ){
                    return 0;
                }
                else{
                    return boost::apply_visitor( *this, x.operand_ );
                }
            }

            if( x.operator_ == "||" )
            {
                if( fabs( lhs ) < 0.000001 ){
                    return boost::apply_visitor( *this, x.operand_ );
                }
                else{
                    return lhs;
                }
            }

            double const rhs = boost::apply_visitor( *this, x.operand_ );

            if( x.operator_ == "+" ){
                return lhs + rhs;
            }

            if( x.operator_ == "-" ){
                return lhs - rhs;
            }

            if( x.operator_ == "*" ){
                return lhs * rhs;
            }

            if( x.operator_ == "/" ){
                return lhs / rhs;
            }

            if( x.operator_ == "<" ){
                return lhs < rhs;
            }

            if( x.operator_ == "<=" ){
                return lhs <= rhs;
            }

            if( x.operator_ == ">" ){
                return lhs > rhs;
            }

            if( x.operator_ == ">=" ){
                return lhs >= rhs;
            }

            if( x.operator_ == "==" ){
                return lhs == rhs;
            }

            if( x.operator_ == "!=" ){
                return lhs != rhs;
            }

            return 0;
        }

        double operator()( Signed const & x ) const
        {
            double const rhs = boost::apply_visitor( *this, x.operand_ );

            switch( x.sign_ )
            {
                case '-':
                    return - rhs;

                case '+':
                    return + rhs;

                case '!':
                    return ( fabs( rhs ) < 0.000001 ) ? 1 : 0;

                default:
                    BOOST_ASSERT( 0 );
            }
        }

        double operator()( Arg const & x ) const
        {
            return args_[ x.digit_ - '0' ];
        }

        double operator()( RightAssocExpr const & x ) const
        {
            double const base = boost::apply_visitor( *this, x.left_ );

            if( ! x.right_ ){
                return base;
            }

            double const exp = boost::apply_visitor( *this, x.right_.get() );

            return std::pow( base, exp );
        }

        double operator()( FunctionCall const & x ) const
        {
            if( x.name_ == "pi" ){
                return M_PI;
            }

            if( x.name_ == "e" ){
                return std::exp( 1.0 );
            }

            double const arg = boost::apply_visitor( *this, x.arg_ );

            if( x.name_ == "sin" ){
                return sin( arg );
            }

            if( x.name_ == "cos" ){
                return cos( arg );
            }

            if( x.name_ == "tan" ){
                return tan( arg );
            }

            if( x.name_ == "abs" ){
                return fabs( arg );
            }

            if( x.name_ == "rad" ){
                return arg * 2 * M_PI / 360;
            }

            if( x.name_ == "deg" ){
                return arg * 360 / 2 / M_PI;
            }

            if( x.name_ == "log" ){
                return log( arg );
            }

            if( x.name_ == "log10" ){
                return log10( arg );
            }

            if( x.name_ == "log2" ){
                return log2( arg );
            }

            return 0;
        }

        double operator()( Expression const & x ) const
        {
            double state = boost::apply_visitor( *this, x.head_ );

            for( Operation const & oper : x.tail_ )
            {
                state = ( *this )( oper, state );
            }

            return state;
        }

    private:

        double args_[ 10 ];
    };
}

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
using boost::phoenix::function;

struct error_handler_
{
    template< typename, typename, typename >
    struct result { typedef void type; };

    template< typename TIterator >
    void operator()(
        qi::info const & what
      , TIterator err_pos, TIterator last ) const
    {
        std::cout
            << "Error! Expecting "
            << what
            << " here: \""
            << std::string( err_pos, last )
            << "\""
            << std::endl
        ;
    }
};

function< error_handler_ > const error_handler = error_handler_();

template< typename TIterator >
struct Calculator
    : qi::grammar< TIterator, ast::Expression(), ascii::space_type >
{
    Calculator()
        : Calculator::base_type( expression )
    {
        qi::char_type char_;
        qi::digit_type digit_;
        qi::double_type double_;
        qi::lit_type lit_;
        qi::string_type string_;
        qi::alpha_type alpha_;
        qi::alnum_type alnum_;

        using qi::on_error;
        using qi::fail;
        using qi::lexeme;

        expression =
            relationalExpression
            >> *(   (string_( "&&" ) > relationalExpression )
                |   (string_( "||" ) > relationalExpression )
                )
            ;

        relationalExpression =
            additiveExpression
            >> *(   (string_( "<=" ) > additiveExpression )
                |   (string_( "<" ) > additiveExpression )
                |   (string_( ">=" ) > additiveExpression )
                |   (string_( ">" ) > additiveExpression )
                |   (string_( "!=" ) > additiveExpression )
                |   (string_( "==" ) > additiveExpression )
                )
            ;

        additiveExpression =
            multiplicativeExpression
            >> *(   (char_( '+' ) > multiplicativeExpression )
                |   (char_( '-' ) > multiplicativeExpression )
                )
            ;

        multiplicativeExpression =
            exponentialExpression
            >> *(   ( char_( '*' ) > exponentialExpression )
                |   ( char_( '/' ) > exponentialExpression )
                )
            ;

        exponentialExpression =
            unaryExpression
            >> -( '^' >> exponentialExpression );

        unaryExpression =
                ( char_( '-' ) > unaryExpression )
            |   ( char_( '+' ) > unaryExpression )
            |   ( char_( '!' ) > unaryExpression )
            |   primaryExpression
            ;

        primaryExpression =
                double_
            |   arg
            |   functionCall
            |   '(' > expression > ')'
            ;

        arg =
            ( '_' > digit_ )
            ;

        functionCall =
            ( +alnum_ > '(' > -unaryExpression > ')' )
            ;

        BOOST_SPIRIT_DEBUG_NODE( expression );
        BOOST_SPIRIT_DEBUG_NODE( relationalExpression );
        BOOST_SPIRIT_DEBUG_NODE( additiveExpression );
        BOOST_SPIRIT_DEBUG_NODE( multiplicativeExpression );
        BOOST_SPIRIT_DEBUG_NODE( exponentialExpression );
        BOOST_SPIRIT_DEBUG_NODE( unaryExpression );
        BOOST_SPIRIT_DEBUG_NODE( primaryExpression );
        BOOST_SPIRIT_DEBUG_NODE( arg );
        BOOST_SPIRIT_DEBUG_NODE( functionCall );

        on_error< fail >(
            expression,
            error_handler( qi::_4_type(), qi::_3_type(), qi::_2_type() )
        );
    }

private:

    qi::rule< TIterator, ast::Expression(), ascii::space_type > expression;
    qi::rule< TIterator, ast::Expression(), ascii::space_type > relationalExpression;
    qi::rule< TIterator, ast::Expression(), ascii::space_type > additiveExpression;
    qi::rule< TIterator, ast::Expression(), ascii::space_type > multiplicativeExpression;
    qi::rule< TIterator, ast::RightAssocExpr(), ascii::space_type > exponentialExpression;
    qi::rule< TIterator, ast::Operand(), ascii::space_type > unaryExpression;
    qi::rule< TIterator, ast::Operand(), ascii::space_type > primaryExpression;
    qi::rule< TIterator, ast::Arg(), ascii::space_type > arg;
    qi::rule< TIterator, ast::FunctionCall(), ascii::space_type > functionCall;
};

template< typename... TDoubles>
double calc(
    std::string const & expr,
    TDoubles... ds
)
{
    std::string::const_iterator iter = expr.begin();
    std::string::const_iterator end = expr.end();

    Calculator< std::string::const_iterator > calc;

    boost::spirit::ascii::space_type space;

    ast::Expression expression;

    bool const r = phrase_parse( iter, end, calc, space, expression );

    if( r && iter == end )
    {
        ast::Calc calc( std::forward< TDoubles >( ds )... );
        return calc( expression );
    }

    throw std::runtime_error( "Parsing failed: " + std::string( iter, end ) );
}

void test()
{
    assert( calc( "1+2*3" ) == 7 );
    assert( calc( "2^3^2" ) == 512 );
    assert( calc( "(1+2)*(3+4)" ) == 21 );

    assert( calc( "1+-1" ) == 0 );
    assert( calc( "1--1" ) == 2 );

    assert( calc( "4/2" ) == 2 );
    assert( calc( "4.5/2" ) == 2.25 );
    assert( calc( "5/2" ) == 2.5 );

    assert( calc( "!1" ) == 0 );
    assert( calc( "!0" ) == 1 );

    assert( calc( "pi()" ) == double(M_PI) );
    assert( calc( "e()" ) == std::exp( 1.0 ) );

    assert( calc( "12||(1/0)" ) == 12 );
    assert( calc( "0&&(1/0)" ) == 0 );
    assert( calc( "1&&2" ) == 2 );
    assert( calc( "2||1" ) == 2 );
    assert( calc( "0||2" ) == 2 );

    assert( calc( "1<2" ) == 1 );
    assert( calc( "2<1" ) == 0 );

    assert( calc( "1>2" ) == 0 );
    assert( calc( "2>1" ) == 1 );

    assert( calc( "1<=2" ) == 1 );
    assert( calc( "2<=2" ) == 1 );
    assert( calc( "3<=2" ) == 0 );

    assert( calc( "1>=2" ) == 0 );
    assert( calc( "2>=2" ) == 1 );
    assert( calc( "3>=2" ) == 1 );

    assert( calc( "abs(1)" ) == 1 );
    assert( calc( "abs(-1)" ) == 1 );

    assert( calc( "sin(rad(0))" ) == 0 );
    assert(( fabs( calc( "sin(rad(90))" ) - 1.0 ) < 0.000001 ));

    assert( calc( "cos(rad(0))" ) == 1 );
    assert(( fabs( calc( "cos(rad(90))" ) - 0.0 ) < 0.0000001 ));

    assert( calc( "log10(1)" ) == 0 );
    assert( calc( "log10(10)" ) == 1 );
    assert( calc( "log10(100)" ) == 2 );

    assert( calc( "log2(1)" ) == 0 );
    assert( calc( "log2(2)" ) == 1 );
    assert( calc( "log2(4)" ) == 2 );

    assert( calc( "_1+_2+_3+_4+_5+_6+_7+_8+_9", 1, 2, 3, 4, 5, 6, 7, 8, 9 ) == 45 );
    assert( calc( "_0" ) == 0 );
    assert( calc( "_0", 1 ) == 1 );
    assert( calc( "_0", 1, 2 ) == 2 );
    assert( calc( "_0", 1, 2, 3 ) == 3 );
}

int main( int argc, char* argv[] )
{
    test();

    using std::cout;
    using std::endl;
    using std::stof;

    try
    {
        if( argc == 2 ){
            cout << calc( argv[1] ) << endl;
        }
        else if( argc == 3 ){
            cout << calc( argv[1], stof(argv[2]) ) << endl;
        }
        else if( argc == 4 ){
            cout << calc( argv[1], stof(argv[2]), stof(argv[3]) ) << endl;
        }
        else if( argc == 5 ){
            cout << calc( argv[1], stof(argv[2]), stof(argv[3]),
                stof(argv[4]) ) << endl;
        }
        else if( argc == 6 ){
            cout << calc( argv[1], stof(argv[2]), stof(argv[3]),
                stof(argv[4]), stof(argv[5]) ) << endl;
        }
        else if( argc == 7 ){
            cout << calc( argv[1], stof(argv[2]), stof(argv[3]),
                stof(argv[4]), stof(argv[5]), stof(argv[6]) ) << endl;
        }
        else if( argc == 8 ){
            cout << calc( argv[1], stof(argv[2]), stof(argv[3]),
                stof(argv[4]), stof(argv[5]), stof(argv[6]),
                stof(argv[7]) ) << endl;
        }
        else if( argc == 9 ){
            cout << calc( argv[1], stof(argv[2]), stof(argv[3]),
                stof(argv[4]), stof(argv[5]), stof(argv[6]),
                stof(argv[7]), stof(argv[8]) ) << endl;
        }
        else if( argc == 10 ){
            cout << calc( argv[1], stof(argv[2]), stof(argv[3]),
                stof(argv[4]), stof(argv[5]), stof(argv[6]),
                stof(argv[7]), stof(argv[8]), stof(argv[9]) ) << endl;
        }
        else if( argc == 11 ){
            cout << calc( argv[1], stof(argv[2]), stof(argv[3]),
                stof(argv[4]), stof(argv[5]), stof(argv[6]),
                stof(argv[7]), stof(argv[8]), stof(argv[9]),
                stof(argv[10]) ) << endl;
        }
    }
    catch( std::runtime_error const & e ){
        std::cerr << e.what() << std::endl;
    }
}