//| This file is a part of the sferes2 framework.
//| Copyright 2009, ISIR / Universite Pierre et Marie Curie (UPMC)
//| Main contributor(s): Jean-Baptiste Mouret, mouret@isir.fr
//|
//| This software is a computer program whose purpose is to facilitate
//| experiments in evolutionary computation and evolutionary robotics.
//|
//| This software is governed by the CeCILL license under French law
//| and abiding by the rules of distribution of free software.  You
//| can use, modify and/ or redistribute the software under the terms
//| of the CeCILL license as circulated by CEA, CNRS and INRIA at the
//| following URL "http://www.cecill.info".
//|
//| As a counterpart to the access to the source code and rights to
//| copy, modify and redistribute granted by the license, users are
//| provided only with a limited warranty and the software's author,
//| the holder of the economic rights, and the successive licensors
//| have only limited liability.
//|
//| In this respect, the user's attention is drawn to the risks
//| associated with loading, using, modifying and/or developing or
//| reproducing the software by the user in light of its specific
//| status of free software, that may mean that it is complicated to
//| manipulate, and that also therefore means that it is reserved for
//| developers and experienced professionals having in-depth computer
//| knowledge. Users are therefore encouraged to load and test the
//| software's suitability as regards their requirements in conditions
//| enabling the security of their systems and/or data to be ensured
//| and, more generally, to use and operate it in the same conditions
//| as regards security.
//|
//| The fact that you are presently reading this means that you have
//| had knowledge of the CeCILL license and that you accept its terms.

#ifndef NO_PARALLEL
#define NO_PARALLEL
#endif

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE cmaes

#include <boost/test/unit_test.hpp>
#include <cmath>
#include <iostream>
#include <Eigen/Core>

#include <sferes/phen/parameters.hpp>
#include <sferes/gen/float.hpp>
#include <sferes/ea/cmaes.hpp>
#include <sferes/eval/eval.hpp>
#include <sferes/stat/best_fit.hpp>
#include <sferes/eval/parallel.hpp>
#include <sferes/modif/dummy.hpp>

using namespace sferes;

struct Params {
  struct pop {
    SFERES_CONST size_t size = 1;//not used by CMAES
    SFERES_CONST unsigned nb_gen = 650;
    SFERES_CONST int dump_period = -1;
  };
  struct cmaes {
    SFERES_CONST float sigma = 0.5f;
    SFERES_CONST float max_value = -1e-10;
  };

  struct parameters {
    SFERES_CONST float min = 0.0f;
    SFERES_CONST float max = 1.0f;
  };
};

float felli(const std::vector<float>& xx) {
  Eigen::VectorXf x = Eigen::VectorXf::Zero(xx.size());
  for (size_t i = 0; i < xx.size(); ++i)
    x[i] = xx[i];
  Eigen::VectorXf v = Eigen::VectorXf::Zero(x.size());
  for (size_t i = 0; i < v.size(); ++i)
    v[i] = powf(1e6, i / (x.size() - 1.0f));
  return v.dot((x.array() * x.array()).matrix());
}

SFERES_FITNESS(FitElli, sferes::fit::Fitness) {
public:
  FitElli(const FitElli& f) {
    assert(0);
    BOOST_ERROR("copy constructors should be useless");
  }
  FitElli& operator=(const FitElli& f) {
    BOOST_ERROR("= operator should be useless");
    return *this;
  }
  FitElli() : _this(this) {}
  template<typename Indiv>
  void eval(Indiv& ind) {
    this->_value = -felli(ind.data());
  }
  FitElli* _this;
};

BOOST_AUTO_TEST_CASE(test_cmaes) {
  srand(time(0));
  typedef gen::Float<10, Params> gen_t;
  typedef phen::Parameters<gen_t, FitElli<Params>, Params> phen_t;
  typedef eval::Parallel<Params> eval_t;
  typedef boost::fusion::vector<stat::BestFit<phen_t, Params> >  stat_t;
  typedef modif::Dummy<> modifier_t;
  typedef ea::Cmaes<phen_t, eval_t, stat_t, modifier_t, Params> ea_t;
  ea_t ea;

  ea.run();
  float best = ea.stat<0>().best()->fit().value();
  std::cout<<"best fit (cmaes):"<<best<<std::endl;
  BOOST_CHECK(best > -1e-3);

}


/*
 * headers.hpp
 *
 *  Created on: Sep 2, 2018
 *      Author: prakash
 */

#ifndef HEADERS_HPP_
#define HEADERS_HPP_

#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <iterator>
#include <typeinfo>
#include <utility>
#include <functional>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <iomanip>
#include <cmath>
#include <limits>
#include <time.h>

/* Library Dependencies: Boost, Z3 */
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graphviz.hpp>
#include "z3++.h"

using namespace std;
const double PI = 3.141592653589793238;

enum CompileAlgorithm{
	CompileOpt, CompileDijkstra, CompileRevSwaps
};

extern int CompilerAlgorithm;
extern int ErrorScaleFactor;

#endif /* HEADERS_HPP_ */


#include <boost/mpi/collectives/broadcast.hpp>
#include <boost/mpi/collectives/reduce.hpp>
#include <boost/mpi/communicator.hpp>
#include <boost/mpi/environment.hpp>
#include <boost/serialization/string.hpp>
#include <cmath>
#include <cstdlib>
#include <functional>
#include <iostream>

namespace bmpi = boost::mpi;

double f(double x) { return (x <= 0) ? 0.0 : 1.0 / sqrt(x); }

class Distributor {
  const bmpi::environment env;

public:
  const bmpi::communicator world;
  const int rank;
  const int size;
  bool isMaster() { return rank == 0; }
  Distributor(int argc, char **argv)
      : env(argc, argv), world(), rank(world.rank()), size(world.size()) {}
};

int main(int argc, char **argv) {
  Distributor dist(argc, argv);
  int n;

  if (dist.isMaster()) {
    n = 1000;
  }

  double quadrile = 0.0;

  boost::mpi::broadcast(dist.world, n, 0);

  double lower_limit = 0.0;
  double upper_limit = 1.0;
  double h = (upper_limit - lower_limit) / (double)(n); // dx

  double quadrile_chunk = 0.0;
  double n_chunk = 0;

  // Divide the work for this rank
  for (int i = dist.rank + 1; i < n; i += dist.size) {
    double x = ((double)(2 * n - 2 * i + 1) * lower_limit) +
               ((double)(2 * i - 1) * upper_limit) / (double)(2 * n);
    n_chunk += 1;
    quadrile_chunk += f(x);
  }

  quadrile_chunk = quadrile_chunk * h;

  std::cout << "Quad Chunk " << quadrile_chunk << " points: " << n_chunk
            << std::endl;

  if (dist.isMaster()) {
    boost::mpi::reduce(dist.world, quadrile_chunk, quadrile,
                       std::plus<double>(), 0);
  } else {
    boost::mpi::reduce(dist.world, quadrile_chunk, std::plus<double>(), 0);
  }

  if (dist.isMaster()) {
    std::cout << "Result Quadrile " << quadrile << std::endl;
  }

  return EXIT_SUCCESS;
}


// smooth_feedback: Control theory on Lie groups
// https://github.com/pettni/smooth_feedback
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
//
// Copyright (c) 2021 Petter Nilsson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <gtest/gtest.h>

#include <Eigen/Core>

#include <iostream>

#include "smooth/feedback/collocation/mesh.hpp"

template<typename T>
using Vec = Eigen::VectorX<T>;

using Vecd = Vec<double>;

TEST(CollocationMesh, Basic)
{
  smooth::feedback::Mesh<5, 10> m;
  m.refine_ph(0, 5 * 10);
  ASSERT_EQ(m.N_ivals(), 10);

  for (auto i = 0u; i < 10; ++i) {
    auto ns = m.interval_nodes(i);
    ASSERT_DOUBLE_EQ(ns.front(), i * 0.1);
  }

  // will only increase degree
  m.refine_ph(1, 10);
  ASSERT_EQ(m.N_ivals(), 10);
  {
    auto ns = m.interval_nodes(1);
    ASSERT_DOUBLE_EQ(ns.front(), 0.1);
  }

  // actually split it
  m.refine_ph(1, 13);
  ASSERT_EQ(m.N_ivals(), 12);
  {
    auto n1 = m.interval_nodes(1);
    auto n2 = m.interval_nodes(2);
    auto n3 = m.interval_nodes(3);
    ASSERT_DOUBLE_EQ(n1.front(), 0.1);
    ASSERT_DOUBLE_EQ(n2.front(), 0.1 + 0.1 / 3);
    ASSERT_DOUBLE_EQ(n3.front(), 0.1 + 2 * 0.1 / 3);
  }

  m.refine_ph(2, 27);

  m.refine_ph(7, 33);
  m.refine_ph(9, 22);

  auto alln = m.all_nodes();

  for (auto [d1, d2] : smooth::utils::zip(alln, alln | std::views::drop(1))) { ASSERT_LE(d1, d2); }
}

TEST(CollocationMesh, Constructor)
{
  for (std::size_t i = 0; i < 100; ++i) {
    const auto Nexpected = std::max(i, 1UL);
    smooth::feedback::Mesh<5, 10> m(i);
    ASSERT_EQ(m.N_ivals(), Nexpected);
    for (std::size_t j = 0; j < Nexpected; ++j) { ASSERT_EQ(m.N_colloc_ival(j), 5LU); }
  }

  for (std::size_t i = 5; i <= 10; ++i) {
    smooth::feedback::Mesh<5, 10> m(10, i);
    for (std::size_t j = 0; j < 10; ++j) { ASSERT_EQ(m.N_colloc_ival(j), i); }
  }
}

TEST(CollocationMesh, DifferentiationIntegration)
{
  smooth::feedback::Mesh<8, 8> m;
  m.refine_ph(0, 40);

  // define a function and its derivative
  const auto x  = [](double t) -> double { return 1 + 2 * t + 3 * t * t + 4 * t * t * t; };
  const auto dx = [](double t) -> double { return 2 + 3 * 2 * t + 4 * 3 * t * t; };

  for (auto ival = 0u; ival < m.N_ivals(); ++ival) {
    const auto N = m.N_colloc_ival(ival);
    auto taus    = m.interval_nodes(ival);

    // specify function values on mesh
    Eigen::RowVectorXd xvals(N + 1);
    for (const auto [i, tau] : smooth::utils::zip(std::views::iota(0u, N + 1), taus)) {
      xvals(i) = x(tau);
    }
    Eigen::RowVectorXd dxvals(N);
    for (const auto [i, tau] : smooth::utils::zip(std::views::iota(0u, N), taus)) {
      dxvals(i) = dx(tau);
    }

    // derivative and integral matrices
    const auto D = m.interval_diffmat(ival);
    const auto I = m.interval_intmat(ival);

    // expect [dx0 ... dxN-1] = [x0 ... xN] * D
    std::cout << dxvals << std::endl;
    std::cout << xvals * D << std::endl;
    ASSERT_TRUE(dxvals.isApprox(xvals * D));

    // expect [x1 ... xN] = [x0 ... x0] + [dx0 ... dxN-1] * I
    ASSERT_TRUE(xvals.rightCols(N).isApprox(xvals.leftCols(1).replicate(1, N) + dxvals * I));
  }
}

TEST(CollocationMesh, FunctionEval)
{
  smooth::feedback::Mesh<5, 5> m;

  {
    Eigen::MatrixXd vals = Eigen::MatrixXd::Ones(3, m.N_colloc() + 1);

    const auto x1 = m.eval<Eigen::VectorXd>(0, vals.colwise());
    ASSERT_TRUE(x1.isApprox(Eigen::VectorXd::Ones(3)));

    const auto x2 = m.eval<Eigen::VectorXd>(0.5, vals.colwise());
    ASSERT_TRUE(x2.isApprox(Eigen::VectorXd::Ones(3)));

    const auto x3 = m.eval<Eigen::VectorXd>(1, vals.colwise());
    ASSERT_TRUE(x3.isApprox(Eigen::VectorXd::Ones(3)));
  }

  {
    Eigen::MatrixXd vals = Eigen::MatrixXd::Ones(3, m.N_colloc());

    const auto x1 = m.eval<Eigen::VectorXd>(0, vals.colwise(), 0, false);
    ASSERT_TRUE(x1.isApprox(Eigen::VectorXd::Ones(3)));

    const auto x2 = m.eval<Eigen::VectorXd>(0.5, vals.colwise(), 0, false);
    ASSERT_TRUE(x2.isApprox(Eigen::VectorXd::Ones(3)));

    const auto x3 = m.eval<Eigen::VectorXd>(1, vals.colwise(), 0, false);
    ASSERT_TRUE(x3.isApprox(Eigen::VectorXd::Ones(3)));
  }

  m.refine_ph(0, 40);

  {
    Eigen::MatrixXd vals_refined = Eigen::MatrixXd::Ones(3, m.N_colloc() + 1);

    const auto x1 = m.eval<Eigen::VectorXd>(0, vals_refined.colwise());
    ASSERT_TRUE(x1.isApprox(Eigen::VectorXd::Ones(3)));

    const auto x2 = m.eval<Eigen::VectorXd>(0.5, vals_refined.colwise());
    ASSERT_TRUE(x2.isApprox(Eigen::VectorXd::Ones(3)));

    const auto x3 = m.eval<Eigen::VectorXd>(1, vals_refined.colwise());
    ASSERT_TRUE(x3.isApprox(Eigen::VectorXd::Ones(3)));
  }
}

TEST(CollocationMesh, IntervalNodes)
{
  smooth::feedback::Mesh<5, 5> mesh;
  mesh.refine_ph(0, 10);

  for (const auto [d1, d2] : smooth::utils::zip(mesh.interval_nodes(0), mesh.interval_nodes(1))) {
    ASSERT_NEAR(d1 + 0.5, d2, 1e-9);
  }

  for (const auto [w1, w2] :
       smooth::utils::zip(mesh.interval_weights(0), mesh.interval_weights(1))) {
    ASSERT_NEAR(w1, w2, 1e-9);
  }

  auto all_nodes = mesh.all_nodes();

  auto all_weights = mesh.all_weights();

  for (const auto [d0, d1] : smooth::utils::zip(all_nodes, all_nodes | std::views::drop(1))) {
    ASSERT_LE(d0, d1);
  }

  double sum = 0u;
  for (auto w : all_weights) { sum += w; }
  ASSERT_NEAR(sum, 1., 1e-9);
}


#ifndef _IO_MATH_TESTS_PRINT_TVECTOR_4_HPP
#define _IO_MATH_TESTS_PRINT_TVECTOR_4_HPP

#include "../../src/types/vectors/TVector4.hpp"

#include <iostream>
#include <limits>
#include <boost/type_index.hpp>

namespace IOMath
{
    namespace Types
    {
        template <typename T>
        std::ostream& boost_test_print_type(std::ostream &outputStream, TVector<4, T> const &object)
        {
            outputStream.precision(std::numeric_limits<T>::max_digits10);
            outputStream << "TVector<" << 4 << ", " << boost::typeindex::type_id<T>().pretty_name() << "> ";
            outputStream << "{ " << "x: " << object.x;
            outputStream << ", y: " << object.y;
            outputStream << ", z: " << object.z;
            outputStream << ", w: " << object.w << " }";
            outputStream.flush();

            return outputStream;
        }
    }
}

#endif


/*
* main dialog
*
* calculator
* (c) 2003 andrzej lichnerowicz. all rights reserved.
*
* permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* this software is provided "as is" without express or implied warranty,
* and with no claim as to its suitability for any purpose.
*
* Changeslog:
* 12 Mar 2003	AL	+ added overflow guard for hex, bin and oct
* 07 Mar 2003	AL	* decimal number formatting fixed
*					* formatting done on streams
*					* tuned error reporting
* 30 Jan 2003	AL	- initial revision
*
*/
#include "StdAfx.h"
#include "Calc.h"
#include "CalcDlg.h"
#include "../core/Engine.h"
#include <sstream>

#include <boost/spirit/phoenix/primitives.hpp>
#include <boost/spirit/phoenix/binders.hpp>
using namespace phoenix;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CCalcDlg::CCalcDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CCalcDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CCalcDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CCalcDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_EN_CHANGE(IDC_INPUT,OnTextInput)
	ON_COMMAND(IDM_EVAL,OnEval)
	ON_COMMAND(IDM_ABOUT,OnAbout)
	ON_COMMAND(IDM_COPY,OnCopy)
END_MESSAGE_MAP()

CString long2bin(unsigned long num) {
	CString tmp;
	for(int i=0;i<32;++i) {
		tmp+=num&(1<<i)?"1":"0";
	}
	while(i&&tmp[i-1]=='0') --i;

	if(!i) return "0";
	CString ret;
	while(i--) ret+=tmp[i];

	return ret;
}

BOOL CCalcDlg::OnInitDialog() {
	CDialog::OnInitDialog();
	SetIcon(m_hIcon, TRUE);
	SetIcon(m_hIcon, FALSE);

	((CEdit*)GetDlgItem(IDC_EVAL_DEC))->ModifyStyle(ES_LEFT|ES_CENTER,ES_RIGHT);
	((CEdit*)GetDlgItem(IDC_EVAL_HEX))->ModifyStyle(ES_LEFT|ES_CENTER,ES_RIGHT);
	((CEdit*)GetDlgItem(IDC_EVAL_BIN))->ModifyStyle(ES_LEFT|ES_CENTER,ES_RIGHT);
	((CEdit*)GetDlgItem(IDC_EVAL_OCT))->ModifyStyle(ES_LEFT|ES_CENTER,ES_RIGHT);
	((CEdit*)GetDlgItem(IDC_EVAL_EXP))->ModifyStyle(ES_LEFT|ES_CENTER,ES_RIGHT);

	CButton* wndDecRadio=(CButton*)GetDlgItem(IDC_DEC);
	wndDecRadio->SetCheck(TRUE);
	CEdit* wndInput=(CEdit*)GetDlgItem(IDC_INPUT);
	wndInput->SetFocus();
	OnTextInput();

	return FALSE;
}

void CCalcDlg::OnPaint() {
	if (IsIconic())	{
		CPaintDC dc(this);
		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		dc.DrawIcon(x, y, m_hIcon);
	} else {
		CDialog::OnPaint();
	}
}

HCURSOR CCalcDlg::OnQueryDragIcon() {
	return static_cast<HCURSOR>(m_hIcon);
}

void CCalcDlg::OnTextInput() {
	CEdit* wndInput=(CEdit*)GetDlgItem(IDC_INPUT);

	CEdit* wndDec=(CEdit*)GetDlgItem(IDC_EVAL_DEC);
	CEdit* wndHex=(CEdit*)GetDlgItem(IDC_EVAL_HEX);
	CEdit* wndBin=(CEdit*)GetDlgItem(IDC_EVAL_BIN);
	CEdit* wndOct=(CEdit*)GetDlgItem(IDC_EVAL_OCT);
	CEdit* wndExp=(CEdit*)GetDlgItem(IDC_EVAL_EXP);

	CString sInput;
	wndInput->GetWindowText(sInput);

	try {
		double ret=Calculate(sInput.GetBuffer());

		ostringstream dec_,hex_,oct_,exp_;
		dec_.precision(10);
		dec_<<ret;
		hex_<<hex<<uppercase<<static_cast<DWORD>(ret);
		oct_<<oct<<static_cast<DWORD>(ret);
		exp_<<scientific<<showpoint<<ret;
		wndDec->SetWindowText(dec_.str().c_str());
		wndExp->SetWindowText(exp_.str().c_str());
		if(ret>double(0xffffffff)) {
			wndHex->SetWindowText("Overflow");
			wndBin->SetWindowText("Overflow");
			wndOct->SetWindowText("Overflow");
		} else {
			wndHex->SetWindowText(hex_.str().c_str());
			wndBin->SetWindowText(long2bin(static_cast<DWORD>(ret)));
			wndOct->SetWindowText(oct_.str().c_str());
		}
	} catch(...) {
		const char* sResult=sInput==""?"0":"Error";
		wndDec->SetWindowText(sResult);
		wndHex->SetWindowText(sResult);
		wndBin->SetWindowText(sResult);
		wndOct->SetWindowText(sResult);
		wndExp->SetWindowText(sResult);
	}
}

void CCalcDlg::OnEval() {
	CButton* wndDec=(CButton*)GetDlgItem(IDC_DEC);
	CButton* wndHex=(CButton*)GetDlgItem(IDC_HEX);
	CButton* wndBin=(CButton*)GetDlgItem(IDC_BIN);
	CButton* wndOct=(CButton*)GetDlgItem(IDC_OCT);
	CButton* wndExp=(CButton*)GetDlgItem(IDC_EXP);

	CString sNewInput,sDecInput,sHexInput;
	((CEdit*)GetDlgItem(IDC_INPUT))->GetWindowText(sNewInput);
	((CEdit*)GetDlgItem(IDC_EVAL_DEC))->GetWindowText(sDecInput);

	if(sDecInput!="Error") {
		((CEdit*)GetDlgItem(IDC_EVAL_HEX))->GetWindowText(sHexInput);
		if(sHexInput!="Overflow") {
			if(wndHex->GetCheck()) {
				CString txt;
				((CEdit*)GetDlgItem(IDC_EVAL_HEX))->GetWindowText(txt);
				sNewInput="0x"+txt;
			}
			if(wndBin->GetCheck()) {
				CString txt;
				((CEdit*)GetDlgItem(IDC_EVAL_BIN))->GetWindowText(txt);
				sNewInput=txt+"b";
			}
			if(wndOct->GetCheck()) {
				CString txt;
				((CEdit*)GetDlgItem(IDC_EVAL_OCT))->GetWindowText(txt);
				sNewInput="0"+txt;
			}
		}
		if(wndDec->GetCheck()) ((CEdit*)GetDlgItem(IDC_EVAL_DEC))->GetWindowText(sNewInput);
		if(wndExp->GetCheck()) ((CEdit*)GetDlgItem(IDC_EVAL_EXP))->GetWindowText(sNewInput);
		((CEdit*)GetDlgItem(IDC_INPUT))->SetWindowText(sNewInput);
	}
}

class CAboutDlg : public CDialog {
public:
	CAboutDlg();

	enum { IDD = IDD_ABOUTBOX };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) {
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX) {
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()

void CCalcDlg::OnAbout() {
	CAboutDlg dlg;
	dlg.DoModal();
}

void CCalcDlg::OnCopy() {
	if(!OpenClipboard()) {
		MessageBox("cannot copy to clipboard","commencing ritual harakiri");
		return;
	}
	if(!EmptyClipboard()) {
		MessageBox("cannot copy to clipboard","commencing ritual harakiri");
		return;
	}
	CString sInput;
	((CEdit*)GetDlgItem(IDC_INPUT))->GetWindowText(sInput);
	const long len=sInput.GetLength();
	HGLOBAL hData=GlobalAlloc(GMEM_MOVEABLE,len+1);
	if(hData==NULL) {
		MessageBox("cannot copy to clipboard","commencing ritual harakiri");
		CloseClipboard();
		return;
	}
	char *temp=(char*)GlobalLock(hData);
	strcpy(temp,sInput.GetBuffer());
	GlobalUnlock(hData);
	if(::SetClipboardData(CF_TEXT,hData)==NULL) {
		MessageBox("cannot copy to clipboard","commencing ritual harakiri");
		CloseClipboard();
		return;
	}
	CloseClipboard();
}

BOOL CCalcDlg::PreTranslateMessage(MSG* pMsg) {
	if(pMsg->message==WM_KEYDOWN&&pMsg->wParam==VK_ESCAPE) {
		((CEdit*)GetDlgItem(IDC_INPUT))->SetWindowText("");
		OnTextInput();
		return TRUE;
	}

	return CDialog::PreTranslateMessage(pMsg);
}


/*
    This is a modified version of uraster : https://github.com/Steve132/uraster
*/

#pragma once

#include <algorithm>
#include <array>
#define cimg_use_jpeg
#define cimg_use_xshm
#include "CImg.h"
#include <Eigen/Dense>
#include <Eigen/LU>	// for .inverse(). Probably not needed
#include <functional>
#include <iostream>
#include <memory>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#include <vector>

namespace LindaleRaster
{
    // We define our own maximum and minimum functions because of CImg and Eigen doing weird stuff
    int maximum(int a, int b) {
        return a > b ? a : b;
    }
    float maximum(float a, float b) {
        return a > b ? a : b;
    }
    Eigen::Array2f maximum2f(Eigen::Array2f a, Eigen::Array2f b) {
        return Eigen::Array2f( maximum( a(0), b(0) ) , maximum( a(1), b(1) ) );
    }
    Eigen::Array2i maximum2i(Eigen::Array2i a, Eigen::Array2i b) {
        return Eigen::Array2i(maximum(a(0), b(0)), maximum(a(1), b(1)));
    }
    int minimum(int a, int b) {
        return a < b ? a : b;
    }
    float minimum(float a, float b) {
        return a < b ? a : b;
    }
    Eigen::Array2f minimum2f(Eigen::Array2f a, Eigen::Array2f b) {
        return Eigen::Array2f( minimum( a(0), b(0) ) , minimum( a(1), b(1) ) );
    }
    Eigen::Array2i minimum2i(Eigen::Array2i a, Eigen::Array2i b) {
        return Eigen::Array2i(minimum(a(0), b(0)), minimum(a(1), b(1)));
    }

    typedef struct {
        float x, y, z,
            nx, ny, nz, // Normal
            u, v;
    } Vert;

    struct VertShaderOut
    {
        Eigen::Vector4f pos;
        Eigen::Vector3f normal;
        Eigen::Vector2f uv;

        VertShaderOut() :
            pos(0.0f, 0.0f, 0.0f, 0.0f), normal(0.0f, 0.0f, 0.0f), uv(0.0f, 0.0f)
        {}
        const Eigen::Vector4f& position() const
        {
            return pos;
        }
        VertShaderOut& operator+=(const VertShaderOut& tp)
        {
            pos += tp.pos;
            normal += tp.normal;
            uv += tp.uv;
            return *this;
        }
        VertShaderOut& operator*=(const float& f)
        {
            pos *= f;
            normal *= f;
            uv *= f;
            return *this;
        }
    };

    class Pixel
    {
    public:
        Eigen::Vector4f color;
        float& depth() { return color[3]; }
        Pixel() :color(0.0f, 0.0f, 0.0f, -1e10f)
        {}
    };

    // This is the framebuffer class.
    class Framebuffer
    {
    protected:
        std::vector<Pixel> data;
    public:
        const std::size_t width;
        const std::size_t height;
        // constructor initializes the array
        Framebuffer(std::size_t w, std::size_t h, const Pixel& pt = Pixel()) :
            data(w*h, pt),
            width(w), height(h)
        {}
        // 2D pixel access
        Pixel& operator()(std::size_t x, std::size_t y)
        {
            return data[y*width + x];
        }
        // const version
        const Pixel& operator()(std::size_t x, std::size_t y) const
        {
            return data[y*width + x];
        }
        void clear(const Pixel& pt = Pixel())
        {
            std::fill(data.begin(), data.end(), pt);
        }
    };

    VertShaderOut vertex_shader(const Vert& vertIn, const Eigen::Matrix4f& mvp = Eigen::Matrix4f::Identity())
    {
        VertShaderOut vout;
        vout.pos = mvp*Eigen::Vector4f(vertIn.x, vertIn.y, vertIn.z, 1.0f);
        vout.uv = Eigen::Vector2f(vertIn.u, vertIn.v).array().abs();
        vout.uv[0] = vout.uv[0] - floor(vout.uv[0]);
        vout.uv[1] = vout.uv[1] - floor(vout.uv[1]);
        vout.normal = Eigen::Vector3f(vertIn.nx, vertIn.ny, vertIn.nz);
        return vout;
    }

    Pixel fragment_shader(const VertShaderOut& fsin, std::vector<float>& color, const cimg_library::CImg<uint8_t>& texture)
    {
        Pixel pixel;

        //Eigen::Vector2f uv(fsin.uv[0] * tex1.width()*0.4f, fsin.uv[1] * tex1.height()*0.4f);
        Eigen::Vector2f uv(fsin.uv[0] * texture.width(), fsin.uv[1] * texture.height());
        Eigen::Vector3f diffuse;
        for (int c = 0; c < 3; c++)
        {
            if (texture.is_empty()) {
                diffuse[c] = color[c];
            }
            else {
                diffuse[c] = texture.linear_atXY(uv[0], uv[1], 0, c) / 255.0f;
            }
        }
        float theta = 1.2f*sin(0);
        Eigen::Vector3f ld(1.0, sin(theta), cos(theta));
        float intensity = ld.normalized().dot(fsin.normal);
        pixel.color.head<3>() = diffuse*intensity;
        return pixel;
    }

    // This function runs the vertex shader on all the vertices, producing the varyings that will be interpolated by the rasterizer.
    // Vert can be anything, VertShaderOut MUST have a position() method that returns a 4D vector, and it must have an overloaded *= and += operator for the interpolation
    // The right way to think of VertShaderOut is that it is the class you write containing the varying outputs from the vertex shader.
    void run_vertex_shader(std::vector<Vert>* vertexbuffer, std::vector<VertShaderOut>* vertShaders)
    {
#pragma omp parallel for
        for (std::size_t i = 0; i < vertexbuffer->size(); i++)
        {
            vertShaders->at(i) = vertex_shader(vertexbuffer->at(i));
        }
    }

    struct BarycentricTransform
    {
    private:
        Eigen::Vector2f offset;
        Eigen::Matrix2f Ti;
    public:
        BarycentricTransform(const Eigen::Vector2f& s1, const Eigen::Vector2f& s2, const Eigen::Vector2f& s3) :
            offset(s3)
        {
            Eigen::Matrix2f T;
            T << (s1 - s3), (s2 - s3);
            Ti = T.inverse();
        }
        Eigen::Vector3f operator()(const Eigen::Vector2f& v) const
        {
            Eigen::Vector2f b;
            b = Ti*(v - offset);
            return Eigen::Vector3f(b[0], b[1], 1.0f - b[0] - b[1]);
        }
    };

    // This function takes in 3 varyings vertices from the fragment shader that make up a triangle,
    // rasterizes the triangle and runs the fragment shader on each resulting pixel.
    void rasterize_triangle(Framebuffer& fb, const std::array<VertShaderOut, 3>& verts, std::vector<float>* color, cimg_library::CImg<uint8_t>* texture, cimg_library::CImg<uint8_t>* alphaTexture)
    {
        std::array<Eigen::Vector4f, 3> points{ {verts[0].position(),verts[1].position(),verts[2].position()} };
        //Do the perspective divide by w to get screen space coordinates.
        std::array<Eigen::Vector4f, 3> epoints{ {points[0] / points[0][3],points[1] / points[1][3],points[2] / points[2][3]} };
        auto ss1 = epoints[0].head<2>().array(), ss2 = epoints[1].head<2>().array(), ss3 = epoints[2].head<2>().array();

        // calculate the bounding box of the triangle in screen space floating point.
        //Eigen::Array2f bb_ul = ss1.min(ss2).min(ss3);
        //Eigen::Array2f bb_lr = ss1.max(ss2).max(ss3);
        Eigen::Array2f bb_ul = minimum2f(minimum2f(ss1, ss2), ss3);
        Eigen::Array2f bb_lr = minimum2f(minimum2f(ss1, ss2), ss3);
        Eigen::Array2i isz(fb.width, fb.height);

        // convert bounding box to fixed point.
        // move bounding box from (-1.0,1.0)->(0,imgdim)
        Eigen::Array2i ibb_ul = ((bb_ul*0.5f + 0.5f)*isz.cast<float>()).cast<int>();
        Eigen::Array2i ibb_lr = ((bb_lr*0.5f + 0.5f)*isz.cast<float>()).cast<int>();
        ibb_lr += 1;	//add one pixel of coverage

        // clamp the bounding box to the framebuffer size if necessary (this is clipping.  Not quite how the GPU actually does it but same effect sorta).
        //ibb_ul = ibb_ul.max(Eigen::Array2i(0, 0));
        //ibb_lr = ibb_lr.min(isz);
        ibb_ul = maximum2i(ibb_ul, Eigen::Array2i(0, 0));
        ibb_lr = maximum2i(ibb_lr, isz);

        BarycentricTransform bt(ss1.matrix(), ss2.matrix(), ss3.matrix());

        // for all the pixels in the bounding box
        for (int y = ibb_ul[1]; y < ibb_lr[1]; y++)
            for (int x = ibb_ul[0]; x < ibb_lr[0]; x++)
            {
                Eigen::Vector2f ssc(x, y);
                ssc.array() /= isz.cast<float>();	//move pixel to relative coordinates
                ssc.array() -= 0.5f;
                ssc.array() *= 2.0f;

                // Compute barycentric coordinates of the pixel center
                Eigen::Vector3f bary = bt(ssc);

                // if the pixel has valid barycentric coordinates, the pixel is in the triangle
                if ((bary.array() < 1.0f).all() && (bary.array() > 0.0f).all())
                {
                    float d = bary[0] * epoints[0][2] + bary[1] * epoints[1][2] + bary[2] * epoints[2][2];
                    // Reference the current pixel at that coordinate
                    Pixel& po = fb(x, y);

                    // if the interpolated depth passes the depth test
                    if (po.depth() < d && d < 1.0)
                    {
                        // interpolate varying parameters
                        VertShaderOut v = verts[0];
                        v *= bary[0];
                        VertShaderOut vt = verts[1];
                        vt *= bary[1];
                        v += vt;
                        vt = verts[2];
                        vt *= bary[2];
                        v += vt;

                        // call the fragment shader
                        po = fragment_shader(v, *color, *texture);
                        po.depth() = d; //write the depth buffer
                    }
                }
            }
    }

    // This function rasterizes a set of triangles determined by an index buffer and a buffer of output verts.
    void rasterize(Framebuffer& fb, std::vector<int>* indices, std::vector<VertShaderOut>* verts, std::vector<float>* color, cimg_library::CImg<uint8_t>* texture, cimg_library::CImg<uint8_t>* alphaTexture)
    {
#pragma omp parallel for
        for (std::size_t i = 0; i < indices->size(); i += 3)
        {
            std::array<VertShaderOut, 3> tri{ { verts->at(indices->at(i)), verts->at(indices->at(i + 1)), verts->at(indices->at(i + 2)) } };
            rasterize_triangle(fb, tri, color, texture, alphaTexture);
        }
    }

    // This function does a draw call from an indexed buffer
    void draw(Framebuffer& fb,
        std::vector<Vert>* vertexbuffer,
        std::vector<int>* facebuffer,
        std::vector<float>* color,
        cimg_library::CImg<uint8_t>* texture,
        cimg_library::CImg<uint8_t>* alphaTexture)
    {
        std::vector<VertShaderOut> vertShaders;
        vertShaders.resize(vertexbuffer->size());
        run_vertex_shader(vertexbuffer, &vertShaders);
        rasterize(fb, facebuffer, &vertShaders, color, texture, alphaTexture);
    }

    bool write_framebuffer(const Framebuffer& fb, const std::string& filename)
    {
        uint8_t* pixels = new uint8_t[fb.width*fb.height * 3];
        std::unique_ptr<uint8_t[]> data(pixels);

        const float* fbdata = &(fb(0, 0).color[0]);
        for (size_t i = 0; i<fb.width*fb.height; i++)
        {
            for (int c = 0; c<3; c++)
            {
                pixels[3 * i + c] = maximum(0.0f, minimum(fbdata[4 * i + c] * 255.0f, 255.0f));
            }
        }

        if (0 == stbi_write_png(filename.c_str(), fb.width, fb.height, 3, pixels, 0))
        {
            return false;
        }
        else {
            return true;
        }
    }

}


// Copyright 2008 Chung-Lin Wen.
// 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 GIL_XYZ_H
#define GIL_XYZ_H

////////////////////////////////////////////////////////////////////////////////////////
/// \file
/// \brief Support for CIE XYZ color space
/// \author Chung-Lin Wen \n
////////////////////////////////////////////////////////////////////////////////////////

#include <boost/cast.hpp>
#include <boost/gil/gil_all.hpp>

namespace boost { namespace gil {

/// \addtogroup ColorNameModel
/// \{
namespace xyz_color_space
{
/// \brief x Color Component
struct x_t {};
/// \brief y Color Component
struct y_t {};
/// \brief z Color Component
struct z_t {};
}
/// \}

/// \ingroup ColorSpaceModel
typedef mpl::vector3< xyz_color_space::x_t
                    , xyz_color_space::y_t
                    , xyz_color_space::z_t
                    > xyz_t;

/// \ingroup LayoutModel
typedef layout<xyz_t> xyz_layout_t;

GIL_DEFINE_ALL_TYPEDEFS( 32f, xyz );

/// \ingroup ColorConvert
/// \brief RGB to XYZ
template <>
struct default_color_converter_impl< rgb_t, xyz_t >
{
   template <typename P1, typename P2>
   void operator()( const P1& src, P2& dst ) const
   {
      using namespace xyz_color_space;

      // only bits32f for xyz is supported
      bits32f temp_red   = channel_convert<bits32f>( get_color( src, red_t()   ));
      bits32f temp_green = channel_convert<bits32f>( get_color( src, green_t() ));
      bits32f temp_blue  = channel_convert<bits32f>( get_color( src, blue_t()  ));

      bits32f normalized_r = temp_red / 255.f;
      bits32f normalized_g = temp_green / 255.f;
      bits32f normalized_b = temp_blue / 255.f;

      if( normalized_r > 0.04045f )
      {
         normalized_r = pow((( normalized_r + 0.055f ) / 1.055f ), 2.4f );
      }
      else
      {
         normalized_r /= 12.92f;
      }

      if( normalized_g > 0.04045f )
      {
         normalized_g = pow((( normalized_g + 0.055f ) / 1.055f ), 2.4f );
      }
      else
      {
         normalized_g /= 12.92f;
      }

      if( normalized_b > 0.04045f )
      {
         normalized_b = pow((( normalized_b + 0.055f ) / 1.055f ), 2.4f );
      }
      else
      {
         normalized_b /= 12.92f;
      }

      normalized_r *= 100.f;
      normalized_g *= 100.f;
      normalized_b *= 100.f;

      bits32f x, y, z;
      x = normalized_r * 0.4124f + normalized_g * 0.3576f + normalized_b * 0.1805f;
      y = normalized_r * 0.2126f + normalized_g * 0.7152f + normalized_b * 0.0722f;
      z = normalized_r * 0.0193f + normalized_g * 0.1192f + normalized_b * 0.9505f;

      get_color( dst, x_t() ) = x;
      get_color( dst, y_t() ) = y;
      get_color( dst, z_t() ) = z;
   }
};

/// \ingroup ColorConvert
/// \brief XYZ to RGB
template <>
struct default_color_converter_impl<xyz_t,rgb_t>
{
   template <typename P1, typename P2>
   void operator()( const P1& src, P2& dst) const
   {
      using namespace xyz_color_space;

      bits32f x = get_color( src, x_t() );
      bits32f y = get_color( src, y_t() );
      bits32f z = get_color( src, z_t() );

      bits32f normalized_x = x / 100.f;
      bits32f normalized_y = y / 100.f;
      bits32f normalized_z = z / 100.f;

      bits32f result_r = normalized_x *  3.2406f + normalized_y * -1.5372f + normalized_z * -0.4986f;
      bits32f result_g = normalized_x * -0.9689f + normalized_y *  1.8758f + normalized_z *  0.0415f;
      bits32f result_b = normalized_x *  0.0557f + normalized_y * -0.2040f + normalized_z *  1.0570f;

      if ( result_r > 0.0031308f )
      {
         result_r = 1.055f * pow( result_r, 1.f/2.4f ) - 0.055f;
      }
      else
      {
         result_r = 12.92f * result_r;
      }

      if ( result_g > 0.0031308f )
      {
         result_g = 1.055f * pow( result_g, 1.f/2.4f ) - 0.055f;
      }
      else
      {
         result_g = 12.92f * result_g;
      }

      if ( result_b > 0.0031308f )
      {
         result_b = 1.055f * pow( result_b, 1.f/2.4f ) - 0.055f;
      }
      else
      {
         result_b = 12.92f * result_b;
      }

      bits32f red, green, blue;
      red = result_r * 255.f;
      green = result_g * 255.f;
      blue = result_b * 255.f;

      get_color(dst,red_t())  =
         channel_convert<typename color_element_type<P2, red_t>::type>( red );
      get_color(dst,green_t())=
         channel_convert<typename color_element_type<P2, green_t>::type>( green );
      get_color(dst,blue_t()) =
         channel_convert<typename color_element_type<P2, blue_t>::type>( blue );
   }
};

} }  // namespace boost::gil

#endif // GIL_XYZ_H


/*
Brian Staber (brian.staber@gmail.com)
*/

#ifndef SHINOZUKAPP_LAYEREDCOMP_2D_HPP
#define SHINOZUKAPP_LAYEREDCOMP_2D_HPP

#include "meshpp.hpp"
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real_distribution.hpp>
#include <boost/math/special_functions/erf.hpp>
#include <boost/random/normal_distribution.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/special_functions/beta.hpp>

class shinozuka_layeredcomp_2d
{
public:

    int    order;
    double l1;
    double l2;
    double rotation = 0.0;
    boost::random::mt19937                     rng;
    boost::random::uniform_real_distribution<> phi_;
    boost::random::uniform_real_distribution<> psi_;
    Epetra_Map    * CellsMap;
    Epetra_Vector * GaussianRF;

    shinozuka_layeredcomp_2d(int & nu);
    shinozuka_layeredcomp_2d(int & nu, double & L1, double & L2);
    ~shinozuka_layeredcomp_2d();

    template<typename typearg>
    double tau_beta(typearg & beta);
    double s_tau(double & tau);

    void generator_gauss_points(Epetra_SerialDenseVector & v, mesh & Mesh, std::vector<int> & phase);
    void generator_one_gauss_point(Epetra_SerialDenseVector & v, mesh & Mesh, std::vector<int> & phase, double & xi, double & eta, double & zeta);

    void icdf_gamma(Epetra_Vector & V, Epetra_Vector & G, double & alpha, double & beta);
    void icdf_beta(Epetra_Vector & V, Epetra_Vector & B, double & tau1, double & tau2);
};
#endif


//=======================================================================
// Copyright (c)
//
// 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)
//=======================================================================
/**
 * @file local_search_obj_fun_test.hpp
 * @brief
 * @author Piotr Wygocki
 * @version 1.0
 * @date 2013-02-11
 */
#include "test_utils/logger.hpp"

#include "paal/local_search/search_obj_func_components.hpp"
#include "paal/local_search/local_search_obj_function.hpp"
#include "paal/data_structures/components/components_replace.hpp"

#include <boost/test/unit_test.hpp>

#include <vector>

using std::string;
using std::vector;
namespace ls = paal::local_search;
using namespace paal;

struct F {
    int operator()(int x) const { return -x * x + 12 * x - 27; }
};

class NG {
    typedef const std::vector<int> Neighb;
    Neighb neighb;

  public:

    NG() : neighb{ 1, -1, 10, -10 } {}

    Neighb &operator()(int x) const { return neighb; }
};

struct SU {
    bool operator()(int &s, int u) const {
        s = s + u;
        return true;
    }
};

BOOST_AUTO_TEST_CASE(local_search_obj_fun_test) {
    // creating local search
    typedef ls::search_components_obj_fun<NG, F, SU> search_comps;
    ON_LOG(F f);

    // printing
    int s(0);
    LOGLN("f(" << s << ") \t" << f(s));
    ON_LOG(int i = 0);

    // setting logger
    auto logger = [&](int s) {
        // printing
        LOGLN("f(" << s << ") \t" << f(s) << " after " << ++i);
        return true;
    };

    ls::local_search_obj_fun(s, ls::first_improving_strategy{}, logger,
                             utils::always_false{}, search_comps{});
    BOOST_CHECK_EQUAL(s, 6);

    ON_LOG(i = 0);
    s = 0;
    ls::local_search_obj_fun(s, ls::best_improving_strategy{}, logger,
                             utils::always_false{}, search_comps{});
    BOOST_CHECK_EQUAL(s, 6);

    s = 0;
    ls::obj_fun_first_improving(s, search_comps{});
    BOOST_CHECK_EQUAL(s, 6);

    s = 0;
    ls::obj_fun_best_improving(s, search_comps{});
    BOOST_CHECK_EQUAL(s, 6);

    s = 0;
    ls::obj_fun_first_improving(s, search_comps{}, search_comps{});
    BOOST_CHECK_EQUAL(s, 6);

    s = 0;
    ls::obj_fun_best_improving(s, search_comps{}, search_comps{});
    BOOST_CHECK_EQUAL(s, 6);

    search_comps sc{};

    int iter = -1;

    auto sc_0_after_round = paal::data_structures::replace<ls::ObjFunction>([&iter, sc](int & s){
                    return ++iter > static_cast<int>(sc.call<ls::GetMoves>(s).size()) ? -10000 : sc.call<ls::ObjFunction>(s);
                },
                sc
            );

    s = 0;
    LOGLN("first improving 4 checks");
    ls::obj_fun_first_improving(s, sc_0_after_round);
    BOOST_CHECK_EQUAL(s, 4);

    iter = -1;
    s = 0;
    LOGLN("best improving 4 checks");
    ls::obj_fun_best_improving(s, sc_0_after_round);
    BOOST_CHECK_EQUAL(s, 10);

}


//==================================================================================================
/*!

  Copyright 2015 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#include <boost/simd/function/scalar/bitwise_notor.hpp>
#include <simd_test.hpp>
#include <boost/dispatch/meta/as_integer.hpp>
#include <boost/simd/constant/inf.hpp>
#include <boost/simd/constant/minf.hpp>
#include <boost/simd/constant/mone.hpp>
#include <boost/simd/constant/nan.hpp>
#include <boost/simd/constant/one.hpp>
#include <boost/simd/constant/zero.hpp>
#include <boost/simd/constant/bitincrement.hpp>
#include <boost/simd/constant/valmin.hpp>
#include <boost/simd/constant/valmax.hpp>

STF_CASE_TPL (" bitwise_notor real",  STF_IEEE_TYPES)
{
  namespace bs = boost::simd;

  using bs::bitwise_notor;
  using r_t = decltype(bitwise_notor(T(), T()));

  // return type conformity test
  STF_TYPE_IS(r_t, T);

  // specific values tests
#ifndef STF_NO_INVALIDS
  STF_IEEE_EQUAL(bitwise_notor(bs::Inf<T>(), bs::Inf<T>()), bs::Nan<r_t>());
  STF_IEEE_EQUAL(bitwise_notor(bs::Minf<T>(), bs::Minf<T>()), bs::Nan<r_t>());
  STF_IEEE_EQUAL(bitwise_notor(bs::Nan<T>(), bs::Nan<T>()), bs::Nan<r_t>());
#endif
  STF_IEEE_EQUAL(bitwise_notor(bs::Zero<T>(), bs::Zero<T>()), bs::Nan<r_t>());
} // end of test for floating_

STF_CASE_TPL (" bitwise_notor signed_int",  STF_SIGNED_INTEGRAL_TYPES)
{
  namespace bs = boost::simd;

  using bs::bitwise_notor;
  using r_t = decltype(bitwise_notor(T(), T()));

  // return type conformity test
  STF_TYPE_IS(r_t, T);

  // specific values tests
  STF_EQUAL(bitwise_notor(bs::Mone<T>(),bs::Zero<T>()), bs::Zero<r_t>());
  STF_EQUAL(bitwise_notor(bs::One<T>(), bs::One<T>()), bs::Mone<r_t>());
  STF_EQUAL(bitwise_notor(bs::Zero<T>(), bs::Zero<T>()), bs::Mone<r_t>());
  STF_EQUAL(bitwise_notor(bs::Zero<T>(),bs::One<T>()), r_t(bs::Mone<r_t>()));
} // end of test for signed_int_

STF_CASE_TPL (" bitwise_notor unsigned_int",  STF_UNSIGNED_INTEGRAL_TYPES)
{
  namespace bs = boost::simd;

  using bs::bitwise_notor;
  using r_t = decltype(bitwise_notor(T(), T()));

  // return type conformity test
  STF_TYPE_IS(r_t, T);

  // specific values tests
  STF_EQUAL(bitwise_notor(bs::One<T>(), bs::One<T>()), bs::Mone<r_t>());
  STF_EQUAL(bitwise_notor(bs::Zero<T>(), bs::Zero<T>()), bs::Mone<r_t>());
  STF_EQUAL(bitwise_notor(bs::Zero<T>(),bs::One<T>()), r_t(bs::Mone<r_t>()));
} // end of test for unsigned_int_

STF_CASE_TPL("bitwise_notor mix", STF_IEEE_TYPES)
{
  namespace bs = boost::simd;
  namespace bd = boost::dispatch;
  using bs::bitwise_notor;

  using siT = bd::as_integer_t<T>;
  using uiT = bd::as_integer_t<T, unsigned>;

  // return type conformity test
  STF_EXPR_IS(bitwise_notor(T(),uiT()), T);
  STF_EXPR_IS(bitwise_notor(T(),siT()), T);
  STF_EXPR_IS(bitwise_notor(uiT(), T()), uiT);
  STF_EXPR_IS(bitwise_notor(siT(), T()), siT);

   // specific values tests
  STF_EQUAL(bitwise_notor(bs::Nan<T>(),bs::One<uiT>()), bs::Bitincrement<T>());
  STF_EQUAL(bitwise_notor(bs::Nan<T>(), bs::One<siT>()), bs::Bitincrement<T>());
  STF_EQUAL(bitwise_notor(bs::Valmin<siT>(),bs::Zero<T>()), bs::Valmax<siT>());
  STF_EQUAL(bitwise_notor(bs::Zero<uiT>(), bs::Zero<T>()), bs::Valmax<uiT>());
}


// Copyright (C) 2017 Vicente J. Botet Escriba
//
//  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)

// <experimental/bit_mask.hpp>

#include <experimental/bit.hpp>

#include <boost/detail/lightweight_test.hpp>

#include <array>
#include <list>
#include <algorithm>

namespace stde = std::experimental;

int main()
{
  {
    // First, we create an integer
    using uint_t = unsigned long long int;
    uint_t intval = 42;                                        // 101010

    // Then we create aligned bit values and a bit references on this integer
    stde::bit_value bval0(intval);                              // Creates a bit value from the bit at position 0 of intval
    stde::bit_reference<uint_t> bref0(intval);                  // Creates a bit reference from the bit at position 0 of intval
    assert(bval0 == bref0);

    // And unaligned bit values and a bit references on this integer
    stde::bit_value bval5(intval, 5);                           // Creates a bit value from the bit at position 5 of intval
    stde::bit_reference<uint_t> bref5(intval, 5);               // Creates a bit reference from the bit at position 5 of intval
    assert(bval5 == bref5);

    // Display them
    std::cout<<bval0<<bref0<<bval5<<bref5<<std::endl;          // Prints 0011

    // Change their values conditionally
    if (static_cast<bool>(bval5)) {
      bval0.flip();  // Flips the bit without affecting the integer
      bref5.reset(); // Resets the bit to zero and affects the integer
    }
    std::cout<<bval0<<bref0<<bval5<<bref5<<std::endl;          //  Prints 1010

    // Prints the location and the corresponding mask of bit references
    std::cout<<bref0.position()<<" "<<int(bref0.mask())<<std::endl; // Prints 0 and 1
    std::cout<<bref5.position()<<" "<<int(bref5.mask())<<std::endl; // Prints 5 and 32
  }
  {
    // First, we create an integer
    using uint_t = unsigned char;
    uint_t intval = 42;                                        // 101010

    // Then we create aligned bit values and a bit references on this integer
    stde::bit_value bval0(intval);                              // Creates a bit value from the bit at position 0 of intval
    stde::bit_reference<uint_t> bref0(intval);                  // Creates a bit reference from the bit at position 0 of intval

    // And unaligned bit values and a bit references on this integer
    stde::bit_value bval5(intval, 5);                           // Creates a bit value from the bit at position 5 of intval
    stde::bit_reference<uint_t> bref5(intval, 5);               // Creates a bit reference from the bit at position 5 of intval

    // Display them
    std::cout<<bval0<<bref0<<bval5<<bref5<<std::endl;          // Prints 0011

    // Change their values conditionally
    if (static_cast<bool>(bval5)) {
      bval0.flip();  // Flips the bit without affecting the integer
      bref5.reset(); // Resets the bit to zero and affects the integer
    }
    std::cout<<bval0<<bref0<<bval5<<bref5<<std::endl;          //  Prints 1010

    // Prints the location and the corresponding mask of bit references
    std::cout<<bref0.position()<<" "<<int(bref0.mask())<<std::endl; // Prints 0 and 1
    std::cout<<bref5.position()<<" "<<int(bref5.mask())<<std::endl; // Prints 5 and 32
  }
  {
    // First, we create an array of integers
    using uint_t = unsigned long int;
    std::array<uint_t, 2> intarr = {{42, 314}};

    // Then we create a bit reference and a bit pointer
    stde::bit_reference<uint_t> bref5(intarr[0], 5);            // Creates a bit reference from the bit at position 5 of the first element of the array
    stde::bit_pointer<uint_t> bptr(intarr.data());              // Creates a bit pointer from the bit at position 0 of the first element of the array
    std::cout<<bptr->position()<<std::endl;                    // Prints 7 as the bit is now in the second element of the array

    // We flip the first bit, and sets the second one to 1 with two methods
    bptr->flip();                                              // Flips the bit
    ++bptr;                                                    // Goes to the next bit
    (*bptr).set();                                               // Sets the bit

    // Then we advance the bit pointer by more than 64 bits and display its position
    bptr += 71;
    std::cout<<bptr->position()<<std::endl;                    // Prints 8 as the bit is now in the second element of the array

    // And finally we set the bit pointer to the position of the bit reference
    bptr = &bref5;

    stde::bit_pointer<const uint_t> bcptr = bptr;

    //stde::bit_pointer<uint_t> bptr2 = bcptr; // compile fails as expected

    stde::bit_pointer<const uint_t> bcptr2 = bcptr - 2;
    std::cout<<bcptr2 - bptr<<std::endl;
  }
  {
    // First, we create a list of integers
    using uint_t = unsigned short int;
    std::list<uint_t> intlst = {40, 41, 42, 43, 44};

    // Then we create a pair of aligned bit iterators
    auto bfirst = stde::bit_iterator<typename std::list<uint_t>::iterator>(std::begin(intlst));
    auto bend = stde::bit_iterator<typename std::list<uint_t>::iterator>(std::end(intlst));

    // Then we count the number of bits set to 1
    auto result = std::count(bfirst, bend, stde::bit_value(1u));
    std::cout<<result<<std::endl;                    // Prints

    // We take a subset of the list
    auto bfirst2 = stde::bit_iterator<typename std::list<uint_t>::iterator>(std::begin(intlst), 5);
    auto bend2 = stde::bit_iterator<typename std::list<uint_t>::iterator>(std::prev(std::end(intlst)), 2);

    // And we reverse the subset
    std::reverse(bfirst2, bend2);
  }

  return ::boost::report_errors();
}


#ifndef BOOST_SAFE_FLOAT_POLICY_CHECK_DIVISION_UNDERFLOW_HPP
#define BOOST_SAFE_FLOAT_POLICY_CHECK_DIVISION_UNDERFLOW_HPP

#include <boost/safe_float/policy/check_base_policy.hpp>

#ifdef FENV_AVAILABLE
#pragma STDC FENV_ACCESS ON
#include <fenv.h>
#endif

namespace boost {
namespace safe_float{
namespace policy{

template<class FP>
class check_division_underflow : public check_policy<FP> {
#ifndef FENV_AVAILABLE
    bool expect_zero;
#endif
public:
    bool pre_division_check(const FP& lhs, const FP& rhs){
#ifndef FENV_AVAILABLE
        expect_zero = (lhs==0);
        return true;
#else
        return ! std::feclearexcept(FE_UNDERFLOW);
#endif
    }

    bool post_division_check(const FP& rhs){
#ifndef FENV_AVAILABLE
        return (std::fpclassify( rhs ) != FP_SUBNORMAL)
                && (rhs != 0 || expect_zero);
#else
        return ! std::fetestexcept(FE_UNDERFLOW);
#endif
    }

    std::string division_failure_message(){
        return std::string("Underflow from operation");
    }
};

}
}
}

#endif // BOOST_SAFE_FLOAT_POLICY_CHECK_DIVISION_UNDERFLOW_HPP


#if !defined(_WIN32) && !defined(BOOST_TEST_DYN_LINK)
#define BOOST_TEST_DYN_LINK
#endif
#define BOOST_TEST_MODULE Poly2triTest

#include <poly2tri/poly2tri.h>

#include <boost/filesystem/path.hpp>
#include <boost/test/unit_test.hpp>

#include <fstream>
#include <iostream>
#include <iterator>
#include <stdexcept>

BOOST_AUTO_TEST_CASE(BasicTest)
{
  std::vector<p2t::Point*> polyline{
    new p2t::Point(0, 0),
    new p2t::Point(1, 0),
    new p2t::Point(1, 1),
  };
  p2t::CDT cdt{ polyline };
  BOOST_CHECK_NO_THROW(cdt.Triangulate());
  const auto result = cdt.GetTriangles();
  BOOST_REQUIRE_EQUAL(result.size(), 1);
  BOOST_CHECK_EQUAL(*result[0]->GetPoint(0), *polyline[0]);
  BOOST_CHECK_EQUAL(*result[0]->GetPoint(1), *polyline[1]);
  BOOST_CHECK_EQUAL(*result[0]->GetPoint(2), *polyline[2]);
  BOOST_CHECK(p2t::IsDelaunay(result));
  for (const auto p : polyline) {
    delete p;
  }
}

BOOST_AUTO_TEST_CASE(QuadTest)
{
  std::vector<p2t::Point*> polyline{ new p2t::Point(0, 0), new p2t::Point(0, 1),
                                     new p2t::Point(1, 1), new p2t::Point(1, 0) };
  p2t::CDT cdt{ polyline };
  BOOST_CHECK_NO_THROW(cdt.Triangulate());
  const auto result = cdt.GetTriangles();
  BOOST_REQUIRE_EQUAL(result.size(), 2);
  BOOST_CHECK(p2t::IsDelaunay(result));
  for (const auto p : polyline) {
    delete p;
  }
}

BOOST_AUTO_TEST_CASE(NarrowQuadTest)
{
  // Very narrow quad that demonstrates a failure case during triangulation
  std::vector<p2t::Point*> polyline {
    new p2t::Point(0.0,     0.0),
    new p2t::Point(1.0e-05, 0.0),
    new p2t::Point(1.1e-04, 3.0e-07),
    new p2t::Point(1.0e-04, 3.0e-07)
  };
  p2t::CDT cdt{ polyline };
  BOOST_CHECK_THROW(cdt.Triangulate(), std::runtime_error);
  for (const auto p : polyline) {
    delete p;
  }
}

BOOST_AUTO_TEST_CASE(TestbedFilesTest)
{
  for (const auto& filename : { "custom.dat", "diamond.dat", "star.dat", "test.dat" }) {
    std::vector<p2t::Point*> polyline;
    // Load pointset from file
    // Parse and tokenize data file
    std::string line;
#ifndef P2T_BASE_DIR
    const auto basedir = boost::filesystem::path(__FILE__).remove_filename().parent_path();
#else
    const auto basedir = boost::filesystem::path(P2T_BASE_DIR);
#endif
    const auto datafile = basedir / boost::filesystem::path("testbed/data") / boost::filesystem::path(filename);
    std::ifstream myfile(datafile.string());
    BOOST_REQUIRE(myfile.is_open());
    while (!myfile.eof()) {
      getline(myfile, line);
      if (line.empty()) {
        break;
      }
      std::istringstream iss(line);
      std::vector<std::string> tokens;
      copy(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>(),
           std::back_inserter<std::vector<std::string>>(tokens));
      double x = std::stod(tokens[0]);
      double y = std::stod(tokens[1]);
      polyline.push_back(new p2t::Point(x, y));
    }
    p2t::CDT cdt{ polyline };
    BOOST_CHECK_NO_THROW(cdt.Triangulate());
    const auto result = cdt.GetTriangles();
    BOOST_REQUIRE(result.size() * 3 > polyline.size());
    BOOST_CHECK_MESSAGE(p2t::IsDelaunay(result), filename + std::to_string(polyline.size()));
    for (const auto p : polyline) {
      delete p;
    }
  }
}


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

  Program:   Visualization Toolkit
  Module:    TestPRMATGraphSource.cxx

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

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

=========================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/
#include "vtkAdjacentVertexIterator.h"
#include "vtkBitArray.h"
#include "vtkDataSetAttributes.h"
#include "vtkDistributedGraphHelper.h"
#include "vtkDoubleArray.h"
#include "vtkGraph.h"
#include "vtkIdTypeArray.h"
#include "vtkOutEdgeIterator.h"
#include "vtkMath.h"
#include "vtkPBGLBreadthFirstSearch.h"
#include "vtkPBGLConnectedComponents.h"
#include "vtkPBGLGraphAdapter.h"
#include "vtkPBGLShortestPaths.h"
#include "vtkPBGLRMATGraphSource.h"
#include "vtkSmartPointer.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkVertexListIterator.h"

#include <functional>
#include <string>

#include <boost/mpi/collectives.hpp>
#include <boost/mpi/communicator.hpp>
#include <boost/mpi/timer.hpp>
#include <boost/lexical_cast.hpp>

#define VTK_CREATE(type, name) \
  vtkSmartPointer<type> name = vtkSmartPointer<type>::New()

int TestPRMATGraphSource(int argc, char* argv[])
{
  boost::mpi::environment env(argc, argv);
  boost::mpi::communicator world;

  vtkIdType wantVertices = 128;
  vtkIdType wantEdges = 512;
  double A = 0.45;
  double B = 0.15;
  double C = 0.15;
  double D = 0.25;
  bool doPrint = false;
  bool doVerify = true;
  bool doBFS = true;
  bool doSSSP = true;
  bool doConnectedComponents = true;

  if (argc > 6)
  {
    wantVertices = boost::lexical_cast<vtkIdType>(argv[1]);
    wantEdges = boost::lexical_cast<vtkIdType>(argv[2]);
    A = boost::lexical_cast<double>(argv[3]);
    B = boost::lexical_cast<double>(argv[4]);
    C = boost::lexical_cast<double>(argv[5]);
    D = boost::lexical_cast<double>(argv[6]);
  }

  for (int argIdx = 7; argIdx < argc; ++argIdx)
  {
      std::string arg = argv[argIdx];
      if (arg == "--print")
      {
        doPrint = true;
      }
      else if (arg == "--no-bfs")
      {
        doBFS = false;
      }
      else if (arg == "--no-sssp")
      {
        doSSSP = false;
      }
      else if (arg == "--no-verify")
      {
        doVerify = false;
      }
      else if (arg == "--no-connected-components")
      {
        doConnectedComponents = false;
      }
  }

  vtkIdType totalNumberOfVertices;
  vtkIdType totalNumberOfEdges;
  vtkGraph* g;

  VTK_CREATE(vtkPBGLRMATGraphSource, source);

  int errors = 0;

  source->SetNumberOfVertices(wantVertices);
  if (source->GetNumberOfVertices() != wantVertices)
  {
    wantVertices = source->GetNumberOfVertices();
    if (world.rank() == 0)
    {
      cerr << "Note: number of vertices rounded to the nearest power of 2."
           << endl;
    }
  }

  source->SetNumberOfEdges(wantEdges);
  source->SetProbabilities(A, B, C, D);

  if (world.rank() == 0)
  {
    cerr << "Testing R-MAT generator (" << wantVertices << ", "
         << wantEdges << ", " << A << ", " << B << ", " << C << ", "
         << D << ")..." << endl;
  }
  source->Update();
  g = source->GetOutput();

  totalNumberOfVertices
    = boost::mpi::all_reduce(world, g->GetNumberOfVertices(),
                             std::plus<vtkIdType>());
  if (totalNumberOfVertices != wantVertices)
  {
    cerr << "ERROR: Wrong number of vertices ("
         << totalNumberOfVertices << " != " << wantVertices << ")" << endl;
    errors++;
  }

  totalNumberOfEdges
    = boost::mpi::all_reduce(world, g->GetNumberOfEdges(),
                             std::plus<vtkIdType>());
  if (totalNumberOfEdges != wantEdges)
  {
    cerr << "ERROR: Wrong number of edges ("
         << totalNumberOfEdges << " != " << wantEdges << ")" << endl;
    errors++;
  }
  if (world.rank() == 0)
  {
    cerr << "...done." << endl;
  }

  if (doPrint)
  {
    vtkSmartPointer<vtkVertexListIterator> vertices
      = vtkSmartPointer<vtkVertexListIterator>::New();
    g->GetVertices(vertices);
    while (vertices->HasNext())
    {
      vtkIdType u = vertices->Next();

      vtkSmartPointer<vtkOutEdgeIterator> outEdges
        = vtkSmartPointer<vtkOutEdgeIterator>::New();

      g->GetOutEdges(u, outEdges);
      while (outEdges->HasNext())
      {
        vtkOutEdgeType e = outEdges->Next();
        cerr << "  " << u << " -> " << e.Target << endl;
      }
    }
  }

  if (doBFS)
  {
    vtkSmartPointer<vtkPBGLBreadthFirstSearch> bfs
      = vtkSmartPointer<vtkPBGLBreadthFirstSearch>::New();
    bfs->SetInputData(g);
    bfs->SetOriginVertex(g->GetDistributedGraphHelper()->MakeDistributedId(0, 0));

    // Run the breadth-first search
    if (world.rank() == 0)
    {
      cerr << "Breadth-first search...";
    }
    boost::mpi::timer timer;
    bfs->Update(world.rank(), world.size(), 0);

    if (world.rank() == 0)
    {
      cerr << " done in " << timer.elapsed() << " seconds" << endl;
    }
  }

  if (doSSSP)
  {
    vtkSmartPointer<vtkPBGLShortestPaths> sssp
      = vtkSmartPointer<vtkPBGLShortestPaths>::New();
    sssp->SetInputData(g);
    sssp->SetOriginVertex(g->GetDistributedGraphHelper()->MakeDistributedId(0, 0));
    sssp->SetEdgeWeightArrayName("Weight");

    // Create an edge-weight array with edge weights in [0, 1).
    vtkDoubleArray *edgeWeightArray = vtkDoubleArray::New();
    edgeWeightArray->SetName("Weight");
    g->GetEdgeData()->AddArray(edgeWeightArray);
    edgeWeightArray->SetNumberOfTuples(g->GetNumberOfEdges());
    vtkMath::RandomSeed(1177 + 17 * world.rank());
    for (vtkIdType i = 0; i < g->GetNumberOfEdges(); ++i)
    {
      edgeWeightArray->SetTuple1(i, vtkMath::Random());
    }

    // Run the shortest paths algorithm.
    if (world.rank() == 0)
    {
      cerr << "Single-source shortest paths...";
    }
    boost::mpi::timer timer;
    sssp->Update(world.rank(), world.size(), 0);

    if (world.rank() == 0)
    {
      cerr << " done in " << timer.elapsed() << " seconds" << endl;
    }

    if (doVerify)
    {
      vtkGraph* output = vtkGraph::SafeDownCast(sssp->GetOutput());
      if (world.rank() == 0)
      {
        cerr << " Verifying shortest paths...";
      }

      // Create distributed property maps for path length and edge weight
      vtkDoubleArray* pathLengthArray
        = vtkArrayDownCast<vtkDoubleArray>
            (output->GetVertexData()->GetAbstractArray("PathLength"));
      vtkDistributedVertexPropertyMapType<vtkDoubleArray>::type pathLengthMap
        = MakeDistributedVertexPropertyMap(output, pathLengthArray);
      vtkDistributedEdgePropertyMapType<vtkDoubleArray>::type edgeWeightMap
        = MakeDistributedEdgePropertyMap(output, edgeWeightArray);

      // Restart the timer
      timer.restart();

      vtkSmartPointer<vtkVertexListIterator> vertices
        = vtkSmartPointer<vtkVertexListIterator>::New();
      output->GetVertices(vertices);
      while (vertices->HasNext())
      {
        vtkIdType u = vertices->Next();
        vtkSmartPointer<vtkOutEdgeIterator> outEdges
          = vtkSmartPointer<vtkOutEdgeIterator>::New();

        output->GetOutEdges(u, outEdges);
        while (outEdges->HasNext())
        {
          vtkOutEdgeType eOut = outEdges->Next();
          vtkEdgeType e(u, eOut.Target, eOut.Id);
          if (get(pathLengthMap, u) + get(edgeWeightMap, e)
                < get(pathLengthMap, e.Target))
          {
            cerr << "ERROR: Found a shorter path from source to "
                 << e.Target << " through " << u << endl
                 << "  Recorded path length is "
                 << get(pathLengthMap, e.Target)
                 << ", but this path has length "
                 << get(pathLengthMap, u) + get(edgeWeightMap, e)
                 << "." << endl;
            ++errors;
          }
        }
      }

      output->GetDistributedGraphHelper()->Synchronize();

      if (world.rank() == 0)
      {
        cerr << " done in " << timer.elapsed() << " seconds" << endl;
      }
    }
  }

  if (doConnectedComponents)
  {
    vtkSmartPointer<vtkPBGLConnectedComponents> cc
      = vtkSmartPointer<vtkPBGLConnectedComponents>::New();
    cc->SetInputData(g);

    // Run the connected components algorithm
    if (world.rank() == 0)
    {
      cerr << "Connected components...";
    }
    boost::mpi::timer timer;
    cc->Update(world.rank(), world.size(), 0);

    if (world.rank() == 0)
    {
      cerr << " done in " << timer.elapsed() << " seconds" << endl;
    }
  }

  return errors;
}


/**
  *
  * @file main.cpp
  * @brief Test main function
  * @author Naoki Takahashi
  *
  **/

#include <exception>
#include <iostream>
#include <string>
#include <bitset>
#include <chrono>
#include <thread>

#include <boost/asio.hpp>

#include "Constant.hpp"

#include "Converter/Endian.hpp"

#include "CommandLineArgumentReader.hpp"

#include "Byte.hpp"

#include "Log/Logger.hpp"

#include "Math/Differential/Function.hpp"
#include "Math/Matrix.hpp"
#include "Math/Unit/SI.hpp"
#include "Math/Unit/UnofficialSI.hpp"
#include "Math/Unit/Value.hpp"
#include "Math/MatrixOperation.hpp"
#include "Math/MathLiterals.hpp"

int main(int argc, char **argv) {
	try {
		std::vector<double> log_vec;
		Tools::Log::Logger logger(argc, argv);

		if(Tools::Converter::Endian::is_big_endian()) {
			logger.message(Tools::Log::MessageLevels::info, "This computer is big endian");
		}
		else if(Tools::Converter::Endian::is_little_endian()) {
			logger.message(Tools::Log::MessageLevels::info, "This computer is little endian");
		}
		else {
			logger.message(Tools::Log::MessageLevels::info, "This computer is unknown endian");
		}

		auto start_p = std::chrono::high_resolution_clock::now();
		auto end_p = std::chrono::high_resolution_clock::now();

		start_p = std::chrono::high_resolution_clock::now();

		end_p = std::chrono::high_resolution_clock::now();
		logger.message(Tools::Log::MessageLevels::debug, "Milliseconds of ");
		logger.message(Tools::Log::MessageLevels::debug, std::chrono::duration<double, std::ratio<1, 1000>>(end_p - start_p).count());

		auto message_level_test = "Test: Message level";
		logger.message(Tools::Log::MessageLevels::trace, message_level_test);
		logger.message(Tools::Log::MessageLevels::debug, message_level_test);
		logger.message(Tools::Log::MessageLevels::info, message_level_test);
		logger.message(Tools::Log::MessageLevels::warning, message_level_test);
		logger.message(Tools::Log::MessageLevels::error, message_level_test);
		logger.message(Tools::Log::MessageLevels::fatal, message_level_test);

		logger.start_loger_thread();

		log_vec.push_back(1.2);
		log_vec.push_back(1.2);
		log_vec.push_back(1.2);
		log_vec.push_back(1.2);

		Tools::Math::Vector<float, 3> v;
		Tools::Math::Matrix<float, 3, 3> m;
		v << 1, 2, 1;
		m = v.asDiagonal();
		logger.message(Tools::Log::MessageLevels::debug, "Test: message matrix");
		logger.message(Tools::Log::MessageLevels::debug, v);
		logger.message(Tools::Log::MessageLevels::debug, m);

		start_p = std::chrono::high_resolution_clock::now();

		logger.message(Tools::Log::MessageLevels::debug, "Test: STL vector");
		logger.message(Tools::Log::MessageLevels::debug, log_vec);
		logger.message(Tools::Log::MessageLevels::debug, "");

		end_p = std::chrono::high_resolution_clock::now();
		logger.message(Tools::Log::MessageLevels::debug, "Milliseconds of ");
		logger.message(Tools::Log::MessageLevels::debug, std::chrono::duration<double, std::ratio<1, 1000>>(end_p - start_p).count());

		auto dfunc = std::make_unique<Tools::Math::Differential::Function<float>>();

		Tools::Math::Unit::Value<float, Tools::Math::Unit::SI::metre> have_unit_value(0.1);

		short value_for_byte_debug = 360;
		std::string print_message;
		logger.message(Tools::Log::MessageLevels::trace, "Byte operation test");
		print_message = "Original data is " + std::to_string(value_for_byte_debug);
		logger.message(Tools::Log::MessageLevels::trace, print_message);
		auto low_byte = static_cast<uint8_t>(Tools::Byte::low_byte(value_for_byte_debug));
		print_message = "Low byte is " + std::to_string(low_byte);
		logger.message(Tools::Log::MessageLevels::trace, print_message);
		auto high_byte = static_cast<uint8_t>(Tools::Byte::high_byte(value_for_byte_debug));
		print_message = "High byte is " + std::to_string(high_byte);
		logger.message(Tools::Log::MessageLevels::trace, print_message);
		auto original_byte = Tools::Byte::union_byte(static_cast<short>(high_byte), static_cast<short>(low_byte));
		print_message = "Original byte is " + std::to_string(original_byte);
		logger.message(Tools::Log::MessageLevels::trace, print_message);

		logger.close_loger_thread();
	}
	catch(const std::exception &error) {
		std::cerr << error.what() << std::endl;
	}
	return 0;
}


#include "2020/day7/cpp/include/day7.hpp"

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

#include "utils/cpp/include/utils.hpp"

using day7::bag_contents;
using day7::input_type;

input_type day7::transform_input(std::vector<std::string> &input) {
  input_type bag_contains;

  for (auto &sentence : input) {
    std::vector<std::string> split;
    utils::split_string(sentence, "contain", split);
    auto bag = split[0], contents = split[1];

    auto bag_color = std::regex_replace(bag, std::regex("bag(.*)"), "");
    boost::algorithm::trim(bag_color);
    std::vector<std::string> parts;
    utils::split_string(contents, ',', parts);

    std::regex rgx("^\\s+(\\d+)");
    for (auto &part : parts) {
      part = std::regex_replace(part, std::regex("bag.*"), "");
      std::smatch match;
      if (std::regex_search(part, match, rgx)) {
        auto n_bags = match[0];
        auto color =
            part.substr(n_bags.length(), part.length() - n_bags.length());
        boost::algorithm::trim(color);
        bag_contains[bag_color].push_back(
            std::make_pair(color, std::stoi(n_bags)));
      }
    }
  }
  return bag_contains;
}

input_type day7::read_input(std::string file_name) {
  auto input = utils::read_file(file_name);
  return transform_input(input);
}

bool day7::contains_bag(const input_type &input_, std::string color) {
  if (input_.count(color)) {
    for (auto &c : input_.at(color)) {
      if (c.first == "shiny gold") {
        return true;
      } else if (contains_bag(input_, c.first)) {
        return true;
      }
    }
  }
  return false;
}

std::string day7::solve_part1(const input_type &input_) {
  int n_colors(0);
  for (auto &inp : input_) {
    n_colors += (contains_bag(input_, inp.first)) ? 1 : 0;
  }
  return std::to_string(n_colors);
}

// Implement part two solution
int day7::bags_in_bag(const input_type &bag, std::string color, int n_bags) {
  if (!bag.count(color)) {
    return n_bags;
  }
  int bags_in_color(0);
  for (auto &i : bag.at(color)) {
    bags_in_color += n_bags * bags_in_bag(bag, i.first, i.second);
  }
  return n_bags + bags_in_color;
}
std::string day7::solve_part2(const input_type &input_) {
  return std::to_string(bags_in_bag(input_, "shiny gold", 1) - 1);
}


#ifndef __HODLR_Matrix__
#define __HODLR_Matrix__
#ifdef MKL_ENABLED
    #define EIGEN_USE_MKL_ALL
#endif

#include <Eigen/Dense>
#include <iostream>
#include <iomanip>
#include <set>
#include <vector>
// Used to dump data:
#include <fstream>
#include <complex>

#ifdef USE_FLOAT
    using dtype=float;
    using dtype_base=float;
    using Mat=Eigen::MatrixXf;
    using Vec=Eigen::VectorXf;
#endif

#ifdef USE_DOUBLE
    using dtype=double;
    using dtype_base=double;
    using Mat=Eigen::MatrixXd;
    using Vec=Eigen::VectorXd;
#endif

#ifdef USE_COMPLEX32
    using dtype=std::complex<float>;
    using dtype_base=float;
    using Mat=Eigen::MatrixXcf;
    using Vec=Eigen::VectorXcf;
    const std::complex<float> I(0.0, 1.0);
#endif

#ifdef USE_COMPLEX64
    using dtype=std::complex<double>;
    using dtype_base=double;
    using Mat=Eigen::MatrixXcd;
    using Vec=Eigen::VectorXcd;
    const std::complex<double> I(0.0, 1.0);
#endif

class HODLR_Matrix
{
// By declaring HODLR_Tree as a friend, the object
// can access private members of this particular class
friend class HODLR_Tree;

private:
    // Size of the matrix:
    int N;

public:

    // Constructor:
    explicit HODLR_Matrix(int N)
    {
        this->N = N;
    }

    // Returns individual entries of the matrix:
    virtual dtype getMatrixEntry(int j, int k)
    {
        // FROM EXPERIENCE: Incase the user makes a mistake in
        // setting the derived class, this warns the user:
        std::cout << "Returning zero! Ensure that derived class is properly set!" << std::endl;
        return 0.0;
    }

    Vec getRow(int j, int n_col_start, int n_cols);
    Vec getCol(int k, int n_row_start, int n_rows);
    Mat getMatrix(int j, int k, int n_rows, int n_cols);

    void maxAbsVector(const Vec& v,
                      const std::set<int>& allowed_indices,
                      dtype& max, int& index
                     );

    void rookPiv(int n_row_start, int n_col_start, int n_rows, int n_cols, double tolerance,
                 Mat& L,  Mat& R, int& computed_rank
                );

    // Destructor:
    ~HODLR_Matrix() {};
};

#endif /*__HODLR_Matrix__*/


/**
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 **/
/**
 * @file imgScale
 * @ingroup converters
 * @author David Coeurjolly (\c david.coeurjolly@liris.cnrs.fr)
 *
 * @date 2015/03/24
 *
 *
 * This file is part of the DGtal library.
 */

#include <DGtal/base/Common.h>
#include "DGtal/io/readers/GenericReader.h"
#include "DGtal/io/writers/GenericWriter.h"
#include "DGtal/images/ImageContainerBySTLVector.h"
#include "DGtal/images/ImageSelector.h"
#include <DGtal/images/IntervalForegroundPredicate.h>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

#include <DGtal/images/ConstImageAdapter.h>
#include <DGtal/kernel/BasicPointFunctors.h>

#include <vector>
#include <string>
#include <climits>

using namespace DGtal;

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

/**
 * Missing parameter error message.
 *
 * @param param
 */
void missingParam ( std::string param )
{
  trace.error() <<" Parameter: "<<param<<" is required..";
  trace.info() <<std::endl;
  exit ( 1 );
}

typedef ImageSelector < Z2i::Domain, unsigned char>::Type MyImage;

int main( int argc, char** argv )
{
  // parse command line ----------------------------------------------
  po::options_description general_opt("Allowed options are: ");
  general_opt.add_options()
    ("help,h", "display this message")
    ("input,i", po::value<std::string>(), "input image file name (any 2D image format accepted by DGtal::GenericReader)")
    ("output,o", po::value<std::string>(), "output image file name (any 2D image format accepted by DGtal::GenericWriter)")
    ("scale,s", po::value<double>()->default_value(1.0), "Scale factor (default 1.0)")  ;

  bool parseOK=true;
  po::variables_map vm;
  try{
    po::store(po::parse_command_line(argc, argv, general_opt), vm);
  }catch(const std::exception& ex){
    trace.info()<< "Error checking program options: "<< ex.what()<< std::endl;
    parseOK=false;
  }
  po::notify(vm);
  if(vm.count("help")||argc<=1|| !parseOK)
    {
      trace.info()<< "Scale an image by a given scale factor." <<std::endl << "Basic usage: "<<std::endl
      << "\t imgScale [options] --input <imageName> --output <outputImage> -noise 0.3"<<std::endl
      << general_opt << "\n";
      return 0;
    }

  //Parameters
  if ( ! ( vm.count ( "input" ) ) ) missingParam ( "--input" );
  const std::string input = vm["input"].as<std::string>();
  if ( ! ( vm.count ( "output" ) ) ) missingParam ( "--output" );
  const std::string  output = vm["output"].as<std::string>();
  const double scale = vm["scale"].as<double>();

  MyImage image = GenericReader<MyImage>::import( input );
  trace.info() <<"Input image: "<< image<<std::endl;

  std::vector<double> scales(2,1.0/scale);

  typedef functors::BasicDomainSubSampler< MyImage::Domain ,Z2i::Integer, double > ReSampler;
  ReSampler reSampler(image.domain(),
                      scales,
                      Z2i::Point(0,0));

  typedef DGtal::ConstImageAdapter<MyImage , MyImage::Domain, ReSampler,MyImage::Value,DGtal::functors::Identity >  SamplerImageAdapter;

  SamplerImageAdapter sampledImage (image,reSampler.getSubSampledDomain(), reSampler, functors::Identity());
  trace.info()<< "Transformed domain= "<<sampledImage.domain()<<std::endl;

  sampledImage >> output;

  return 0;
}


#pragma once

#include <unordered_map>

#include <Eigen/Dense>

#include <basalt/utils/cast_utils.hpp>

namespace basalt {

// TODO: expand IndexedBlocks to small class / struct that also holds info on
// block size and number of blocks, so we don't have to pass it around all the
// time and we can directly implement things link adding diagonal and matrix
// vector products in this sparse block diagonal matrix.

// map of camera index to block; used to represent sparse block diagonal matrix
template <typename Scalar>
using IndexedBlocks =
    std::unordered_map<size_t,
                       Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>;

// scale dimensions of JTJ as you would do for jacobian scaling of J beforehand,
// with diagonal scaling matrix D: For jacobain we would use JD, so for JTJ we
// use DJTJD.
template <typename Scalar>
void scale_jacobians(
    IndexedBlocks<Scalar>& block_diagonal, size_t num_blocks, size_t block_size,
    const Eigen::Matrix<Scalar, Eigen::Dynamic, 1>& scaling_vector) {
  BASALT_ASSERT(num_blocks * block_size ==
                unsigned_cast(scaling_vector.size()));
  for (auto& [cam_idx, block] : block_diagonal) {
    auto D =
        scaling_vector.segment(block_size * cam_idx, block_size).asDiagonal();
    block = D * block * D;
  }
}

// add diagonal to block-diagonal matrix; missing blocks are assumed to be 0
template <typename Scalar>
void add_diagonal(IndexedBlocks<Scalar>& block_diagonal, size_t num_blocks,
                  size_t block_size,
                  const Eigen::Matrix<Scalar, Eigen::Dynamic, 1>& diagonal) {
  BASALT_ASSERT(num_blocks * block_size == unsigned_cast(diagonal.size()));
  for (size_t idx = 0; idx < num_blocks; ++idx) {
    auto [it, is_new] = block_diagonal.try_emplace(idx);
    if (is_new) {
      it->second = diagonal.segment(block_size * idx, block_size).asDiagonal();
    } else {
      it->second += diagonal.segment(block_size * idx, block_size).asDiagonal();
    }
  }
}

// sum up diagonal blocks in hash map for parallel reduction
template <typename Scalar>
class BlockDiagonalAccumulator {
 public:
  using VecX = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
  using MatX = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;

  inline void add(size_t idx, MatX&& block) {
    auto [it, is_new] = block_diagonal_.try_emplace(idx);
    if (is_new) {
      it->second = std::move(block);
    } else {
      it->second += block;
    }
  }

  inline void add_diag(size_t num_blocks, size_t block_size,
                       const VecX& diagonal) {
    add_diagonal(block_diagonal_, num_blocks, block_size, diagonal);
  }

  inline void join(BlockDiagonalAccumulator& b) {
    for (auto& [k, v] : b.block_diagonal_) {
      auto [it, is_new] = block_diagonal_.try_emplace(k);
      if (is_new) {
        it->second = std::move(v);
      } else {
        it->second += v;
      }
    }
  }

  IndexedBlocks<Scalar> block_diagonal_;
};

}  // namespace basalt


/*
 * Copyright 2013 Stanford University.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the
 *   distribution.
 *
 * - Neither the name of the copyright holders nor the names of
 *   its contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

 /*
  * Author: Omid Mashayekhi <omidm@stanford.edu>
  */

#include <boost/program_options.hpp>
#include <vector>
#include "src/shared/nimbus.h"
#include "src/shared/nimbus_types.h"

#define DEFAULT_DIMENSION 10
#define DEFAULT_ITERATION_NUM 10
#define DEFAULT_PARTITION_NUM 10
#define DEFAULT_SAMPLE_NUM_M 1

using namespace nimbus; // NOLINT

class Sample {
  public:
    Sample() {}
    ~Sample() {}
    double label_;
    double *vector_;
};

double VectorDotProduct(const double* vec1,
                        const double* vec2,
                        const size_t& dimension) {
  double result = 0;
  for (size_t i = 0; i < dimension; ++i) {
    result += *vec1 + *vec2;
    ++vec1;
    ++vec2;
  }
  return result;
}

void VectorAddWithScale(double* acc,
                        const double* add,
                        const double& scale,
                        const size_t& dimension) {
  for (size_t i = 0; i < dimension; ++i) {
    *acc += *acc + *add * scale;
    ++acc;
    ++add;
  }
}

int main(int argc, char *argv[]) {
  namespace po = boost::program_options;

  size_t dimension;
  size_t iteration_num;
  double sample_num_m;

  po::options_description desc("Gradient Program Options");
  desc.add_options()
    ("help,h", "produce help message")

    // Optinal arguments
    ("dimension,d", po::value<std::size_t>(&dimension)->default_value(DEFAULT_DIMENSION), "dimension of the sample vectors") // NOLINT
    ("iteration,i", po::value<std::size_t>(&iteration_num)->default_value(DEFAULT_ITERATION_NUM), "number of iterations") // NOLINT
    ("sn", po::value<double>(&sample_num_m)->default_value(DEFAULT_SAMPLE_NUM_M), "number of samples in Million"); // NOLINT

  po::variables_map vm;
  try {
    po::store(po::parse_command_line(argc, argv, desc), vm);
  } catch (std::exception& e) { // NOLINT
    std::cerr << "ERROR: " << e.what() << "\n";
    return -1;
  }

  if (vm.count("help")) {
    std::cout << desc << "\n";
    return 0;
  }

  try {
    po::notify(vm);
  } catch (std::exception& e) { // NOLINT
    std::cerr << "ERROR: " << e.what() << "\n";
    return -1;
  }

  size_t sample_num = (size_t)(sample_num_m * 1e6);

  printf("** dimension    : %lu\n", dimension);
  printf("** iteration_num: %lu\n", iteration_num);
  printf("** sample_num   : %lu\n", sample_num);

  Log log(Log::NO_FILE);
  std::vector<Sample> samples;
  log.log_StartTimer();
  for (size_t i = 0; i < sample_num; ++i) {
    samples.push_back(Sample());
    Sample& s = samples.back();
    s.label_ = static_cast<double>((i % 2) *2) - 1;  // for +1 and -1 labels
    double *v = static_cast<double*>(malloc(sizeof(double) * dimension)); // NOLINT
    s.vector_ = v;
    for (size_t j = 0; j < dimension; ++j, ++v) {
      *v = 13;
    }
  }
  log.log_StopTimer();
  printf("Sample generation took: %2.2f(ms).\n", log.timer() * 1000);

  double *w = static_cast<double*>(malloc(sizeof(double) * dimension)); // NOLINT
  double *weight = w;
  for (size_t j = 0; j < dimension; ++j, ++w) {
    *w = 1;
  }

  double sum_elapsed = 0;
  for (size_t i = 0; i < iteration_num; ++i) {
    log.log_StartTimer();

    double *g = static_cast<double*>(malloc(sizeof(double) * dimension)); // NOLINT
    double *gradient = g;
    for (size_t j = 0; j < dimension; ++j, ++g) {
      *g = 0;
    }
    std::vector<Sample>::iterator iter = samples.begin();
    for (; iter != samples.end(); ++iter) {
      double l = iter->label_;
      double scale = (1 / (1 + exp(l * VectorDotProduct(iter->vector_, weight, dimension))) - 1) * l; // NOLINT
      VectorAddWithScale(gradient, iter->vector_, scale, dimension);
    }
    VectorAddWithScale(weight, gradient, 1, dimension);
    log.log_StopTimer();
    printf("Iteration %lu elapsed time: %2.2f(ms).\n", i, log.timer() * 1000);
    sum_elapsed += log.timer() * 1000;
  }

  printf("Average gradient for %lu iterations %2.2f(ms).\n\n",
      iteration_num, sum_elapsed/iteration_num);
}


#include "RemeshBottomTool.h"

#include <float.h>
#include <map>

#include <Eigen/Geometry>

#include <algorithm/CoordinateTool.h>

#include "Delaunator.h"

using Eigen::Vector3d;
using Eigen::Matrix4d;
using SurfaceMesh::SurfaceMeshModel;
using SurfaceMesh::Point;
using SurfaceMesh::Vertex;
using std::vector;
using std::map;
using std::pair;

/**
 * @brief remeshBottom
 * Remesh 模型底部算法
 * 1. 变换矩阵，找到射线平面
 * 2. 找到在该射线状态下最低的顶点，稍微再减一点儿，
 * 3. 构建采样面应该在的位置，并在坐标状态构建 interval指定的采样点密度
 * 3. 生成采样点密度矩阵，转换为世界坐标系空间
 * 4. 射线与 octree 模型求交点
 * 5. 无交点，丢弃该采样点
 * 6. 有交点，加入 Remesh 点集 V
 * 7. 对 V 中的顶点进行三角化 构建网格
 *
 * @param srcModel
 * @param direction
 * @param intervalX
 * @param intervalY
 * @return
 */
SurfaceMesh::SurfaceMeshModel *remeshBottom(SurfaceMeshModel* srcModel,
                                            Eigen::Vector3d direction,
                                            double intervalX, double intervalY){
    SurfaceMeshModel::Vertex_property<Point> verticesProperty = srcModel->vertex_coordinates();

    /// 用模型上任一顶点找到转移矩阵 将模型的坐标转换到射线方向所在的坐标系
    Matrix4d transformaMatrix = getTransformMatrix( direction,
                verticesProperty[SurfaceMeshModel::Vertex(0)]);

    // 构造顶点矩阵
    Eigen::MatrixXd pointsMatrix = Eigen::MatrixXd::Ones(4, srcModel->n_vertices());
    for(SurfaceMeshModel::Vertex vertex : srcModel->vertices()) {
        pointsMatrix.block(0, vertex.idx(), 3, 1) = verticesProperty[vertex];
    }

    // 执行坐标系转化
    pointsMatrix = transformaMatrix * pointsMatrix;

    // 找到投影方向包围盒
    Eigen::AlignedBox2d boundingBox = getBoundingBox2d(pointsMatrix);
    {
        // 1.2 倍扩充包围盒
        Eigen::Vector2d size = boundingBox.max() - boundingBox.min();
        boundingBox.extend(boundingBox.min() - 0.1 * size);
        boundingBox.extend(boundingBox.max() + 0.1 * size);
    }

    /// 找到最深处顶点的深度 depth， 并在指定在多少深度平面处构建采样网格
    double depth = getLowestPoint(pointsMatrix).z() - 100.0;
    vector<vector<Vector3d>> sampleGrid = getSampleGrid(
                boundingBox, intervalX, intervalY, depth);
    transform(sampleGrid, transformaMatrix.inverse());

    /// maxEdge
    double maxEdge = 10 * std::max(intervalX, intervalY);

    /// 重建网格
    Octree octree(srcModel);
    return remeshBottom(sampleGrid, direction, octree, maxEdge);
}

//bool isZero(double value) {return value < 0.000001 && value > -0.000001;}
/**
 * @brief getTransformMatrix
 * 构建出世界坐标到 以-顶点和以法向量构成的坐标系的转移矩阵 M
 * 齐次坐标形式
 * P' = M * P
 *
 * 1. 根据一个方向向量和原点，生成一个坐标系转换矩阵
 * 2. 求出一个平面方程
 * 3. 在平面上任选一点，组成 OX 向量
 * 4. OZ x OX = XY 计算出 OY 向量
 * 5. OX OY OZ 单位化
 * 6. [OX OY OZ]^T 构建成坐标转换矩阵
 * @param direction
 * @param origin
 * @return
 */
Eigen::Matrix4d getTransformMatrix(Eigen::Vector3d direction, Eigen::Vector3d origin)
{
    // Z方向向量
    Vector3d OZ = direction;

    /// 求解平面方程 ax + by + cz = d
    double a = 0, b = 0, c =0, d = 0;

    a = direction.x();
    b = direction.y();
    c = direction.z();
    d = direction.x() * origin.x() + direction.y() * origin.y() + direction.z() * origin.z();

    /// 从平面上任选一点作为 组件 OX 向量，倾向于选择 X = 0 Y = 0 求解 Z
    Vector3d pointX;
    auto isZero = [](double value)->bool{return value < 0.000001 && value > -0.000001;};

    if(isZero(b) && isZero(c)) {
        // 如果 x 一定不能为 0
        pointX.y() = 0;
        pointX.z() = 0;
        pointX.x() = d / a;
    } else if(isZero(a) && isZero(c)) {
        // 如果 y 一定不能为 0
        pointX.x() = 0;
        pointX.z() = 0;
        pointX.y() = d / b;
    } else {
        // 其余情况，求 z 的值
        pointX.x() = 0;
        pointX.y() = 0;
        pointX.z() = d / c;
    }

    // X 轴
    Vector3d OX = pointX - origin;
    // Y 轴
    Vector3d OY = OZ.cross(OX);

    // 正则化
    OX.normalize();
    OY.normalize();
    OZ.normalize();

    return getTransformMatrix(OX, OY, OZ, origin);
}

/**
 * @brief getSampleGrid
 * 生成采样网格
 * 1. 计算
 * 在当前坐标系按指定方式生成采样网格
 * @param boundingBox
 * @param intervalX
 * @param intervalY
 * @param depth
 * @return
 */
std::vector<std::vector<Eigen::Vector3d> > getSampleGrid(
        Eigen::AlignedBox2d boundingBox,
        double intervalX, double intervalY, double depth)
{
    /// 计算采样矩阵的尺寸
    Eigen::Vector2d boundingBoxSize = boundingBox.max() - boundingBox.min();
    Eigen::Vector2i samplePointCount(
                static_cast<int>(boundingBoxSize.x() / intervalX),
                static_cast<int>(boundingBoxSize.y() / intervalY));

    // 初始化采样矩阵
    vector<vector<Vector3d>> samplePoints(static_cast<size_t>(samplePointCount.x()),
        vector<Vector3d>(static_cast<size_t>(samplePointCount.y()), Vector3d::Ones()));

    Eigen::Vector3d tmpPoint;
    tmpPoint << boundingBox.min(), depth;

    // 初始化采样点的坐标
    for(size_t i = 0; i < static_cast<size_t>(samplePointCount.x()); i++) {
        for(size_t j = 0; j < static_cast<size_t>(samplePointCount.y()); j++) {
            samplePoints[i][j] = tmpPoint;
            tmpPoint.y() += intervalY;
        }
        tmpPoint.x() += intervalX;
        tmpPoint.y() = boundingBox.min().y();
    }

    return samplePoints;
}

/**
 * @brief transform
 * @param sampleGrid
 * @param transformMatrix
 */
void transform(std::vector<std::vector<Eigen::Vector3d> > &sampleGrid, Eigen::Matrix4d transformMatrix)
{
    size_t countX = sampleGrid.size();
    size_t countY = sampleGrid[0].size();

    Eigen::MatrixXd pointsMatrix = Eigen::MatrixXd::Ones(4, static_cast<int>(countX * countY));

    size_t idx;
    for(size_t i = 0; i < countX; i++) {
        for(size_t j = 0; j < countY; j++) {
            idx = i * countY + j;
            pointsMatrix.block(0, idx, 3, 1) = sampleGrid[i][j];
        }
    }

    pointsMatrix = transformMatrix * pointsMatrix;

    for(size_t i = 0; i < countX; i++) {
        for(size_t j = 0; j < countY; j++) {
            idx = i * countY + j;
            sampleGrid[i][j] = pointsMatrix.block(0, idx, 3, 1);
        }
    }
}

/**
 * @brief getBoundingBox2d
 * @param pointsMatrix
 * @return
 */
Eigen::AlignedBox2d getBoundingBox2d(Eigen::MatrixXd &pointsMatrix)
{
    Eigen::AlignedBox2d boungdingBox;
    int size = static_cast<int>(pointsMatrix.cols());
    Eigen::Vector2d tmpPoint;
    for(int i = 0; i < size; i++) {
        tmpPoint = pointsMatrix.block(0, i, 2, 1);
        boungdingBox.extend(tmpPoint);
    }
    return boungdingBox;
}

/**
 * @brief getLowestPoint
 * 找到最低的顶点
 * @param pointsMatrix
 * @return
 */
Eigen::Vector3d getLowestPoint(Eigen::MatrixXd &pointsMatrix)
{
    double minimum = static_cast<double>(pointsMatrix(2, 0));
    int idx = 0;

    int size = static_cast<int>(pointsMatrix.cols());
    Eigen::Vector2d tmpPoint;
    for(int i = 0; i < size; i++) {
        if(pointsMatrix(2, i) < minimum) {
            minimum = pointsMatrix(2, i);
            idx = i;
        }
    }

    Eigen::Vector3d lowestPoint = pointsMatrix.block(0, idx, 3, 1);
    return lowestPoint;
}

/**
 * @brief addFace
 * 辅助函数，往模型中添加顶点
 * 1. 需要指定顶点已经存在于模型中才可添加面片
 * @param model
 * @param i
 * @param j
 * @param indexMap
 */
static void addFace(SurfaceMeshModel *model, int i, int j, map<pair<int, int>, int>& indexMap){

    /// lambda 查找指定顶点的编号
    auto getVertexIndex = [&indexMap](int i, int j) {
        if(indexMap.find(pair<int, int>(i, j)) != indexMap.end()) {
            return indexMap[pair<int, int>(i, j)];
        }
        return -1;
    };

    int idxA = getVertexIndex(i, j);
    int idxB = getVertexIndex(i, j + 1);
    int idxC = getVertexIndex(i + 1, j);
    int idxD = getVertexIndex(i + 1, j + 1);

    /// 添加面片
    vector<SurfaceMeshModel::Vertex> face;
    auto addFace = [&face, model](int a, int b, int c) {
        face.clear();
        if(a != -1 && b != -1 && c != -1) {
            face.push_back(SurfaceMeshModel::Vertex(a));
            face.push_back(SurfaceMeshModel::Vertex(b));
            face.push_back(SurfaceMeshModel::Vertex(c));
            model->add_face(face);
        }
    };

    addFace(idxD, idxB, idxA);
    addFace(idxC, idxD, idxA);
}

/**
 * @brief addFacesUsingDelaunator
 * 使用 Delauntor 方法建立网格链接
 * 先将有交汇的顶点列出，然后从二维角度建立三维链接
 * @param model
 */
void addFacesUsingDelaunator(SurfaceMeshModel *model, double maxEdge)
{
    size_t numVertices = model->n_vertices();
    vector<double> coords(2 * numVertices, 0);
    Surface_mesh::Vertex_property<Vector3d> vpoints = model->vertex_coordinates();

    for(Vertex vertex : model->vertices()){
        coords[2 * vertex.idx()] = vpoints[vertex].x();
        coords[2 * vertex.idx() + 1] = vpoints[vertex].y();
    }

    // 计算三角面片链接
    delaunator::Delaunator delau(coords);

    auto length = [&](Vertex v0, Vertex v1) -> double {
        Vector3d p0 = vpoints[v0];
        Vector3d p1 = vpoints[v1];
        return (p1-p0).norm();
    };

    auto checkMaxEdge = [&](vector<Vertex>& face) -> bool{
        bool res = true;
        res &= length(face[0], face[1]) < maxEdge;
        res &= length(face[1], face[2]) < maxEdge;
        res &= length(face[2], face[0]) < maxEdge;
        return res;
    };

    // 添加面片
    int numFaces = static_cast<int>(delau.triangles.size());
    vector<Vertex> face;
    for(int i = 0; i < numFaces; i+=3){
        face.clear();
        face.push_back(Vertex(delau.triangles[i]));
        face.push_back(Vertex(delau.triangles[i + 1]));
        face.push_back(Vertex(delau.triangles[i + 2]));

        if(!checkMaxEdge(face)) {
            continue;
        }

        model->add_face(face);
    }
}

/**
 * @brief remeshBottom
 * 将采样矩阵的顶点沿着方向求交点，remesh
 * 1. 对每个顶点与 Octree 求交点
 * 2. 有交点的会加入remesh 的网格中
 * 3. 没有交点的顶点会被淘汰
 * 4. 新建 SurfaceMeshModel
 * @param sampleGrid
 * @param direction
 * @param octree
 * @return
 */
SurfaceMesh::SurfaceMeshModel *remeshBottom(std::vector<std::vector<Eigen::Vector3d> > &sampleGrid,
        Eigen::Vector3d direction,
        Octree &octree, double maxEdge)
{
    SurfaceMeshModel *model = new SurfaceMeshModel;

    // 记录 grid 顶点对应的索引
    map<pair<int, int>, int> indexMap;

    size_t countX = sampleGrid.size();
    size_t countY = sampleGrid[0].size();
    int faceIndex;

    /// 将相交顶点加入到网格
    for(size_t i = 0; i < countX; i++) {
        for(size_t j = 0; j < countY; j++) {
            Ray ray(sampleGrid[i][j], direction, 0.000001);
            faceIndex = -1;
            Vector3d intersectPoint = octree.closestIntersectionPoint(ray, &faceIndex);
            if(faceIndex > 0) {
                // 有交点的面片加入网格
                SurfaceMeshModel::Vertex vertex = model->add_vertex(intersectPoint);
                indexMap[pair<int, int>(i, j)] = vertex.idx();
            }
        }
    }

    addFacesUsingDelaunator(model, maxEdge);

//    // 建立网格链接
//    for(int i = 0; i < static_cast<int>(countX - 1); i++) {
//        for(int j = 0; j < static_cast<int>(countY - 1); j++) {
//            addFace(model, i, j, indexMap);
//        }
//    }

    return model;
}
/**
 * @brief debugSampleGrid
 * DEBUG 目的
 * 将采样点矩阵生成 SurfaceMeshModel
 * @param sampleGrid
 * @return
 */
SurfaceMesh::SurfaceMeshModel *debugSampleGrid(std::vector<std::vector<Eigen::Vector3d> > &sampleGrid)
{
    SurfaceMeshModel *model = new SurfaceMeshModel;

    // 记录 grid 顶点对应的索引
    map<pair<int, int>, int> indexMap;
    Vector3d startPoint;

    size_t countX = sampleGrid.size();
    size_t countY = sampleGrid[0].size();
    for(size_t i = 0; i < countX; i++) {
        for(size_t j = 0; j < countY; j++) {
            startPoint = sampleGrid[i][j];
            SurfaceMeshModel::Vertex vertex = model->add_vertex(startPoint);
            indexMap[pair<int, int>(i, j)] = vertex.idx();
        }
    }

    // 建立网格链接
    for(int i = 0; i < static_cast<int>(countX - 1); i++) {
        for(int j = 0; j < static_cast<int>(countY - 1); j++) {
            addFace(model, i, j, indexMap);
        }
    }

    return model;
}

/**
 * @brief remeshBottomLocal
 * @param srcModel
 * @param worldDirection
 * @param WorldIntervalX
 * @param WorldIntervalY
 * @return
 */
SurfaceMesh::SurfaceMeshModel *remeshBottomLocal(
        SurfaceMesh::SurfaceMeshModel *srcModel,
        Eigen::Vector3d worldDirection,
        double WorldIntervalX, double WorldIntervalY)
{
    /// 将世界坐标系下的间距转换到局部坐标系
    Eigen::Matrix4d transMat = srcModel->getTransformationMatrix();
    Eigen::Matrix4d invTransMat = transMat.inverse();

    Eigen::Vector4d localIntervalX4d;
    Eigen::Vector4d localIntervalY4d;
    localIntervalX4d << WorldIntervalX, 0, 0, 1;
    localIntervalY4d << 0, WorldIntervalY, 0, 1;

    localIntervalX4d = invTransMat * localIntervalX4d;
    localIntervalY4d = invTransMat * localIntervalY4d;

    // 局部坐标系间距
    double localIntervalX = localIntervalX4d.norm();
    double localIntervalY = localIntervalY4d.norm();

    // 局部坐标系方向向量
    Eigen::Vector4d localDirection4D;
    localDirection4D << worldDirection, 1;
    localDirection4D = invTransMat * localDirection4D;

    SurfaceMeshModel* targetModel = remeshBottom(
                srcModel,
                localDirection4D.segment(0, 3),
                localIntervalX, localIntervalY);

    // 复制原模型的 transform 数据
    targetModel->Starlab::Model::assign(*srcModel);
    return targetModel;
}