// Boost.Polygon library polygon_interval_test.cpp file

//          Copyright Andrii Sydorchuk 2012.
// 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 updates, documentation, and revision history.

#define BOOST_TEST_MODULE POLYGON_INTERVAL_TEST
#include <boost/mpl/list.hpp>
#include <boost/test/test_case_template.hpp>

#include "boost/polygon/interval_concept.hpp"
#include "boost/polygon/interval_data.hpp"
#include "boost/polygon/interval_traits.hpp"
using namespace boost::polygon;

typedef boost::mpl::list<int> test_types;

BOOST_AUTO_TEST_CASE_TEMPLATE(interval_data_test, T, test_types) {
  typedef interval_data<T> interval_type;
  interval_type interval1(1, 2);
  interval_type interval2;
  interval2 = interval1;

  BOOST_CHECK_EQUAL(interval1.low(), 1);
  BOOST_CHECK_EQUAL(interval1.high(), 2);
  BOOST_CHECK_EQUAL(interval1.get(LOW), 1);
  BOOST_CHECK_EQUAL(interval1.get(HIGH), 2);
  BOOST_CHECK(interval1 == interval2);
  BOOST_CHECK(!(interval1 != interval2));
  BOOST_CHECK(!(interval1 < interval2));
  BOOST_CHECK(!(interval1 > interval2));
  BOOST_CHECK(interval1 <= interval2);
  BOOST_CHECK(interval1 >= interval2);

  interval1.low(2);
  interval1.high(1);
  BOOST_CHECK_EQUAL(interval1.low(), 2);
  BOOST_CHECK_EQUAL(interval1.high(), 1);
  BOOST_CHECK(!(interval1 == interval2));
  BOOST_CHECK(interval1 != interval2);

  interval2.set(LOW, 2);
  interval2.set(HIGH, 1);
  BOOST_CHECK(interval1 == interval2);
}

BOOST_AUTO_TEST_CASE_TEMPLATE(interval_traits_test, T, test_types) {
  typedef interval_data<T> interval_type;

  interval_type interval = interval_mutable_traits<interval_type>::construct(1, 2);
  BOOST_CHECK_EQUAL(interval_traits<interval_type>::get(interval, LOW), 1);
  BOOST_CHECK_EQUAL(interval_traits<interval_type>::get(interval, HIGH), 2);

  interval_mutable_traits<interval_type>::set(interval, LOW, 3);
  interval_mutable_traits<interval_type>::set(interval, HIGH, 4);
  BOOST_CHECK_EQUAL(interval_traits<interval_type>::get(interval, LOW), 3);
  BOOST_CHECK_EQUAL(interval_traits<interval_type>::get(interval, HIGH), 4);
}

template <typename T>
struct Interval {
  T left;
  T right;
};

namespace boost {
namespace polygon {
  template <typename T>
  struct geometry_concept< Interval<T> > {
    typedef interval_concept type;
  };

  template <typename T>
  struct interval_traits< Interval<T> > {
    typedef T coordinate_type;

    static coordinate_type get(const Interval<T>& interval, direction_1d dir) {
      return (dir == LOW) ? interval.left : interval.right;
    }
  };

  template <typename T>
  struct interval_mutable_traits< Interval<T> > {
    typedef T coordinate_type;

    static void set(Interval<T>& interval, direction_1d dir, T value) {
      (dir == LOW) ? interval.left = value : interval.right = value;
    }

    static Interval<T> construct(coordinate_type left, coordinate_type right) {
      Interval<T> interval;
      interval.left = left;
      interval.right = right;
      return interval;
    }
  };
}  // polygon
}  // boost

BOOST_AUTO_TEST_CASE_TEMPLATE(interval_concept_test1, T, test_types) {
  typedef Interval<T> interval_type;

  interval_type interval1 = construct<interval_type>(2, 1);
  BOOST_CHECK_EQUAL(interval1.left, 1);
  BOOST_CHECK_EQUAL(interval1.right, 2);

  set(interval1, LOW, 3);
  set(interval1, HIGH, 4);
  BOOST_CHECK_EQUAL(get(interval1, LOW), 3);
  BOOST_CHECK_EQUAL(get(interval1, HIGH), 4);

  interval_type interval2 = copy_construct<interval_type>(interval1);
  BOOST_CHECK(equivalence(interval1, interval2));

  low(interval2, 1);
  high(interval2, 2);
  BOOST_CHECK_EQUAL(low(interval2), 1);
  BOOST_CHECK_EQUAL(high(interval2), 2);

  assign(interval1, interval2);
  BOOST_CHECK(equivalence(interval1, interval2));
}

BOOST_AUTO_TEST_CASE_TEMPLATE(interval_concept_test2, T, test_types) {
  typedef Interval<T> interval_type;

  interval_type interval1 = construct<interval_type>(1, 3);
  BOOST_CHECK_EQUAL(center(interval1), 2);
  BOOST_CHECK_EQUAL(delta(interval1), 2);

  flip(interval1, -1);
  BOOST_CHECK_EQUAL(low(interval1), -5);
  BOOST_CHECK_EQUAL(high(interval1), -3);

  scale_up(interval1, 2);
  BOOST_CHECK_EQUAL(low(interval1), -10);
  BOOST_CHECK_EQUAL(high(interval1), -6);

  scale_down(interval1, 2);
  BOOST_CHECK_EQUAL(low(interval1), -5);
  BOOST_CHECK_EQUAL(high(interval1), -3);

  move(interval1, 5);
  BOOST_CHECK_EQUAL(low(interval1), 0);
  BOOST_CHECK_EQUAL(high(interval1), 2);

  convolve(interval1, 1);
  BOOST_CHECK_EQUAL(low(interval1), 1);
  BOOST_CHECK_EQUAL(high(interval1), 3);

  deconvolve(interval1, 2);
  BOOST_CHECK_EQUAL(low(interval1), -1);
  BOOST_CHECK_EQUAL(high(interval1), 1);

  interval_type interval2 = construct<interval_type>(-1, 2);
  convolve(interval1, interval2);
  BOOST_CHECK_EQUAL(low(interval1), -2);
  BOOST_CHECK_EQUAL(high(interval1), 3);

  deconvolve(interval1, interval2);
  BOOST_CHECK_EQUAL(low(interval1), -1);
  BOOST_CHECK_EQUAL(high(interval1), 1);

  reflected_convolve(interval1, interval2);
  BOOST_CHECK_EQUAL(low(interval1), -3);
  BOOST_CHECK_EQUAL(high(interval1), 2);

  reflected_deconvolve(interval1, interval2);
  BOOST_CHECK_EQUAL(low(interval1), -1);
  BOOST_CHECK_EQUAL(high(interval1), 1);
}

BOOST_AUTO_TEST_CASE_TEMPLATE(interval_concept_test3, T, test_types) {
  typedef Interval<T> interval_type;

  interval_type interval1 = construct<interval_type>(1, 3);
  BOOST_CHECK_EQUAL(euclidean_distance(interval1, -2), 3);
  BOOST_CHECK_EQUAL(euclidean_distance(interval1, 2), 0);
  BOOST_CHECK_EQUAL(euclidean_distance(interval1, 4), 1);

  interval_type interval2 = construct<interval_type>(-1, 0);
  BOOST_CHECK_EQUAL(euclidean_distance(interval1, interval2), 1);
  BOOST_CHECK(!intersects(interval1, interval2));
  BOOST_CHECK(!boundaries_intersect(interval1, interval2));
  BOOST_CHECK(!intersect(interval2, interval1));
  BOOST_CHECK_EQUAL(low(interval2), -1);
  BOOST_CHECK_EQUAL(high(interval2), 0);

  interval_type interval3 = construct<interval_type>(-1, 6);
  BOOST_CHECK_EQUAL(euclidean_distance(interval1, interval3), 0);
  BOOST_CHECK(intersects(interval1, interval3));
  BOOST_CHECK(!boundaries_intersect(interval1, interval3));
  BOOST_CHECK(intersect(interval3, interval1));
  BOOST_CHECK_EQUAL(low(interval3), 1);
  BOOST_CHECK_EQUAL(high(interval3), 3);

  interval_type interval4 = construct<interval_type>(5, 6);
  BOOST_CHECK_EQUAL(euclidean_distance(interval1, interval4), 2);
  BOOST_CHECK(!intersects(interval1, interval4));
  BOOST_CHECK(!boundaries_intersect(interval1, interval4));
  BOOST_CHECK(!intersect(interval4, interval1));
  BOOST_CHECK_EQUAL(low(interval4), 5);
  BOOST_CHECK_EQUAL(high(interval4), 6);

  interval_type interval5 = construct<interval_type>(3, 5);
  BOOST_CHECK_EQUAL(euclidean_distance(interval1, interval5), 0);
  BOOST_CHECK(!intersects(interval1, interval5, false));
  BOOST_CHECK(boundaries_intersect(interval1, interval5));
  BOOST_CHECK(intersect(interval5, interval1));
  BOOST_CHECK_EQUAL(low(interval5), 3);
  BOOST_CHECK_EQUAL(high(interval5), 3);
}

BOOST_AUTO_TEST_CASE_TEMPLATE(interval_concept_test4, T, test_types) {
  typedef Interval<T> interval_type;

  interval_type interval1 = construct<interval_type>(1, 3);
  interval_type interval2 = construct<interval_type>(3, 5);
  BOOST_CHECK(!abuts(interval1, interval2, LOW));
  BOOST_CHECK(abuts(interval1, interval2, HIGH));
  BOOST_CHECK(abuts(interval1, interval2));

  bloat(interval1, 1);
  BOOST_CHECK_EQUAL(low(interval1), 0);
  BOOST_CHECK_EQUAL(high(interval1), 4);
  BOOST_CHECK(!abuts(interval1, interval2));

  bloat(interval1, LOW, 1);
  BOOST_CHECK_EQUAL(low(interval1), -1);
  BOOST_CHECK_EQUAL(high(interval1), 4);

  shrink(interval1, LOW, 1);
  BOOST_CHECK_EQUAL(low(interval1), 0);
  BOOST_CHECK_EQUAL(high(interval1), 4);

  shrink(interval1, 1);
  BOOST_CHECK_EQUAL(low(interval1), 1);
  BOOST_CHECK_EQUAL(high(interval1), 3);

  BOOST_CHECK(encompass(interval1, 4));
  BOOST_CHECK_EQUAL(low(interval1), 1);
  BOOST_CHECK_EQUAL(high(interval1), 4);

  BOOST_CHECK(encompass(interval1, interval2));
  BOOST_CHECK_EQUAL(low(interval1), 1);
  BOOST_CHECK_EQUAL(high(interval1), 5);

  interval1 = get_half(interval1, LOW);
  BOOST_CHECK_EQUAL(low(interval1), 1);
  BOOST_CHECK_EQUAL(high(interval1), 3);

  BOOST_CHECK(join_with(interval1, interval2));
  BOOST_CHECK_EQUAL(low(interval1), 1);
  BOOST_CHECK_EQUAL(high(interval1), 5);
}


//          Copyright Carl Philipp Reh 2009 - 2016.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#ifndef FCPPT_MATH_MATRIX_OBJECT_DECL_HPP_INCLUDED
#define FCPPT_MATH_MATRIX_OBJECT_DECL_HPP_INCLUDED

#include <fcppt/no_init_fwd.hpp>
#include <fcppt/math/difference_type.hpp>
#include <fcppt/math/size_type.hpp>
#include <fcppt/math/detail/make_op_decl.hpp>
#include <fcppt/math/matrix/object_fwd.hpp>
#include <fcppt/math/matrix/detail/row_view_fwd.hpp>
#include <fcppt/math/vector/object_decl.hpp>
#include <fcppt/config/external_begin.hpp>
#include <boost/mpl/times.hpp>
#include <fcppt/config/external_end.hpp>

namespace fcppt
{
namespace math
{
namespace matrix
{

/**
\brief A class representing a static matrix

Represents a static R by C matrix, which is a matrix
consisting of R rows and C columns.

\ingroup fcpptmathmatrix

\tparam T The matrix's value_type

\tparam R The number of rows

\tparam C The number of columns

\tparam S The matrix's storage type

See the \link fcpptmathmatrix module documentation \endlink for more information.
*/
template<
	typename T,
	fcppt::math::size_type R,
	fcppt::math::size_type C,
	typename S
>
class object
{
public:
	typedef
	fcppt::math::static_size<
		R
	>
	static_rows;

	typedef
	fcppt::math::static_size<
		C
	>
	static_columns;

	typedef
	static_rows
	static_size;

	typedef
	typename
	boost::mpl::times<
		static_rows,
		static_columns
	>::type
	dim_wrapper;

	/**
	\brief A typedef for the \p S parameter
	*/
	typedef
	S
	storage_type;

	/**
	\brief A type that counts the number of elements in a matrix.
	*/
	typedef
	fcppt::math::size_type
	size_type;

	/**
	\brief A type that provides the difference between the addresses of two elements in a matrix.
	*/
	typedef
	fcppt::math::difference_type
	difference_type;

	/**
	\brief A type that represents the data type stored in a matrix.
	*/
	typedef
	T
	value_type;

	/**
	\brief A type that provides a reference to an element stored in a
	matrix.

	This is one of the few non-trivial implementations of the reference
	typedef, as it's really a vector that models a row-view over the
	matrix.
	*/
	typedef
	fcppt::math::vector::object<
		T,
		C,
		fcppt::math::matrix::detail::row_view<
			T,
			C
		>
	>
	reference;

	/**
	\brief
	A type that provides a reference to a const element stored
	in a vector for reading and performing const operations.

	This is one of the few non-trivial implementations of the reference
	typedef, as it's really a vector that models a row-view over the
	matrix.
	*/
	typedef
	fcppt::math::vector::object<
		T,
		C,
		fcppt::math::matrix::detail::row_view<
			T const,
			C
		>
	>
	const_reference;

	/**
	\brief Construct an uninitialized matrix

	\warning
	The content of the matrix will be undefined (not null) after
	initialization
	*/
	explicit
	object(
		fcppt::no_init const &
	);

	/**
	\brief Construct a matrix from a storage source
	*/
	explicit
	object(
		storage_type const &
	);

	/**
	\brief Constructs a matrix from R rows

	Constructs a matrix by using R arguments of type \link
	fcppt::math::matrix::row_type\endlink of size C. Use \link
	fcppt::math::matrix::row\endlink to initialize them.
	*/
	template<
		typename ...Args
	>
	explicit
	object(
		Args const &...
	);

	/**
	\brief Copy-construct the matrix from another matrix
	*/
	object(
		object const &
	);

	/**
	\brief Create a matrix from a matrix with the same dimension and value
	type but different storage type

	\tparam OtherStorage The other matrix's storage type
	*/
	template<
		typename OtherStorage
	>
	explicit
	object(
		fcppt::math::matrix::object<
			T,
			R,
			C,
			OtherStorage
		> const &
	);

	/**
	\brief Copy the values from a different matrix
	*/
	object &
	operator=(
		object const &
	);

	/**
	\brief Copy the values from a different matrix of the same size but
	different storage type

	\tparam OtherStorage The other matrix's storage type
	*/
	template<
		typename OtherStorage
	>
	object &
	operator=(
		fcppt::math::matrix::object<
			T,
			R,
			C,
			OtherStorage
		> const &
	);

	~object();

// \cond FCPPT_DOXYGEN_DEBUG
#define FCPPT_MATH_MATRIX_OBJECT_DECLARE_OPERATOR(op)\
FCPPT_MATH_DETAIL_MAKE_OP_DECL(\
	template<\
		typename OtherStorage\
	>, \
	(object<T, R, C, OtherStorage>),\
	4,\
	op \
)
// \endcond

	FCPPT_MATH_MATRIX_OBJECT_DECLARE_OPERATOR(+=)
	FCPPT_MATH_MATRIX_OBJECT_DECLARE_OPERATOR(-=)
#undef FCPPT_MATH_MATRIX_OBJECT_DECLARE_OPERATOR

	/**
	\brief Multiply a matrix by a scalar
	*/
	object &
	operator*=(
		value_type const &
	);

	/**
	\brief Divide a matrix by a scalar
	*/
	object &
	operator/=(
		value_type const &
	);

	/**
	\brief Returns a reference to a row in the matrix

	\warning
	Behaviour is undefined if the index is out of range.
	*/
	reference
	operator[](
		size_type
	);

	/**
	\brief Returns a reference to a (constant) row in the matrix

	\warning
	Behaviour is undefined if the index is out of range.
	*/
	const_reference
	operator[](
		size_type
	) const;

	/**
	\brief Returns the number of rows in the matrix.
	*/
	constexpr
	static
	size_type
	rows();

	/**
	\brief Returns the number of columns in the matrix.
	*/
	constexpr
	static
	size_type
	columns();

	S &
	storage();

	S const &
	storage() const;
private:
	S storage_;
};

}
}
}

#endif


/**
 * @file sparse_coding_test.cpp
 * @author Manish Kumar
 *
 * Test mlpackMain() of sparse_coding_main.cpp.
 *
 * mlpack is free software; you may redistribute it and/or modify it under the
 * terms of the 3-clause BSD license.  You should have received a copy of the
 * 3-clause BSD license along with mlpack.  If not, see
 * http://www.opensource.org/licenses/BSD-3-Clause for more information.
 */
#include <string>

#define BINDING_TYPE BINDING_TYPE_TEST
static const std::string testName = "SparseCoding";

#include <mlpack/core.hpp>
#include <mlpack/core/util/mlpack_main.hpp>
#include <mlpack/methods/sparse_coding/sparse_coding_main.cpp>
#include "test_helper.hpp"

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

using namespace mlpack;

struct SparseCodingTestFixture
{
 public:
  SparseCodingTestFixture()
  {
    // Cache in the options for this program.
    CLI::RestoreSettings(testName);
  }

  ~SparseCodingTestFixture()
  {
    // Clear the settings.
    bindings::tests::CleanMemory();
    CLI::ClearSettings();
  }
};

BOOST_FIXTURE_TEST_SUITE(SparseCodingMainTest, SparseCodingTestFixture);

/**
 * Helper function to load datasets.
 */
void LoadData(arma::mat& inputData, arma::mat& testData)
{
  // Load train dataset.
  if (!data::Load("iris_train.csv", inputData))
    BOOST_FAIL("Cannot load train dataset iris_train.csv!");

  // Load test dataset.
  if (!data::Load("iris_test.csv", testData))
    BOOST_FAIL("Cannot load test dataset iris_test.csv!");
}

/**
 * Make sure that output points in dictionary equals number of
 * atoms passed and codes have desired dimension.
 */
BOOST_AUTO_TEST_CASE(SparseCodingOutputDimensionTest)
{
  arma::mat inputData;
  arma::mat testData;
  LoadData(inputData, testData);

  mat initialDictionary = inputData.cols(0, 1);

  // Input data.
  SetInputParam("training", std::move(inputData));
  SetInputParam("atoms", (int) 2);
  SetInputParam("max_iterations", (int) 100);
  SetInputParam("test", std::move(testData));

  mlpackMain();

  // Check that number of output dictionary points are equals number of atoms.
  BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("dictionary").n_cols, 2);

  // Check that number of output dictionary rows equal number of input rows
  // which equal 4 for each data point.
  BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("dictionary").n_rows, 4);

  // Check that number of output points are equal to number of test points.
  // Test file contains 63 data points.
  BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("codes").n_cols, 63);

  // Check that number of output codes rows equal number of atoms.
  BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("codes").n_rows, 2);
}

/**
 * Ensure that training data is normalized if normalize
 * parameter is set to true.
 */
BOOST_AUTO_TEST_CASE(SparseCodingNormalizationTest)
{
  arma::mat inputData;
  arma::mat testData;
  LoadData(inputData, testData);

  mat initialDictionary = inputData.cols(0, 1);

  // Train for normalization set to true.

  // Input data.
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", initialDictionary);
  SetInputParam("max_iterations", (int) 100);
  SetInputParam("normalize", (bool) true);
  SetInputParam("test", testData);

  mlpackMain();

  // Store outputs.
  arma::mat dictionary = CLI::GetParam<arma::mat>("dictionary");
  arma::mat codes =
      std::move(CLI::GetParam<arma::mat>("codes"));

  // Train for normalization set to false.

  // Reset passed parameters.
  bindings::tests::CleanMemory();
  CLI::GetSingleton().Parameters()["normalize"].wasPassed = false;

  // Normalize train dataset.
  for (size_t i = 0; i < inputData.n_cols; ++i)
    inputData.col(i) /= norm(inputData.col(i), 2);

  // Normalize test dataset.
  for (size_t i = 0; i < testData.n_cols; ++i)
    testData.col(i) /= norm(testData.col(i), 2);

  // Input data.
  SetInputParam("training", std::move(inputData));
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", std::move(initialDictionary));
  SetInputParam("max_iterations", (int) 100);
  SetInputParam("test", std::move(testData));

  mlpackMain();

  // Check that initial outputs and final outputs
  // using two models model are same.
  CheckMatrices(dictionary, CLI::GetParam<arma::mat>("dictionary"));
  CheckMatrices(codes, CLI::GetParam<arma::mat>("codes"));
}

/**
 * Ensure that l1, l2, max_iterations, objective_tolerance,
 * newton_tolerance value is always non-negative and number
 * of atoms is always positive.
 */
BOOST_AUTO_TEST_CASE(SparseCodingBoundsTest)
{
  arma::mat inputData;
  if (!data::Load("iris_train.csv", inputData))
    BOOST_FAIL("Cannot load train dataset iris_train.csv!");

  // Test for L1 value.

  // Input training data.
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 10);
  SetInputParam("lambda1", (double) -1.0);

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;

  // Test for L2 value.

  // Input training data.
  bindings::tests::CleanMemory();
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 10);
  SetInputParam("lambda2", (double) -1.0);

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;

  // Test for max_iterations.

  // Input training data.
  bindings::tests::CleanMemory();
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 10);
  SetInputParam("max_iterations", (int) -1.0);

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;

  // Test for objective_tolerance.

  // Input training data.
  bindings::tests::CleanMemory();
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 10);
  SetInputParam("objective_tolerance", (double) -1.0);

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;

  // Test for newton_tolerance.

  // Input training data.
  bindings::tests::CleanMemory();
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 10);
  SetInputParam("newton_tolerance", (double) -1.0);

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;

  // Test for atoms.

  // Input training data.
  SetInputParam("training", std::move(inputData));
  SetInputParam("atoms", (int) 0);

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/**
 * Make sure atoms are specified if training data is passed.
 */
BOOST_AUTO_TEST_CASE(SparseCodingReqAtomsTest)
{
  arma::mat inputData;
  if (!data::Load("iris_train.csv", inputData))
    BOOST_FAIL("Cannot load train dataset iris_train.csv!");

  // Input training data.
  SetInputParam("training", std::move(inputData));

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/**
 * Ensure only one of input_model or initial_dictionary
 * is specified.
 */
BOOST_AUTO_TEST_CASE(SparseCodingModelVerTest)
{
  arma::mat inputData;
  arma::mat testData;
  LoadData(inputData, testData);

  mat initialDictionary = inputData.cols(0, 1);
  SparseCoding* c = new SparseCoding();

  // Input trained model and initial_dictionary.
  SetInputParam("input_model", c);
  SetInputParam("initial_dictionary", std::move(initialDictionary));

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/**
 * Ensure that specified number of atoms and initial_dictionary
 * atoms are equal.
 */
BOOST_AUTO_TEST_CASE(SparseCodingAtomsVerTest)
{
  arma::mat inputData;
  arma::mat testData;
  LoadData(inputData, testData);

  mat initialDictionary = inputData.cols(0, 1); // 2 points.

  // Input data and initial_dictionary.
  SetInputParam("training", std::move(inputData));
  SetInputParam("atoms", (int) 40); // Invalid.
  SetInputParam("initial_dictionary", std::move(initialDictionary));
  SetInputParam("max_iterations", (int) 100);

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/**
 * Ensure that input data and initial_dictionary
 * have same number of rows.
 */
BOOST_AUTO_TEST_CASE(SparseCodingRowsVerTest)
{
  arma::mat inputData;
  arma::mat testData;
  LoadData(inputData, testData);

  mat initialDictionary = inputData.cols(0, 1);

  // Trim inputData.
  inputData.shed_rows(1, 2);

  // Input data and initial_dictionary.
  SetInputParam("training", std::move(inputData)); // Invalid Data.
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", std::move(initialDictionary));
  SetInputParam("max_iterations", (int) 100);
  SetInputParam("normalize", (bool) true);

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/**
 * Ensure that training data and test data
 * have same dimensionality w.r.t rows.
 */
BOOST_AUTO_TEST_CASE(SparseCodingDataDimensionalityTest)
{
  arma::mat inputData;
  arma::mat testData;
  LoadData(inputData, testData);

  mat initialDictionary = inputData.cols(0, 1);

  // Trim testData.
  testData.shed_rows(1, 2);

  // Input data.
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 2);
  SetInputParam("max_iterations", (int) 100);
  SetInputParam("test", std::move(testData));

  Log::Fatal.ignoreInput = true;
  BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
  Log::Fatal.ignoreInput = false;
}

/**
 * Check that saved model can be reused again.
 */
BOOST_AUTO_TEST_CASE(SparseCodingModelReuseTest)
{
  arma::mat inputData;
  arma::mat testData;
  LoadData(inputData, testData);

  // Input data.
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 2);
  SetInputParam("max_iterations", (int) 100);
  SetInputParam("normalize", (bool) true);
  SetInputParam("test", testData);

  mlpackMain();

  // Store outputs.
  arma::mat dictionary =
      std::move(CLI::GetParam<arma::mat>("dictionary"));
  arma::mat codes =
      std::move(CLI::GetParam<arma::mat>("codes"));

  // Reset passed parameters.
  CLI::GetSingleton().Parameters()["training"].wasPassed = false;

  // Test the correctness of trained model.

  // Input data.
  SetInputParam("max_iterations", (int) 100);
  SetInputParam("input_model", CLI::GetParam<SparseCoding*>("output_model"));
  SetInputParam("normalize", (bool) true);
  SetInputParam("test", std::move(testData));

  mlpackMain();

  // Check that number of output dictionary points are equals number of atoms.
  BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("dictionary").n_cols, 2);

  // Check that number of output dictionary rows equal number of input rows
  // which equal 4 for each data point.
  BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("dictionary").n_rows, 4);

  // Check that number of output points are equal to number of test points.
  // Test file contains 63 data points.
  BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("codes").n_cols, 63);

  // Check that number of output codes rows equal number of atoms.
  BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("codes").n_rows, 2);

  // Check that initial outputs and final outputs
  // using two models model are same.
  CheckMatrices(dictionary, CLI::GetParam<arma::mat>("dictionary"));
  CheckMatrices(codes, CLI::GetParam<arma::mat>("codes"));
}

/**
 * Ensure that for different value of max iterations
 * outputs are different.
 */
BOOST_AUTO_TEST_CASE(SparseCodingDiffMaxItrTest)
{
  arma::mat inputData;
  arma::mat testData;
  LoadData(inputData, testData);

  mat initialDictionary = inputData.cols(0, 1);

  // Train for max_iterations equals to 2.

  // Input data.
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", initialDictionary);
  SetInputParam("max_iterations", (int) 2);
  SetInputParam("normalize", (bool) true);
  SetInputParam("test", testData);

  mlpackMain();

  // Store outputs.
  arma::mat dictionary = CLI::GetParam<arma::mat>("dictionary");
  arma::mat codes =
      std::move(CLI::GetParam<arma::mat>("codes"));

  // Train for max_iterations equals to 100.

  // Input data.
  bindings::tests::CleanMemory();
  SetInputParam("training", std::move(inputData));
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", std::move(initialDictionary));
  SetInputParam("max_iterations", (int) 100);
  SetInputParam("normalize", (bool) true);
  SetInputParam("test", std::move(testData));

  mlpackMain();

  // Check that initial outputs and final outputs
  // using two models model are different.
  BOOST_REQUIRE_LT(arma::accu(dictionary ==
      CLI::GetParam<arma::mat>("dictionary")), dictionary.n_elem);

  BOOST_REQUIRE_LT(arma::accu(codes ==
      CLI::GetParam<arma::mat>("codes")), codes.n_elem);
}

/**
 * Ensure that for different value of objective_tolerance
 * outputs are different.
 */
BOOST_AUTO_TEST_CASE(SparseCodingDiffObjToleranceTest)
{
  arma::mat inputData;
  arma::mat testData;
  LoadData(inputData, testData);

  mat initialDictionary = inputData.cols(0, 1);

  // Train for default objective_tolerance.

  // Input data.
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", initialDictionary);
  SetInputParam("test", testData);

  mlpackMain();

  // Store outputs.
  arma::mat dictionary = CLI::GetParam<arma::mat>("dictionary");
  arma::mat codes =
      std::move(CLI::GetParam<arma::mat>("codes"));

  // Train for objective_tolerance equals to 10000.0.

  // Input data.
  bindings::tests::CleanMemory();
  SetInputParam("training", std::move(inputData));
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", std::move(initialDictionary));
  SetInputParam("objective_tolerance", (double) 10000.0);
  SetInputParam("test", std::move(testData));

  mlpackMain();

  // Check that initial outputs and final outputs
  // using two models model are different.
  BOOST_REQUIRE_LT(arma::accu(dictionary ==
      CLI::GetParam<arma::mat>("dictionary")), dictionary.n_elem);

  BOOST_REQUIRE_LT(arma::accu(codes ==
      CLI::GetParam<arma::mat>("codes")), codes.n_elem);
}

/**
 * Ensure that for different value of newton_tolerance
 * outputs are different.
 */
BOOST_AUTO_TEST_CASE(SparseCodingDiffNewtonToleranceTest)
{
  arma::mat inputData;
  arma::mat testData;
  LoadData(inputData, testData);

  mat initialDictionary = inputData.cols(0, 1);

  // Train for default newton_tolerance.

  // Input data.
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", initialDictionary);
  SetInputParam("test", testData);

  mlpackMain();

  // Store outputs.
  arma::mat dictionary = CLI::GetParam<arma::mat>("dictionary");
  arma::mat codes =
      std::move(CLI::GetParam<arma::mat>("codes"));

  // Train for newton_tolerance equals to 10000.0.

  // Input data.
  bindings::tests::CleanMemory();
  SetInputParam("training", std::move(inputData));
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", std::move(initialDictionary));
  SetInputParam("newton_tolerance", (double) 10000.0);
  SetInputParam("test", std::move(testData));

  mlpackMain();

  // Check that initial outputs and final outputs
  // using two models model are different.
  BOOST_REQUIRE_LT(arma::accu(dictionary ==
      CLI::GetParam<arma::mat>("dictionary")), dictionary.n_elem);

  BOOST_REQUIRE_LT(arma::accu(codes ==
      CLI::GetParam<arma::mat>("codes")), codes.n_elem);
}

/**
 * Ensure that for different value of lambda1
 * outputs are different.
 */
BOOST_AUTO_TEST_CASE(SparseCodingDiffL1Test)
{
  arma::mat inputData;
  arma::mat testData;
  LoadData(inputData, testData);

  mat initialDictionary = inputData.cols(0, 1);

  // Train for default lambda1.

  // Input data.
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", initialDictionary);
  SetInputParam("test", testData);

  mlpackMain();

  // Store outputs.
  arma::mat dictionary = CLI::GetParam<arma::mat>("dictionary");
  arma::mat codes =
      std::move(CLI::GetParam<arma::mat>("codes"));

  // Train for lambda1 equals to 10000.0.

  // Input data.
  bindings::tests::CleanMemory();
  SetInputParam("training", std::move(inputData));
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", std::move(initialDictionary));
  SetInputParam("lambda1", (double) 10000.0);
  SetInputParam("test", std::move(testData));

  mlpackMain();

  // Check that initial outputs and final outputs
  // using two models model are different.
  BOOST_REQUIRE_LT(arma::accu(dictionary ==
      CLI::GetParam<arma::mat>("dictionary")), dictionary.n_elem);

  BOOST_REQUIRE_LT(arma::accu(codes ==
      CLI::GetParam<arma::mat>("codes")), codes.n_elem);
}

/**
 * Ensure that for different value of lambda2
 * outputs are different.
 */
BOOST_AUTO_TEST_CASE(SparseCodingDiffL2Test)
{
  arma::mat inputData;
  arma::mat testData;
  LoadData(inputData, testData);

  mat initialDictionary = inputData.cols(0, 1);

  // Train for default lambda2.

  // Input data.
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", initialDictionary);
  SetInputParam("test", testData);

  mlpackMain();

  // Store outputs.
  arma::mat dictionary = CLI::GetParam<arma::mat>("dictionary");
  arma::mat codes =
      std::move(CLI::GetParam<arma::mat>("codes"));

  // Train for lambda2 equals to 10000.0.

  // Input data.
  bindings::tests::CleanMemory();
  SetInputParam("training", std::move(inputData));
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", std::move(initialDictionary));
  SetInputParam("lambda2", (double) 10000.0);
  SetInputParam("test", std::move(testData));

  mlpackMain();

  // Check that initial outputs and final outputs
  // using two models model are different.
  BOOST_REQUIRE_LT(arma::accu(dictionary ==
      CLI::GetParam<arma::mat>("dictionary")), dictionary.n_elem);

  BOOST_REQUIRE_LT(arma::accu(codes ==
      CLI::GetParam<arma::mat>("codes")), codes.n_elem);
}

/**
 * Ensure that for different value of lambda1 & lambda2
 * outputs are different.
 */
BOOST_AUTO_TEST_CASE(SparseCodingDiffL1L2Test)
{
  arma::mat inputData;
  arma::mat testData;
  LoadData(inputData, testData);

  mat initialDictionary = inputData.cols(0, 1);

  // Train for default lambda2 & lambda1 equal to 10000.0.

  // Input data.
  SetInputParam("training", inputData);
  SetInputParam("atoms", (int) 2);
  SetInputParam("lambda1", (double) 10000.0);
  SetInputParam("initial_dictionary", initialDictionary);
  SetInputParam("test", testData);

  mlpackMain();

  // Store outputs.
  arma::mat dictionary = CLI::GetParam<arma::mat>("dictionary");
  arma::mat codes =
      std::move(CLI::GetParam<arma::mat>("codes"));

  // Train for lambda1 EQUALS 0.0 & lambda2 equals to 10000.0.

  // Input data.
  bindings::tests::CleanMemory();
  SetInputParam("training", std::move(inputData));
  SetInputParam("atoms", (int) 2);
  SetInputParam("initial_dictionary", std::move(initialDictionary));
  SetInputParam("lambda1", (double) 0.0);
  SetInputParam("lambda2", (double) 10000.0);
  SetInputParam("test", std::move(testData));

  mlpackMain();

  // Check that initial outputs and final outputs
  // using two models model are different.
  BOOST_REQUIRE_LT(arma::accu(dictionary ==
      CLI::GetParam<arma::mat>("dictionary")), dictionary.n_elem);

  BOOST_REQUIRE_LT(arma::accu(codes ==
      CLI::GetParam<arma::mat>("codes")), codes.n_elem);
}

BOOST_AUTO_TEST_SUITE_END();


//
// Created by Alex Beccaro on 21/01/2019.
//

#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include "../../src/problems/101-150/122/problem122.hpp"

BOOST_AUTO_TEST_SUITE( Problem122 )

    BOOST_AUTO_TEST_CASE( Solution ) {
        auto res = problems::problem122::solve();
        BOOST_CHECK_EQUAL(res, 1582);
    }

BOOST_AUTO_TEST_SUITE_END()


/*
 * Copyright (c) 2009 Carnegie Mellon University.
 *     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.
 *
 * For more about this software visit:
 *
 *      http://www.graphlab.ml.cmu.edu
 *
 */

#include <boost/unordered_set.hpp>
#include <graphlab.hpp>
#include <graphlab/macros_def.hpp>
#include "../../src/graphlab/util/timer.hpp"
/**
 *
 * In this program we implement the "k-core" decomposition algorithm.
 * We use a parallel variant of
 *
 * V. Batagelj and M. Zaversnik, An O(m) algorithm for cores
 * decomposition of networks,
 *
 *  - Essentially, recursively remove everything with degree 1
 *  - Then recursively remove everything with degree 2
 *  - etc.
 */

/*
 * Each vertex maintains a "degree" count. If this value
 * is 0, the vertex is "deleted"
 */
typedef int vertex_data_type;

/*
 * Don't need any edges
 */
typedef graphlab::empty edge_data_type;

/*
 * Define the type of the graph
 */
typedef graphlab::distributed_graph<vertex_data_type,
                                    edge_data_type> graph_type;

// The current K to compute
size_t CURRENT_K;

size_t ITERATIONS = 0;

/*
 * The core K-core implementation.
 * The basic concept is simple.
 * Each vertex maintains a count of the number of adjacent edges.
 * If a vertex receives a message, the message contains the number of
 * adjacent edges deleted. The vertex then updates its counter.
 * If the counter falls below K, it deletes itself
 * (set the adjacent count to 0) and signals each of its neighbors
 * with a message of 1.
 */
class k_core :
  public graphlab::ivertex_program<graph_type,
                                   graphlab::empty, // gathers are integral
                                   int>,   // messages are integral
  public graphlab::IS_POD_TYPE  {
public:
  // the last received message
  int msg;

  /* Each vertex can only signal once. I set this flag
   * if it is the first time this vertex falls below K, so I can
   * initiate scattering
   */
  bool just_deleted;

  k_core():msg(0),just_deleted(false) { }

  /* The message contains the number of adjacent edges deleted.
   * Store the message in the program, and reset the just_deleted flag
   */
  void init(icontext_type& context, const vertex_type& vertex,
            const message_type& message) {
    msg = message;
    just_deleted = false;
  }

  // gather is never invoked
  edge_dir_type gather_edges(icontext_type& context,
                             const vertex_type& vertex) const {
    return graphlab::NO_EDGES;
  }

  /* On apply, if the vertex has not yet been deleted,
   * decrement the counter on the vertex.
   * If the adjacency count of the vertex falls below K,
   * the vertex shall be deleted.
   * We set the vertex data to 0 to designate that it is deleted
   * and Set the just_deleted flag to signal the neighbors in scatter
   */
  void apply(icontext_type& context, vertex_type& vertex,
             const gather_type& unused) {
    if (vertex.data() > 0) {
      vertex.data() -= msg;
      if (vertex.data() < CURRENT_K) {
        just_deleted = true;
        vertex.data() = 0;
      }
    }
  }

  /*
   * If the vertex is deleted, we signal all neighbors on the scatter
   */
  edge_dir_type scatter_edges(icontext_type& context,
                              const vertex_type& vertex) const {
    return just_deleted ?
      graphlab::ALL_EDGES : graphlab::NO_EDGES;
  }

  /*
   * For each neighboring vertex, if it is not yet deleted,
   * signal it.
   */
  void scatter(icontext_type& context,
               const vertex_type& vertex,
               edge_type& edge) const {
    vertex_type other = edge.source().id() == vertex.id() ?
      edge.target() : edge.source();
    if (other.data() > 0) {
      context.signal(other, 1);
    }
  }

};

// type of the synchronous_engine
typedef graphlab::synchronous_engine<k_core> engine_type;

/*
 * Called before any graph operation is performed.
 * Initializes all vertex data to the number of adjacent edges.
 * Can be called from a graph.transform_vertices()
 */
void initialize_vertex_values(graph_type::vertex_type& v) {
  v.data() = v.num_in_edges() + v.num_out_edges();
}

/*
 * Signals all non-deleted vertices with degree less than K.
 * Can be called from an engine.map_reduce_vertices()
 * We return empty since no reduction is performed. Only the map.
 */
graphlab::empty signal_vertices_at_k(engine_type::icontext_type& ctx,
                                     const graph_type::vertex_type& vertex) {
  if (vertex.data() > 0 && vertex.data() < CURRENT_K) {
    ctx.signal(vertex, 0);
  }
  return graphlab::empty();
}

/*
 * Counts the number of un-deleted vertices.
 */
size_t count_active_vertices(const graph_type::vertex_type& vertex) {
  return vertex.data() > 0;
}

/*
 * Counts the degree of each un-deleted vertex. Half of this
 * will be the size of the K-core graph.
 */
size_t double_count_active_edges(const graph_type::vertex_type& vertex) {
  return (size_t) vertex.data();
}

/*
 * Saves the graph in a tsv format with the condition that
 * the adjacent vertices have not yet been deleted.
 * This allows saving of the k-core graph.
 */
struct save_core_at_k {
  std::string save_vertex(graph_type::vertex_type) { return ""; }
  std::string save_edge(graph_type::edge_type e) {
    if (e.source().data() > 0 && e.target().data() > 0) {
      return graphlab::tostr(e.source().id()) + "\t" +
        graphlab::tostr(e.target().id()) + "\n";
    }
    else return "";
  }
};

int main(int argc, char** argv) {
  std::cout << "Computes a k-core decomposition of a graph.\n\n";

  graphlab::command_line_options clopts
    ("K-Core decomposition. This program "
     "computes the K-Core decomposition of a graph, for K ranging from [kmin] "
     "to [kmax]. The size of the remaining K-core graph at each K is printed. "
     "The [savecores] allow the saving of each K-Core graph in a TSV format"
     );
  std::string prefix, format;
  size_t kmin = 0;
  size_t kmax = (size_t)(-1);
  std::string savecores;
  clopts.attach_option("graph", prefix,
                       "Graph input. reads all graphs matching prefix*");
  clopts.attach_option("format", format,
                       "The graph format");
  clopts.attach_option("kmin", kmin,
                       "Compute the k-Core for k the range [kmin,kmax]");
  clopts.attach_option("kmax", kmax,
                       "Compute the k-Core for k the range [kmin,kmax]");
  clopts.attach_option("savecores", savecores,
                       "If non-empty, will save tsv of each core with prefix [savecores].K.");
	clopts.attach_option("iterations", ITERATIONS,
                       "If set, will force the use of the synchronous engine"
                       "overriding any engine option set by the --engine parameter. "
                       "Runs complete (non-dynamic) PageRank for a fixed "
                       "number of iterations. Also overrides the iterations "
                       "option in the engine");
	size_t powerlaw = 0;
  clopts.attach_option("powerlaw", powerlaw,
                       "Generate a synthetic powerlaw degree graph. ");
  double alpha = 2.1, beta = 2.2;
  clopts.attach_option("alpha", alpha,
                         "Power-law constant for indegree ");
  clopts.attach_option("beta", beta,
                         "Power-law constant for outdegree ");
  std::string result_file;
  clopts.attach_option("result_file", result_file,
                       "If set, will save the test result to the"
                       "specific file");

  if(!clopts.parse(argc, argv)) return EXIT_FAILURE;
  if (kmax < kmin) {
    std::cout << "kmax must be at least as large as kmin\n";
    clopts.print_description();
    return EXIT_FAILURE;
  }

  // Initialize control plane using mpi
  graphlab::mpi_tools::init(argc, argv);
  graphlab::distributed_control dc;

  if (ITERATIONS) {
    // make sure this is the synchronous engine
    dc.cout() << "--iterations set. Forcing Synchronous engine, and running "
              << "for " << ITERATIONS << " iterations." << std::endl;
    //clopts.get_engine_args().set_option("type", "synchronous");
    clopts.get_engine_args().set_option("max_iterations", ITERATIONS);
    clopts.get_engine_args().set_option("sched_allv", true);
  }

  int ntrials = 20;
  int trial_results1[20];
  double trial_results2[20][8];
  uint32_t seed_set[20] = {1492133106, 680965948, 2040586311, 73972395, 942196338, 819390547, 1643934785, 1707678784, 401305863, 1051761031, 956889080, 1387946621, 1523349375, 1620677309, 592759340, 1459650384, 1406812251, 349206043, 255545576, 1070228652};
  for(int i = 0; i < ntrials; i++)
  {

		// random seed
		// dc.cout() << seed_set[i] << std::endl;
		clopts.get_graph_args().set_option("seed", seed_set[i]);

	  // load graph
	  graph_type graph(dc, clopts);

	  if(powerlaw > 0) { // make a synthetic graph
		  dc.cout() << "Loading synthetic Powerlaw graph." << std::endl;
		  graph.load_synthetic_powerlaw(powerlaw, alpha, beta, 100000000);
		}
		else if (prefix.length() > 0) { // Load the graph from a file
			if(dc.procid() == 24)
		  std::cout << "Loading graph in format: "<< format << std::endl;
		  graph.load_format(prefix, format);
		}
		else {
		  dc.cout() << "graph or powerlaw option must be specified" << std::endl;
		  clopts.print_description();
		  return 0;
		}

	  graphlab::timer timer;
	  timer.start();
	  graph.finalize();
	  const double ingress_time = timer.current_time();
	  dc.cout() << "Finalizing graph. Finished in "
		  << ingress_time << std::endl;
	  dc.cout() << "Number of vertices: " << graph.num_vertices() << std::endl
				<< "Number of edges:    " << graph.num_edges() << std::endl;

	  timer.start();
	  graphlab::synchronous_engine<k_core> engine(dc, graph, clopts);

	  // initialize the vertex data with the degree
	  graph.transform_vertices(initialize_vertex_values);

	  // for each K value
	  for (CURRENT_K = kmin; CURRENT_K <= kmax; CURRENT_K++) {
		// signal all vertices with degree less than K
		engine.map_reduce_vertices<graphlab::empty>(signal_vertices_at_k);
		// recursively delete all vertices with degree less than K
		engine.start();
		// count the number of vertices and edges remaining
		size_t numv = graph.map_reduce_vertices<size_t>(count_active_vertices);
		size_t nume = graph.map_reduce_vertices<size_t>(double_count_active_edges) / 2;
		if (numv == 0) break;
		// Output the size of the graph
		dc.cout() << "K=" << CURRENT_K << ":  #V = "
				  << numv << "   #E = " << nume << std::endl;

		// Saves the result if requested
		if (savecores != "") {
		  graph.save(savecores + "." + graphlab::tostr(CURRENT_K) + ".",
					 save_core_at_k(),
					 false, /* no compression */
					 false, /* do not save vertex */
					 true, /* save edge */
					 clopts.get_ncpus()); /* one file per machine */
		}
	  }
	  const double runtime = timer.current_time();

	  if(dc.procid() == 0) {
          std::cout << graph.num_replicas() << "\t"
                    << (double)graph.num_replicas()/graph.num_vertices() << "\t"
                    << graph.get_edge_balance() << "\t"
                    << graph.get_vertex_balance() << "\t"
                    << ingress_time << "\t"
					<< runtime << "\t"
                    << engine.get_exec_time() << "\t"
                    << engine.get_one_itr_time() << "\t"
                    << engine.get_compute_balance() << "\t"
                    << std::endl;
          trial_results1[i] = graph.num_replicas();
          trial_results2[i][0] = (double)graph.num_replicas()/graph.num_vertices();
          trial_results2[i][1] = graph.get_edge_balance();
          trial_results2[i][2] = graph.get_vertex_balance() ;
          trial_results2[i][3] = ingress_time;
          trial_results2[i][4] = runtime;
          trial_results2[i][5] = engine.get_exec_time();
          trial_results2[i][6] = engine.get_one_itr_time();
          trial_results2[i][7] = engine.get_compute_balance();

          if(result_file != "") {
              std::cout << "saving the result to " << result_file << std::endl;
              std::ofstream fout(result_file.c_str(), std::ios::app);
              if(powerlaw > 0) {
                  fout << "powerlaw synthetic: " << powerlaw << "\t"
                      << alpha << "\t" << beta << "\t" << dc.numprocs() << std::endl;
              }
              else {
                  fout << "real-world graph: " << prefix << "\t"
                      << graph.num_vertices() << "\t" << graph.num_edges()
                      << "\t" << dc.numprocs() << std::endl;
              }
              std::string ingress_method = "";
              clopts.get_graph_args().get_option("ingress", ingress_method);
              fout << ingress_method << "\t";
              fout << graph.num_replicas() << "\t"
                  << (double)graph.num_replicas()/graph.num_vertices() << "\t"
                  << graph.get_edge_balance() << "\t"
                  << graph.get_vertex_balance() << "\t"
                  << ingress_time << "\t"
				  << runtime << "\t"
                  << engine.get_exec_time() << "\t"
                  << engine.get_one_itr_time() << "\t"
                  << engine.get_compute_balance() << "\t"
                  << std::endl;
              fout.close();
          }
      }

  }

  graphlab::mpi_tools::finalize();
  return EXIT_SUCCESS;
} // End of main


// Boost.Geometry Index
//
// This view makes possible to treat some simple primitives as its bounding geometry
// e.g. box, nsphere, etc.
//
// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
//
// This file was modified by Oracle on 2019.
// Modifications copyright (c) 2019 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
//
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_GEOMETRY_INDEX_DETAIL_BOUNDED_VIEW_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_BOUNDED_VIEW_HPP

#include <boost/mpl/assert.hpp>

#include <boost/geometry/algorithms/envelope.hpp>

#include <boost/geometry/strategies/index.hpp>

namespace boost { namespace geometry {

namespace index { namespace detail {

template <typename Geometry, typename BoundingGeometry, typename Strategy>
struct bounded_view_base_cs_tag
{
    typedef typename Strategy::cs_tag type;
};

template <typename Geometry, typename BoundingGeometry>
struct bounded_view_base_cs_tag<Geometry, BoundingGeometry, default_strategy>
    : geometry::cs_tag<Geometry>
{};

template
<
    typename Geometry,
    typename BoundingGeometry,
    typename Strategy,
    typename Tag = typename geometry::tag<Geometry>::type,
    typename BoundingTag = typename geometry::tag<BoundingGeometry>::type,
    typename CSTag = typename bounded_view_base_cs_tag
                        <
                            Geometry, BoundingGeometry, Strategy
                        >::type
>
struct bounded_view_base
{
    BOOST_MPL_ASSERT_MSG(
        (false),
        NOT_IMPLEMENTED_FOR_THOSE_GEOMETRIES,
        (types<Tag, BoundingTag, CSTag>));
};

// Segment -> Box

template <typename Segment, typename Box, typename Strategy>
struct bounded_view_base<Segment, Box, Strategy, segment_tag, box_tag, cartesian_tag>
{
public:
    typedef typename geometry::coordinate_type<Box>::type coordinate_type;

    bounded_view_base(Segment const& segment, Strategy const& )
        : m_segment(segment)
    {}

    template <std::size_t Dimension>
    inline coordinate_type get_min() const
    {
        return boost::numeric_cast<coordinate_type>(
                (std::min)( geometry::get<0, Dimension>(m_segment),
                            geometry::get<1, Dimension>(m_segment) ) );
    }

    template <std::size_t Dimension>
    inline coordinate_type get_max() const
    {
        return boost::numeric_cast<coordinate_type>(
                (std::max)( geometry::get<0, Dimension>(m_segment),
                            geometry::get<1, Dimension>(m_segment) ) );
    }

private:
    Segment const& m_segment;
};

template <typename Segment, typename Box, typename Strategy, typename CSTag>
struct bounded_view_base<Segment, Box, Strategy, segment_tag, box_tag, CSTag>
{
    template <typename S>
    inline void envelope(Segment const& segment, S const& strategy)
    {
        geometry::envelope(segment, m_box,
                           strategy.get_envelope_segment_strategy());
    }

    inline void envelope(Segment const& segment, default_strategy const& )
    {
        geometry::envelope(segment, m_box);
    }

public:
    typedef typename geometry::coordinate_type<Box>::type coordinate_type;

    bounded_view_base(Segment const& segment, Strategy const& strategy)
    {
        envelope(segment, strategy);
    }

    template <std::size_t Dimension>
    inline coordinate_type get_min() const
    {
        return geometry::get<min_corner, Dimension>(m_box);
    }

    template <std::size_t Dimension>
    inline coordinate_type get_max() const
    {
        return geometry::get<max_corner, Dimension>(m_box);
    }

private:
    Box m_box;
};

// Box -> Box

template <typename BoxIn, typename Box, typename Strategy, typename CSTag>
struct bounded_view_base<BoxIn, Box, Strategy, box_tag, box_tag, CSTag>
{
public:
    typedef typename geometry::coordinate_type<Box>::type coordinate_type;

    bounded_view_base(BoxIn const& box, Strategy const& )
        : m_box(box)
    {}

    template <std::size_t Dimension>
    inline coordinate_type get_min() const
    {
        return boost::numeric_cast<coordinate_type>(
                geometry::get<min_corner, Dimension>(m_box) );
    }

    template <std::size_t Dimension>
    inline coordinate_type get_max() const
    {
        return boost::numeric_cast<coordinate_type>(
                geometry::get<max_corner, Dimension>(m_box) );
    }

private:
    BoxIn const& m_box;
};

// Point -> Box

template <typename Point, typename Box, typename Strategy, typename CSTag>
struct bounded_view_base<Point, Box, Strategy, point_tag, box_tag, CSTag>
{
public:
    typedef typename geometry::coordinate_type<Box>::type coordinate_type;

    bounded_view_base(Point const& point, Strategy const& )
        : m_point(point)
    {}

    template <std::size_t Dimension>
    inline coordinate_type get_min() const
    {
        return boost::numeric_cast<coordinate_type>(
                geometry::get<Dimension>(m_point) );
    }

    template <std::size_t Dimension>
    inline coordinate_type get_max() const
    {
        return boost::numeric_cast<coordinate_type>(
                geometry::get<Dimension>(m_point) );
    }

private:
    Point const& m_point;
};

template <typename Geometry,
          typename BoundingGeometry,
          typename Strategy,
          typename Tag = typename geometry::tag<Geometry>::type,
          typename BoundingTag = typename geometry::tag<BoundingGeometry>::type>
struct bounded_view
    : bounded_view_base<Geometry, BoundingGeometry, Strategy>
{
    typedef bounded_view_base<Geometry, BoundingGeometry, Strategy> base_type;

    bounded_view(Geometry const& geometry, Strategy const& strategy)
        : base_type(geometry, strategy)
    {}
};

template <typename Geometry,
          typename BoundingGeometry,
          typename Tag,
          typename BoundingTag>
struct bounded_view<Geometry, BoundingGeometry, default_strategy, Tag, BoundingTag>
    : bounded_view_base
        <
            Geometry,
            BoundingGeometry,
            typename strategy::index::services::default_strategy<Geometry>::type
        >
{
    typedef typename strategy::index::services::default_strategy
        <
            Geometry
        >::type strategy_type;

    typedef bounded_view_base
        <
            Geometry,
            BoundingGeometry,
            strategy_type
        > base_type;

    explicit bounded_view(Geometry const& geometry, default_strategy const& )
        : base_type(geometry, strategy_type())
    {}
};

}} // namespace index::detail

// XXX -> Box

#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
namespace traits
{

template <typename Geometry, typename Box, typename Strategy, typename Tag>
struct tag< index::detail::bounded_view<Geometry, Box, Strategy, Tag, box_tag> >
{
    typedef box_tag type;
};

template <typename Geometry, typename Box, typename Strategy, typename Tag>
struct point_type< index::detail::bounded_view<Geometry, Box, Strategy, Tag, box_tag> >
{
    typedef typename point_type<Box>::type type;
};

template <typename Geometry, typename Box, typename Strategy, typename Tag, std::size_t Dimension>
struct indexed_access<index::detail::bounded_view<Geometry, Box, Strategy, Tag, box_tag>,
                      min_corner, Dimension>
{
    typedef index::detail::bounded_view<Geometry, Box, Strategy, Tag, box_tag> box_type;
    typedef typename geometry::coordinate_type<Box>::type coordinate_type;

    static inline coordinate_type get(box_type const& b)
    {
        return b.template get_min<Dimension>();
    }

    //static inline void set(box_type & b, coordinate_type const& value)
    //{
    //    BOOST_GEOMETRY_INDEX_ASSERT(false, "unable to modify a box through view");
    //}
};

template <typename Geometry, typename Box, typename Strategy, typename Tag, std::size_t Dimension>
struct indexed_access<index::detail::bounded_view<Geometry, Box, Strategy, Tag, box_tag>,
                      max_corner, Dimension>
{
    typedef index::detail::bounded_view<Geometry, Box, Strategy, Tag, box_tag> box_type;
    typedef typename geometry::coordinate_type<Box>::type coordinate_type;

    static inline coordinate_type get(box_type const& b)
    {
        return b.template get_max<Dimension>();
    }

    //static inline void set(box_type & b, coordinate_type const& value)
    //{
    //    BOOST_GEOMETRY_INDEX_ASSERT(false, "unable to modify a box through view");
    //}
};

} // namespace traits
#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_INDEX_DETAIL_BOUNDED_VIEW_HPP


#include <boost/python.hpp>
#include <iostream>
#include <cassert>

#include "ndarray.h"
#include <cmath>

using namespace std;
namespace py = boost::python;

void gen_multinomial(PyObject *arr, PyObject *acc_prob_arr) {
    std::default_random_engine re(rand());
    std::uniform_real_distribution<double> unif(0, 1);

    ndarray<double> acc_prob(acc_prob_arr);
    ndarray<int> result(arr);
    assert(result.nd() == 1);
    assert(acc_prob.nd() == 2);
    assert(acc_prob.shape(0) == result.shape(0));
    for (int i = 0; i < result.shape(0); i++) {
        double current = unif(re);
        int j = 0;
        for (; j < acc_prob.shape(1) && current > acc_prob(i, j); j++) ;
        result(i) = j;
    }
}

BOOST_PYTHON_MODULE(multinomial_cpp)
{
    py::def("gen_multinomial", &gen_multinomial);
}


#include <frovedis.hpp>
#include <frovedis/matrix/sliced_vector.hpp>
#include <frovedis/matrix/blas_wrapper.hpp>

#define BOOST_TEST_MODULE FrovedisTest
#include <boost/test/unit_test.hpp>

using namespace frovedis;
using namespace std;

BOOST_AUTO_TEST_CASE( frovedis_test )
{
    int argc = 1;
    char** argv = NULL;
    use_frovedis use(argc, argv);

    colmajor_matrix_local<float> cm (
             make_rowmajor_matrix_local_load<float>("./sample_4x1"));

    // creating slice colmajor vector from entire "colmajor matrix with single column"
    sliced_colmajor_vector_local<float> sv (cm);

    // scaling entire slice with 2
    scal<float> (sv, 2);
    cm.to_rowmajor().save("./out_4x1");

    // if slice was correctly created, this check should pass
    BOOST_CHECK (system("diff ./out_4x1 ref_4x1") == 0);
    system("rm -f ./out_4x1");
}


#include <iostream>                    // std::flush
#include <fstream>                     // std::ofstream
#include <string>                      // std::string
#include <tuple>                       // std::tuple
#include <vector>                      // std::vector
// For External Library
#include <torch/torch.h>               // torch
#include <boost/program_options.hpp>   // boost::program_options
// For Original Header
#include "loss.hpp"                    // Loss
#include "networks.hpp"                // SegNet
#include "dataloader.hpp"              // DataLoader::ImageFolderSegmentWithPaths
#include "visualizer.hpp"              // visualizer::graph

// Define Namespace
namespace po = boost::program_options;

// -------------------
// Validation Function
// -------------------
void valid(po::variables_map &vm, DataLoader::ImageFolderSegmentWithPaths &valid_dataloader, torch::Device &device, Loss &criterion, SegNet &model, const size_t epoch, visualizer::graph &writer){

    // (0) Initialization and Declaration
    size_t correct, correct_per_class, total_class_pixel, class_count;
    size_t iteration;
    float ave_loss, total_loss;
    double pixel_wise_accuracy, ave_pixel_wise_accuracy, total_pixel_wise_accuracy;
    double mean_accuracy, ave_mean_accuracy, total_mean_accuracy;
    std::ofstream ofs;
    std::tuple<torch::Tensor, torch::Tensor, std::vector<std::string>, std::vector<std::string>, std::vector<std::tuple<unsigned char, unsigned char, unsigned char>>> mini_batch;
    torch::Tensor image, label, output, output_argmax, answer_mask, response_mask;
    torch::Tensor loss;

    // (1) Tensor Forward per Mini Batch
    torch::NoGradGuard no_grad;
    model->eval();
    iteration = 0;
    total_loss = 0.0;
    total_pixel_wise_accuracy = 0.0;
    total_mean_accuracy = 0.0;
    while (valid_dataloader(mini_batch)){

        image = std::get<0>(mini_batch).to(device);
        label = std::get<1>(mini_batch).to(device);

        output = model->forward(image);
        loss = criterion(output, label);

        output_argmax = output.exp().argmax(/*dim=*/1, /*keepdim=*/true);
        correct = (label == output_argmax).sum().item<long int>();
        pixel_wise_accuracy = (double)correct / (double)(label.size(0) * label.size(1) * label.size(2));

        class_count = 0;
        mean_accuracy = 0.0;
        for (size_t i = 0; i < std::get<4>(mini_batch).size(); i++){
            answer_mask = torch::full({label.size(0), label.size(1), label.size(2)}, /*value=*/(long int)i, torch::TensorOptions().dtype(torch::kLong)).to(device);
            total_class_pixel = (label == answer_mask).sum().item<long int>();
            if (total_class_pixel != 0){
                response_mask = torch::full({label.size(0), label.size(1), label.size(2)}, /*value=*/2, torch::TensorOptions().dtype(torch::kLong)).to(device);
                correct_per_class = (((label == output_argmax).to(torch::kLong) + (label == answer_mask).to(torch::kLong)) == response_mask).sum().item<long int>();
                mean_accuracy += (double)correct_per_class / (double)total_class_pixel;
                class_count++;
            }
        }
        mean_accuracy = mean_accuracy / (double)class_count;

        total_loss += loss.item<float>();
        total_pixel_wise_accuracy += pixel_wise_accuracy;
        total_mean_accuracy += mean_accuracy;
        iteration++;
    }

    // (2) Calculate Average Loss
    ave_loss = total_loss / (float)iteration;
    ave_pixel_wise_accuracy = total_pixel_wise_accuracy / (double)iteration;
    ave_mean_accuracy = total_mean_accuracy / (double)iteration;

    // (3.1) Record Loss (Log)
    ofs.open("checkpoints/" + vm["dataset"].as<std::string>() + "/log/valid.txt", std::ios::app);
    ofs << "epoch:" << epoch << '/' << vm["epochs"].as<size_t>() << ' ' << std::flush;
    ofs << "classify:" << ave_loss << ' ' << std::flush;
    ofs << "pixel-wise-accuracy:" << ave_pixel_wise_accuracy << ' ' << std::flush;
    ofs << "mean-accuracy:" << ave_mean_accuracy << std::endl;
    ofs.close();

    // (3.2) Record Loss (Graph)
    writer.plot(/*base=*/epoch, /*value=*/{ave_loss});

    // End Processing
    return;

}


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

#include <boost/simd/ieee/functions/frexp.hpp>
#include <boost/simd/include/functions/scalar/is_invalid.hpp>
#include <boost/simd/include/functions/scalar/bitwise_andnot.hpp>
#include <boost/simd/include/functions/scalar/bitwise_and.hpp>
#include <boost/simd/include/functions/scalar/bitwise_or.hpp>
#include <boost/simd/include/functions/scalar/shr.hpp>
#include <boost/simd/include/functions/scalar/bitwise_cast.hpp>
#include <boost/simd/include/constants/limitexponent.hpp>
#include <boost/simd/include/constants/maxexponentm1.hpp>
#include <boost/simd/include/constants/mask1frexp.hpp>
#include <boost/simd/include/constants/mask2frexp.hpp>
#include <boost/simd/include/constants/nbmantissabits.hpp>
#include <boost/simd/include/constants/zero.hpp>
#include <boost/simd/sdk/config.hpp>
#include <boost/dispatch/meta/as_integer.hpp>
#include <boost/dispatch/attributes.hpp>

#ifndef BOOST_SIMD_NO_DENORMALS
#include <boost/simd/include/functions/scalar/is_eqz.hpp>
#include <boost/simd/include/constants/twotonmb.hpp>
#endif

namespace boost { namespace simd { namespace ext
{
  BOOST_DISPATCH_IMPLEMENT          ( frexp_
                                    , tag::cpu_
                                    , (A0)(A1)
                                    , (scalar_< floating_<A0> >)
                                      (scalar_< floating_<A0> >)
                                      (scalar_< integer_<A1>  >)
                                    )
  {
    typedef void result_type;
    BOOST_FORCEINLINE result_type operator()(A0 a0,A0 & r0,A1& r1) const
    {
      if (a0 == 0 || is_invalid(a0))
      {
        r0 = a0;
        r1 = Zero<A1>();
      }
      else
      {
        typedef typename dispatch::meta::as_integer<A0, signed>::type int_type;
        r1 = simd::bitwise_cast<int_type>(b_and(Mask1frexp<A0>(), a0));  // extract exp.
#ifndef BOOST_SIMD_NO_DENORMALS
        A1 t = Zero<A1>();
        if(is_eqz(r1)) // denormal
        {
          a0 *= Twotonmb<A0>();
          r1 = simd::bitwise_cast<int_type>(b_and(Mask1frexp<A0>(), a0));  // extract exp. again
          t = Nbmantissabits<A0>();
        }
#endif
        A0 x  = b_andnot(a0, Mask1frexp<A0>());                          // clear exp. in a0
        r1 = shri(r1,Nbmantissabits<A0>())- Maxexponentm1<A0>();         // compute exp.
        if (r1 > Limitexponent<A0>())
        {
          r1   = 0;
          r0   = a0;
          return;
        }
        r0 = b_or(x,Mask2frexp<A0>());                                    // insert exp.+1 in x
#ifndef BOOST_SIMD_NO_DENORMALS
        r1 -= t;
#endif
      }
    }
  };
} } }

#endif


//  Copyright Benjamin Sobotta 2012

//  Use, modification and distribution are subject to the
//  Boost Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_STATS_SKEW_NORMAL_HPP
#define BOOST_STATS_SKEW_NORMAL_HPP

// http://en.wikipedia.org/wiki/Skew_normal_distribution
// http://azzalini.stat.unipd.it/SN/
// Also:
// Azzalini, A. (1985). "A class of distributions which includes the normal ones".
// Scand. J. Statist. 12: 171-178.

#include <boost/math/distributions/fwd.hpp> // TODO add skew_normal distribution to fwd.hpp!
#include <boost/math/special_functions/owens_t.hpp> // Owen's T function
#include <boost/math/distributions/complement.hpp>
#include <boost/math/distributions/normal.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/tools/tuple.hpp>
#include <boost/math/tools/roots.hpp> // Newton-Raphson
#include <boost/assert.hpp>
#include <boost/math/distributions/detail/generic_mode.hpp> // pdf max finder.

#include <utility>
#include <algorithm> // std::lower_bound, std::distance

namespace boost{ namespace math{

  namespace detail
  {
    template <class RealType, class Policy>
    inline bool check_skew_normal_shape(
      const char* function,
      RealType shape,
      RealType* result,
      const Policy& pol)
    {
      if(!(boost::math::isfinite)(shape))
      {
        *result =
          policies::raise_domain_error<RealType>(function,
          "Shape parameter is %1%, but must be finite!",
          shape, pol);
        return false;
      }
      return true;
    }

  } // namespace detail

  template <class RealType = double, class Policy = policies::policy<> >
  class skew_normal_distribution
  {
  public:
    typedef RealType value_type;
    typedef Policy policy_type;

    skew_normal_distribution(RealType l_location = 0, RealType l_scale = 1, RealType l_shape = 0)
      : location_(l_location), scale_(l_scale), shape_(l_shape)
    { // Default is a 'standard' normal distribution N01. (shape=0 results in the normal distribution with no skew)
      static const char* function = "boost::math::skew_normal_distribution<%1%>::skew_normal_distribution";

      RealType result;
      detail::check_scale(function, l_scale, &result, Policy());
      detail::check_location(function, l_location, &result, Policy());
      detail::check_skew_normal_shape(function, l_shape, &result, Policy());
    }

    RealType location()const
    {
      return location_;
    }

    RealType scale()const
    {
      return scale_;
    }

    RealType shape()const
    {
      return shape_;
    }

  private:
    //
    // Data members:
    //
    RealType location_;  // distribution location.
    RealType scale_;    // distribution scale.
    RealType shape_;    // distribution shape.
  }; // class skew_normal_distribution

  typedef skew_normal_distribution<double> skew_normal;

  template <class RealType, class Policy>
  inline const std::pair<RealType, RealType> range(const skew_normal_distribution<RealType, Policy>& /*dist*/)
  { // Range of permissible values for random variable x.
    using boost::math::tools::max_value;
    return std::pair<RealType, RealType>(
       std::numeric_limits<RealType>::has_infinity ? -std::numeric_limits<RealType>::infinity() : -max_value<RealType>(),
       std::numeric_limits<RealType>::has_infinity ? std::numeric_limits<RealType>::infinity() : max_value<RealType>()); // - to + max value.
  }

  template <class RealType, class Policy>
  inline const std::pair<RealType, RealType> support(const skew_normal_distribution<RealType, Policy>& /*dist*/)
  { // Range of supported values for random variable x.
    // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.

    using boost::math::tools::max_value;
    return std::pair<RealType, RealType>(-max_value<RealType>(),  max_value<RealType>()); // - to + max value.
  }

  template <class RealType, class Policy>
  inline RealType pdf(const skew_normal_distribution<RealType, Policy>& dist, const RealType& x)
  {
    const RealType scale = dist.scale();
    const RealType location = dist.location();
    const RealType shape = dist.shape();

    static const char* function = "boost::math::pdf(const skew_normal_distribution<%1%>&, %1%)";

    RealType result = 0;
    if(false == detail::check_scale(function, scale, &result, Policy()))
    {
      return result;
    }
    if(false == detail::check_location(function, location, &result, Policy()))
    {
      return result;
    }
    if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
    {
      return result;
    }
    if((boost::math::isinf)(x))
    {
       return 0; // pdf + and - infinity is zero.
    }
    // Below produces MSVC 4127 warnings, so the above used instead.
    //if(std::numeric_limits<RealType>::has_infinity && abs(x) == std::numeric_limits<RealType>::infinity())
    //{ // pdf + and - infinity is zero.
    //  return 0;
    //}
    if(false == detail::check_x(function, x, &result, Policy()))
    {
      return result;
    }

    const RealType transformed_x = (x-location)/scale;

    normal_distribution<RealType, Policy> std_normal;

    result = pdf(std_normal, transformed_x) * cdf(std_normal, shape*transformed_x) * 2 / scale;

    return result;
  } // pdf

  template <class RealType, class Policy>
  inline RealType cdf(const skew_normal_distribution<RealType, Policy>& dist, const RealType& x)
  {
    const RealType scale = dist.scale();
    const RealType location = dist.location();
    const RealType shape = dist.shape();

    static const char* function = "boost::math::cdf(const skew_normal_distribution<%1%>&, %1%)";
    RealType result = 0;
    if(false == detail::check_scale(function, scale, &result, Policy()))
    {
      return result;
    }
    if(false == detail::check_location(function, location, &result, Policy()))
    {
      return result;
    }
    if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
    {
      return result;
    }
    if((boost::math::isinf)(x))
    {
      if(x < 0) return 0; // -infinity
      return 1; // + infinity
    }
    // These produce MSVC 4127 warnings, so the above used instead.
    //if(std::numeric_limits<RealType>::has_infinity && x == std::numeric_limits<RealType>::infinity())
    //{ // cdf +infinity is unity.
    //  return 1;
    //}
    //if(std::numeric_limits<RealType>::has_infinity && x == -std::numeric_limits<RealType>::infinity())
    //{ // cdf -infinity is zero.
    //  return 0;
    //}
    if(false == detail::check_x(function, x, &result, Policy()))
    {
      return result;
    }

    const RealType transformed_x = (x-location)/scale;

    normal_distribution<RealType, Policy> std_normal;

    result = cdf(std_normal, transformed_x) - owens_t(transformed_x, shape)*static_cast<RealType>(2);

    return result;
  } // cdf

  template <class RealType, class Policy>
  inline RealType cdf(const complemented2_type<skew_normal_distribution<RealType, Policy>, RealType>& c)
  {
    const RealType scale = c.dist.scale();
    const RealType location = c.dist.location();
    const RealType shape = c.dist.shape();
    const RealType x = c.param;

    static const char* function = "boost::math::cdf(const complement(skew_normal_distribution<%1%>&), %1%)";

    if((boost::math::isinf)(x))
    {
      if(x < 0) return 1; // cdf complement -infinity is unity.
      return 0; // cdf complement +infinity is zero
    }
    // These produce MSVC 4127 warnings, so the above used instead.
    //if(std::numeric_limits<RealType>::has_infinity && x == std::numeric_limits<RealType>::infinity())
    //{ // cdf complement +infinity is zero.
    //  return 0;
    //}
    //if(std::numeric_limits<RealType>::has_infinity && x == -std::numeric_limits<RealType>::infinity())
    //{ // cdf complement -infinity is unity.
    //  return 1;
    //}
    RealType result = 0;
    if(false == detail::check_scale(function, scale, &result, Policy()))
      return result;
    if(false == detail::check_location(function, location, &result, Policy()))
      return result;
    if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
      return result;
    if(false == detail::check_x(function, x, &result, Policy()))
      return result;

    const RealType transformed_x = (x-location)/scale;

    normal_distribution<RealType, Policy> std_normal;

    result = cdf(complement(std_normal, transformed_x)) + owens_t(transformed_x, shape)*static_cast<RealType>(2);
    return result;
  } // cdf complement

  template <class RealType, class Policy>
  inline RealType location(const skew_normal_distribution<RealType, Policy>& dist)
  {
    return dist.location();
  }

  template <class RealType, class Policy>
  inline RealType scale(const skew_normal_distribution<RealType, Policy>& dist)
  {
    return dist.scale();
  }

  template <class RealType, class Policy>
  inline RealType shape(const skew_normal_distribution<RealType, Policy>& dist)
  {
    return dist.shape();
  }

  template <class RealType, class Policy>
  inline RealType mean(const skew_normal_distribution<RealType, Policy>& dist)
  {
    BOOST_MATH_STD_USING  // for ADL of std functions

    using namespace boost::math::constants;

    //const RealType delta = dist.shape() / sqrt(static_cast<RealType>(1)+dist.shape()*dist.shape());

    //return dist.location() + dist.scale() * delta * root_two_div_pi<RealType>();

    return dist.location() + dist.scale() * dist.shape() / sqrt(pi<RealType>()+pi<RealType>()*dist.shape()*dist.shape()) * root_two<RealType>();
  }

  template <class RealType, class Policy>
  inline RealType variance(const skew_normal_distribution<RealType, Policy>& dist)
  {
    using namespace boost::math::constants;

    const RealType delta2 = static_cast<RealType>(1) / (static_cast<RealType>(1)+static_cast<RealType>(1)/(dist.shape()*dist.shape()));
    //const RealType inv_delta2 = static_cast<RealType>(1)+static_cast<RealType>(1)/(dist.shape()*dist.shape());

    RealType variance = dist.scale()*dist.scale()*(static_cast<RealType>(1)-two_div_pi<RealType>()*delta2);
    //RealType variance = dist.scale()*dist.scale()*(static_cast<RealType>(1)-two_div_pi<RealType>()/inv_delta2);

    return variance;
  }

  namespace detail
  {
    /*
      TODO No closed expression for mode, so use max of pdf.
    */

    template <class RealType, class Policy>
    inline RealType mode_fallback(const skew_normal_distribution<RealType, Policy>& dist)
    { // mode.
        static const char* function = "mode(skew_normal_distribution<%1%> const&)";
        const RealType scale = dist.scale();
        const RealType location = dist.location();
        const RealType shape = dist.shape();

        RealType result;
        if(!detail::check_scale(
          function,
          scale, &result, Policy())
          ||
        !detail::check_skew_normal_shape(
          function,
          shape,
          &result,
          Policy()))
        return result;

        if( shape == 0 )
        {
          return location;
        }

        if( shape < 0 )
        {
          skew_normal_distribution<RealType, Policy> D(0, 1, -shape);
          result = mode_fallback(D);
          result = location-scale*result;
          return result;
        }

        BOOST_MATH_STD_USING

        // 21 elements
        static const RealType shapes[] = {
          0.0,
          1.000000000000000e-004,
          2.069138081114790e-004,
          4.281332398719396e-004,
          8.858667904100824e-004,
          1.832980710832436e-003,
          3.792690190732250e-003,
          7.847599703514606e-003,
          1.623776739188722e-002,
          3.359818286283781e-002,
          6.951927961775606e-002,
          1.438449888287663e-001,
          2.976351441631319e-001,
          6.158482110660261e-001,
          1.274274985703135e+000,
          2.636650898730361e+000,
          5.455594781168514e+000,
          1.128837891684688e+001,
          2.335721469090121e+001,
          4.832930238571753e+001,
          1.000000000000000e+002};

        // 21 elements
        static const RealType guess[] = {
          0.0,
          5.000050000525391e-005,
          1.500015000148736e-004,
          3.500035000350010e-004,
          7.500075000752560e-004,
          1.450014500145258e-003,
          3.050030500305390e-003,
          6.250062500624765e-003,
          1.295012950129504e-002,
          2.675026750267495e-002,
          5.525055250552491e-002,
          1.132511325113255e-001,
          2.249522495224952e-001,
          3.992539925399257e-001,
          5.353553535535358e-001,
          4.954549545495457e-001,
          3.524535245352451e-001,
          2.182521825218249e-001,
          1.256512565125654e-001,
          6.945069450694508e-002,
          3.735037350373460e-002
        };

        const RealType* result_ptr = std::lower_bound(shapes, shapes+21, shape);

        typedef typename std::iterator_traits<RealType*>::difference_type diff_type;

        const diff_type d = std::distance(shapes, result_ptr);

        BOOST_ASSERT(d > static_cast<diff_type>(0));

        // refine
        if(d < static_cast<diff_type>(21)) // shape smaller 100
        {
          result = guess[d-static_cast<diff_type>(1)]
            + (guess[d]-guess[d-static_cast<diff_type>(1)])/(shapes[d]-shapes[d-static_cast<diff_type>(1)])
            * (shape-shapes[d-static_cast<diff_type>(1)]);
        }
        else // shape greater 100
        {
          result = 1e-4;
        }

        skew_normal_distribution<RealType, Policy> helper(0, 1, shape);

        result = detail::generic_find_mode_01(helper, result, function);

        result = result*scale + location;

        return result;
    } // mode_fallback

    /*
     * TODO No closed expression for mode, so use f'(x) = 0
     */
    template <class RealType, class Policy>
    struct skew_normal_mode_functor
    {
      skew_normal_mode_functor(const boost::math::skew_normal_distribution<RealType, Policy> dist)
        : distribution(dist)
      {
      }

      boost::math::tuple<RealType, RealType> operator()(RealType const& x)
      {
        normal_distribution<RealType, Policy> std_normal;
        const RealType shape = distribution.shape();
        const RealType pdf_x = pdf(distribution, x);
        const RealType normpdf_x = pdf(std_normal, x);
        const RealType normpdf_ax = pdf(std_normal, x*shape);
        RealType fx = static_cast<RealType>(2)*shape*normpdf_ax*normpdf_x - x*pdf_x;
        RealType dx = static_cast<RealType>(2)*shape*x*normpdf_x*normpdf_ax*(static_cast<RealType>(1) + shape*shape) + pdf_x + x*fx;
        // return both function evaluation difference f(x) and 1st derivative f'(x).
        return boost::math::make_tuple(fx, -dx);
      }
    private:
      const boost::math::skew_normal_distribution<RealType, Policy> distribution;
    };

  } // namespace detail

  template <class RealType, class Policy>
  inline RealType mode(const skew_normal_distribution<RealType, Policy>& dist)
  {
    const RealType scale = dist.scale();
    const RealType location = dist.location();
    const RealType shape = dist.shape();

    static const char* function = "boost::math::mode(const skew_normal_distribution<%1%>&, %1%)";

    RealType result = 0;
    if(false == detail::check_scale(function, scale, &result, Policy()))
      return result;
    if(false == detail::check_location(function, location, &result, Policy()))
      return result;
    if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
      return result;

    if( shape == 0 )
    {
      return location;
    }

    if( shape < 0 )
    {
      skew_normal_distribution<RealType, Policy> D(0, 1, -shape);
      result = mode(D);
      result = location-scale*result;
      return result;
    }

    // 21 elements
    static const RealType shapes[] = {
      0.0,
      static_cast<RealType>(1.000000000000000e-004),
      static_cast<RealType>(2.069138081114790e-004),
      static_cast<RealType>(4.281332398719396e-004),
      static_cast<RealType>(8.858667904100824e-004),
      static_cast<RealType>(1.832980710832436e-003),
      static_cast<RealType>(3.792690190732250e-003),
      static_cast<RealType>(7.847599703514606e-003),
      static_cast<RealType>(1.623776739188722e-002),
      static_cast<RealType>(3.359818286283781e-002),
      static_cast<RealType>(6.951927961775606e-002),
      static_cast<RealType>(1.438449888287663e-001),
      static_cast<RealType>(2.976351441631319e-001),
      static_cast<RealType>(6.158482110660261e-001),
      static_cast<RealType>(1.274274985703135e+000),
      static_cast<RealType>(2.636650898730361e+000),
      static_cast<RealType>(5.455594781168514e+000),
      static_cast<RealType>(1.128837891684688e+001),
      static_cast<RealType>(2.335721469090121e+001),
      static_cast<RealType>(4.832930238571753e+001),
      static_cast<RealType>(1.000000000000000e+002)
    };

    // 21 elements
    static const RealType guess[] = {
      0.0,
      static_cast<RealType>(5.000050000525391e-005),
      static_cast<RealType>(1.500015000148736e-004),
      static_cast<RealType>(3.500035000350010e-004),
      static_cast<RealType>(7.500075000752560e-004),
      static_cast<RealType>(1.450014500145258e-003),
      static_cast<RealType>(3.050030500305390e-003),
      static_cast<RealType>(6.250062500624765e-003),
      static_cast<RealType>(1.295012950129504e-002),
      static_cast<RealType>(2.675026750267495e-002),
      static_cast<RealType>(5.525055250552491e-002),
      static_cast<RealType>(1.132511325113255e-001),
      static_cast<RealType>(2.249522495224952e-001),
      static_cast<RealType>(3.992539925399257e-001),
      static_cast<RealType>(5.353553535535358e-001),
      static_cast<RealType>(4.954549545495457e-001),
      static_cast<RealType>(3.524535245352451e-001),
      static_cast<RealType>(2.182521825218249e-001),
      static_cast<RealType>(1.256512565125654e-001),
      static_cast<RealType>(6.945069450694508e-002),
      static_cast<RealType>(3.735037350373460e-002)
    };

    const RealType* result_ptr = std::lower_bound(shapes, shapes+21, shape);

    typedef typename std::iterator_traits<RealType*>::difference_type diff_type;

    const diff_type d = std::distance(shapes, result_ptr);

    BOOST_ASSERT(d > static_cast<diff_type>(0));

    // TODO: make the search bounds smarter, depending on the shape parameter
    RealType search_min = 0; // below zero was caught above
    RealType search_max = 0.55f; // will never go above 0.55

    // refine
    if(d < static_cast<diff_type>(21)) // shape smaller 100
    {
      // it is safe to assume that d > 0, because shape==0.0 is caught earlier
      result = guess[d-static_cast<diff_type>(1)]
        + (guess[d]-guess[d-static_cast<diff_type>(1)])/(shapes[d]-shapes[d-static_cast<diff_type>(1)])
        * (shape-shapes[d-static_cast<diff_type>(1)]);
    }
    else // shape greater 100
    {
      result = 1e-4f;
      search_max = guess[19]; // set 19 instead of 20 to have a safety margin because the table may not be exact @ shape=100
    }

    const int get_digits = policies::digits<RealType, Policy>();// get digits from policy,
    boost::uintmax_t m = policies::get_max_root_iterations<Policy>(); // and max iterations.

    skew_normal_distribution<RealType, Policy> helper(0, 1, shape);

    result = tools::newton_raphson_iterate(detail::skew_normal_mode_functor<RealType, Policy>(helper), result,
      search_min, search_max, get_digits, m);

    result = result*scale + location;

    return result;
  }

  template <class RealType, class Policy>
  inline RealType skewness(const skew_normal_distribution<RealType, Policy>& dist)
  {
    BOOST_MATH_STD_USING  // for ADL of std functions
    using namespace boost::math::constants;

    static const RealType factor = four_minus_pi<RealType>()/static_cast<RealType>(2);
    const RealType delta = dist.shape() / sqrt(static_cast<RealType>(1)+dist.shape()*dist.shape());

    return factor * pow(root_two_div_pi<RealType>() * delta, 3) /
      pow(static_cast<RealType>(1)-two_div_pi<RealType>()*delta*delta, static_cast<RealType>(1.5));
  }

  template <class RealType, class Policy>
  inline RealType kurtosis(const skew_normal_distribution<RealType, Policy>& dist)
  {
    return kurtosis_excess(dist)+static_cast<RealType>(3);
  }

  template <class RealType, class Policy>
  inline RealType kurtosis_excess(const skew_normal_distribution<RealType, Policy>& dist)
  {
    using namespace boost::math::constants;

    static const RealType factor = pi_minus_three<RealType>()*static_cast<RealType>(2);

    const RealType delta2 = static_cast<RealType>(1) / (static_cast<RealType>(1)+static_cast<RealType>(1)/(dist.shape()*dist.shape()));

    const RealType x = static_cast<RealType>(1)-two_div_pi<RealType>()*delta2;
    const RealType y = two_div_pi<RealType>() * delta2;

    return factor * y*y / (x*x);
  }

  namespace detail
  {

    template <class RealType, class Policy>
    struct skew_normal_quantile_functor
    {
      skew_normal_quantile_functor(const boost::math::skew_normal_distribution<RealType, Policy> dist, RealType const& p)
        : distribution(dist), prob(p)
      {
      }

      boost::math::tuple<RealType, RealType> operator()(RealType const& x)
      {
        RealType c = cdf(distribution, x);
        RealType fx = c - prob;  // Difference cdf - value - to minimize.
        RealType dx = pdf(distribution, x); // pdf is 1st derivative.
        // return both function evaluation difference f(x) and 1st derivative f'(x).
        return boost::math::make_tuple(fx, dx);
      }
    private:
      const boost::math::skew_normal_distribution<RealType, Policy> distribution;
      RealType prob;
    };

  } // namespace detail

  template <class RealType, class Policy>
  inline RealType quantile(const skew_normal_distribution<RealType, Policy>& dist, const RealType& p)
  {
    const RealType scale = dist.scale();
    const RealType location = dist.location();
    const RealType shape = dist.shape();

    static const char* function = "boost::math::quantile(const skew_normal_distribution<%1%>&, %1%)";

    RealType result = 0;
    if(false == detail::check_scale(function, scale, &result, Policy()))
      return result;
    if(false == detail::check_location(function, location, &result, Policy()))
      return result;
    if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
      return result;
    if(false == detail::check_probability(function, p, &result, Policy()))
      return result;

    // Compute initial guess via Cornish-Fisher expansion.
    RealType x = -boost::math::erfc_inv(2 * p, Policy()) * constants::root_two<RealType>();

    // Avoid unnecessary computations if there is no skew.
    if(shape != 0)
    {
      const RealType skew = skewness(dist);
      const RealType exk = kurtosis_excess(dist);

      x = x + (x*x-static_cast<RealType>(1))*skew/static_cast<RealType>(6)
      + x*(x*x-static_cast<RealType>(3))*exk/static_cast<RealType>(24)
      - x*(static_cast<RealType>(2)*x*x-static_cast<RealType>(5))*skew*skew/static_cast<RealType>(36);
    } // if(shape != 0)

    result = standard_deviation(dist)*x+mean(dist);

    // handle special case of non-skew normal distribution.
    if(shape == 0)
      return result;

    // refine the result by numerically searching the root of (p-cdf)

    const RealType search_min = range(dist).first;
    const RealType search_max = range(dist).second;

    const int get_digits = policies::digits<RealType, Policy>();// get digits from policy,
    boost::uintmax_t m = policies::get_max_root_iterations<Policy>(); // and max iterations.

    result = tools::newton_raphson_iterate(detail::skew_normal_quantile_functor<RealType, Policy>(dist, p), result,
      search_min, search_max, get_digits, m);

    return result;
  } // quantile

  template <class RealType, class Policy>
  inline RealType quantile(const complemented2_type<skew_normal_distribution<RealType, Policy>, RealType>& c)
  {
    const RealType scale = c.dist.scale();
    const RealType location = c.dist.location();
    const RealType shape = c.dist.shape();

    static const char* function = "boost::math::quantile(const complement(skew_normal_distribution<%1%>&), %1%)";
    RealType result = 0;
    if(false == detail::check_scale(function, scale, &result, Policy()))
      return result;
    if(false == detail::check_location(function, location, &result, Policy()))
      return result;
    if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
      return result;
    RealType q = c.param;
    if(false == detail::check_probability(function, q, &result, Policy()))
      return result;

    skew_normal_distribution<RealType, Policy> D(-location, scale, -shape);

    result = -quantile(D, q);

    return result;
  } // quantile

} // namespace math
} // namespace boost

// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>

#endif // BOOST_STATS_SKEW_NORMAL_HPP


/*
==============================================================================
KratosConvectionDiffusionApplication
A library based on:
Kratos
A General Purpose Software for Multi-Physics Finite Element Analysis
Version 1.0 (Released on march 05, 2007).

Copyright 2007
Pooyan Dadvand, Riccardo Rossi
pooyan@cimne.upc.edu
rrossi@cimne.upc.edu
- CIMNE (International Center for Numerical Methods in Engineering),
Gran Capita' s/n, 08034 Barcelona, Spain

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

Distribution of this code for  any  commercial purpose  is permissible
ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNERS.

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

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

==============================================================================
*/
//
//   Project Name:        Kratos
//   Last modified by:    $Author: antonia $
//   Date:                $Date: 2008-03-11 14:06:15 $
//   Revision:            $Revision: 1.4 $
//
//

// System includes

// External includes
#include <boost/python.hpp>

// Project includes
#include "includes/define.h"
#include "processes/process.h"
#include "custom_python/add_custom_utilities_to_python.h"
#include "custom_utilities/face_heat_utilities.h"
#include "custom_utilities/pure_convection_tools.h"
#include "custom_utilities/pure_convection_CrankN_tools.h"

#include "spaces/ublas_space.h"
#include "linear_solvers/linear_solver.h"

namespace Kratos
{

namespace Python
{

  void  AddCustomUtilitiesToPython()
  {
	using namespace boost::python;

	  class_<FaceHeatUtilities>("FaceHeatUtilities", init<>())
		.def("ApplyFaceHeat",&FaceHeatUtilities::ApplyFaceHeat)
		;

	  typedef UblasSpace<double, CompressedMatrix, Vector> SparseSpaceType;
	  typedef UblasSpace<double, Matrix, Vector> LocalSpaceType;
	  typedef LinearSolver<SparseSpaceType, LocalSpaceType > LinearSolverType;

	  class_< PureConvectionUtilities< 2, SparseSpaceType, LinearSolverType >,  boost::noncopyable >	("PureConvectionUtilities2D", init<	>() )
			  .def("ConstructSystem",&PureConvectionUtilities< 2, SparseSpaceType, LinearSolverType >::ConstructSystem)
			  .def("CalculateProjection",&PureConvectionUtilities< 2, SparseSpaceType, LinearSolverType >::CalculateProjection)
			  .def("ConvectScalarVar",&PureConvectionUtilities< 2, SparseSpaceType, LinearSolverType >::ConvectScalarVar)
			  .def("ClearSystem",&PureConvectionUtilities< 2, SparseSpaceType, LinearSolverType >::ClearSystem)
			  ;

	  class_< PureConvectionUtilities< 3, SparseSpaceType, LinearSolverType >,  boost::noncopyable >	("PureConvectionUtilities3D", init<	>() )
			  .def("ConstructSystem",&PureConvectionUtilities< 3, SparseSpaceType, LinearSolverType >::ConstructSystem)
			  .def("CalculateProjection",&PureConvectionUtilities< 3, SparseSpaceType, LinearSolverType >::CalculateProjection)
			  .def("ConvectScalarVar",&PureConvectionUtilities< 3, SparseSpaceType, LinearSolverType >::ConvectScalarVar)
			  .def("ClearSystem",&PureConvectionUtilities< 3, SparseSpaceType, LinearSolverType >::ClearSystem)
			  ;

	class_< PureConvectionCrankNUtilities< 2, SparseSpaceType, LinearSolverType >,  boost::noncopyable >	("PureConvectionCrankNUtilities2D", init<	>() )
			  .def("ConstructSystem",&PureConvectionCrankNUtilities< 2, SparseSpaceType, LinearSolverType >::ConstructSystem)
			  .def("CalculateProjection",&PureConvectionCrankNUtilities< 2, SparseSpaceType, LinearSolverType >::CalculateProjection)
			  .def("ConvectScalarVar",&PureConvectionCrankNUtilities< 2, SparseSpaceType, LinearSolverType >::ConvectScalarVar)
			  .def("ClearSystem",&PureConvectionCrankNUtilities< 2, SparseSpaceType, LinearSolverType >::ClearSystem)
			  ;

	  class_< PureConvectionCrankNUtilities< 3, SparseSpaceType, LinearSolverType >,  boost::noncopyable >	("PureConvectionCrankNUtilities3D", init<	>() )
			  .def("ConstructSystem",&PureConvectionCrankNUtilities< 3, SparseSpaceType, LinearSolverType >::ConstructSystem)
			  .def("CalculateProjection",&PureConvectionCrankNUtilities< 3, SparseSpaceType, LinearSolverType >::CalculateProjection)
			  .def("ConvectScalarVar",&PureConvectionCrankNUtilities< 3, SparseSpaceType, LinearSolverType >::ConvectScalarVar)
			  .def("ClearSystem",&PureConvectionCrankNUtilities< 3, SparseSpaceType, LinearSolverType >::ClearSystem)
			  ;

  }

}  // namespace Python.

} // Namespace Kratos