#include <fstream>

#include <boost/config.hpp>
#include <boost/version.hpp>
// CGAL headers
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Snap_rounding_traits_2.h>
#include <CGAL/Snap_rounding_2.h>
#include <CGAL/Snap_rounding_traits_2.h>

// Qt headers
#include <QtGui>
#include <QString>
#include <QActionGroup>
#include <QFileDialog>
#include <QInputDialog>

// GraphicsView items and event filters (input classes)
#include <CGAL/Qt/RegularGridGraphicsItem.h>
#include <CGAL/Qt/SegmentsGraphicsItem.h>
#include <CGAL/Qt/PolylinesGraphicsItem.h>
#include <CGAL/Qt/GraphicsViewPolylineInput.h>
#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500)
#include <CGAL/IO/WKT.h>
#endif

// for viewportsBbox
#include <CGAL/Qt/utility.h>

// the two base classes
#include "ui_Snap_rounding_2.h"
#include <CGAL/Qt/DemosMainWindow.h>

typedef CGAL::Exact_predicates_exact_constructions_kernel K;
typedef CGAL::Snap_rounding_traits_2<K>     Traits;

typedef K::Point_2 Point_2;
typedef K::Segment_2 Segment_2;
typedef K::Iso_rectangle_2 Iso_rectangle_2;

class MainWindow :
  public CGAL::Qt::DemosMainWindow,
  public Ui::Snap_rounding_2
{
  Q_OBJECT

private:

  QGraphicsScene scene;

  CGAL::Qt::RegularGridGraphicsItem<K> * rgi;

  CGAL::Qt::GraphicsViewPolylineInput<K> * pi;

  std::list<Segment_2> input;
  std::list<std::list<Point_2> > output;

  typedef CGAL::Qt::SegmentsGraphicsItem<std::list<Segment_2> > InputSegmentsGraphicsItem;
  typedef CGAL::Qt::PolylinesGraphicsItem<std::list<std::list<Point_2> > > OutputPolylinesGraphicsItem;
  InputSegmentsGraphicsItem * isgi;
  OutputPolylinesGraphicsItem *plgi;
  double delta;

public:
  MainWindow();

  void resize(){
  this->graphicsView->setSceneRect(QRectF(0,0,20, 20));
  this->graphicsView->fitInView(0,0, 20, 20, Qt::KeepAspectRatio);
  }

public Q_SLOTS:

  void processInput(CGAL::Object o);

  void on_actionLoadSegments_triggered();

  void on_actionClear_triggered();

  void on_actionSaveSegments_triggered();

  void on_actionRecenter_triggered();

  void on_actionShowGrid_toggled(bool checked);
  void on_actionShowInput_toggled(bool checked);
  void on_actionShowSnappedSegments_toggled(bool checked);

  void deltaChanged(double);

  virtual void open(QString fileName);

Q_SIGNALS:
  void changed();
};

MainWindow::MainWindow()
  : DemosMainWindow(), delta(1.0)
{
  setupUi(this);

  this->graphicsView->setAcceptDrops(false);

  isgi = new InputSegmentsGraphicsItem(&input);
  scene.addItem(isgi);

  plgi = new OutputPolylinesGraphicsItem(&output);
  scene.addItem(plgi);

 // inputs polylines with 2 points
  pi = new CGAL::Qt::GraphicsViewPolylineInput<K>(this, &scene, 2, false);
  QObject::connect(pi, SIGNAL(generate(CGAL::Object)),
		   this, SLOT(processInput(CGAL::Object)));

  scene.installEventFilter(pi);

  // Manual handling of actions
  //

  QObject::connect(this->doubleSpinBox, SIGNAL(valueChanged(double)),
		   this, SLOT(deltaChanged(double)));

  QObject::connect(this->actionQuit, SIGNAL(triggered()),
		   this, SLOT(close()));

  //
  // Setup the scene and the view
  //
  scene.setItemIndexMethod(QGraphicsScene::NoIndex);
  this->graphicsView->setScene(&scene);
  // Turn the vertical axis upside down
  this->graphicsView->matrix().scale(1, -1);
  this->graphicsView->setMouseTracking(true);

  rgi = new CGAL::Qt::RegularGridGraphicsItem<K>(delta, delta);

    QObject::connect(this, SIGNAL(changed()),
                     rgi, SLOT(modelChanged()));

    QObject::connect(this, SIGNAL(changed()),
                     isgi, SLOT(modelChanged()));

    QObject::connect(this, SIGNAL(changed()),
                     plgi, SLOT(modelChanged()));

  rgi->setVerticesPen(QPen(Qt::red, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
  rgi->setEdgesPen(QPen(Qt::gray, 0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
  scene.addItem(rgi);

  plgi->setEdgesPen(QPen(Qt::blue, 0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));

  // The navigation adds zooming and translation functionality to the
  // QGraphicsView
  this->addNavigation(this->graphicsView);

  this->setupStatusBar();
  this->setupOptionsMenu();
  this->addAboutDemo(":/cgal/help/about_Snap_rounding_2.html");
  this->addAboutCGAL();

  this->addRecentFiles(this->menuFile, this->actionQuit);
  connect(this, SIGNAL(openRecentFile(QString)),
	  this, SLOT(open(QString)));
}

void
MainWindow::deltaChanged(double d)
{
  if(delta == d){
    return;
  }
  delta = d;
  output.clear();
  CGAL::snap_rounding_2<Traits,std::list<Segment_2>::const_iterator,std::list<std::list<Point_2> > >(input.begin(), input.end(), output, delta, true, false);
  rgi->setDelta(delta, delta);
  Q_EMIT( changed());
}

void
MainWindow::processInput(CGAL::Object o)
{

  std::list<Point_2> points;
  if(CGAL::assign(points, o)){
    if(points.size() == 2) {
      input.push_back(Segment_2(points.front(), points.back()));
      output.clear();
      CGAL::snap_rounding_2<Traits,std::list<Segment_2>::const_iterator,std::list<std::list<Point_2> > >(input.begin(), input.end(), output, delta, true, false);
    }
    else {
      std::cerr << points.size() << std::endl;
    }
  }
  Q_EMIT( changed());
}

/*
 *  Qt Automatic Connections
 *  https://doc.qt.io/qt-5/designer-using-a-ui-file.html#automatic-connections
 *
 *  setupUi(this) generates connections to the slots named
 *  "on_<action_name>_<signal_name>"
 */

void
MainWindow::on_actionClear_triggered()
{
  input.clear();
  output.clear();
  Q_EMIT( changed());
}

void
MainWindow::on_actionShowGrid_toggled(bool checked)
{
  rgi->setVisible(checked);
  Q_EMIT( changed());
}

void
MainWindow::on_actionShowInput_toggled(bool checked)
{
  isgi->setVisible(checked);
  Q_EMIT( changed());
}

void
MainWindow::on_actionShowSnappedSegments_toggled(bool checked)
{
  plgi->setVisible(checked);
  Q_EMIT( changed());
}

void
MainWindow::on_actionLoadSegments_triggered()
{
  QString fileName = QFileDialog::getOpenFileName(this,
						  tr("Open segment file"),
                                                  ".",
                                                  tr("Edge files (*.edg);;"
                                                   #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500)
                                                     "WKT files (*.wkt *.WKT);;"
                                                   #endif
                                                     "All files (*)"));
  if(! fileName.isEmpty()){
    open(fileName);
  }
}

void
MainWindow::open(QString fileName)
{
  // wait cursor
  QApplication::setOverrideCursor(Qt::WaitCursor);
  std::ifstream ifs(qPrintable(fileName));
  if(fileName.endsWith(".wkt", Qt::CaseInsensitive))
  {
#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500)
    std::vector<std::vector<Point_2> > mls;
    CGAL::read_multi_linestring_WKT(ifs, mls);
    for(const std::vector<Point_2>& ls : mls)
    {
      if(ls.size() > 2)
        continue;
      Segment_2 seg(ls[0], ls[1]);
      input.push_back(seg);
    }
#endif
  }
  else {
    std::copy(std::istream_iterator<Segment_2>(ifs),
              std::istream_iterator<Segment_2>(),
              std::back_inserter(input));
  }
  output.clear();
  CGAL::snap_rounding_2<Traits,std::list<Segment_2>::const_iterator,std::list<std::list<Point_2> > >(input.begin(), input.end(), output, delta, true, false);
  ifs.close();
  // default cursor
  QApplication::restoreOverrideCursor();
  this->addToRecentFiles(fileName);
  on_actionRecenter_triggered();
  Q_EMIT( changed());
}

void
MainWindow::on_actionSaveSegments_triggered()
{
  QString fileName = QFileDialog::getSaveFileName(this,
						  tr("Save points"),
                                                  ".",
                                                  tr("Edge files (*.edg);;"
                                                   #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500)
                                                     "WKT files (*.wkt *.WKT);;"
                                                   #endif
                                                     "All files (*)"));
  if(! fileName.isEmpty()){
    std::ofstream ofs(qPrintable(fileName));
    ofs.precision(12);
    if(fileName.endsWith(".wkt", Qt::CaseInsensitive))
    {
#if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500)
      std::vector<std::vector<Point_2> >mls;
      for(const Segment_2& seg : input)
      {
        std::vector<Point_2> ls(2);
        ls[0] = seg.source();
        ls[1] = seg.target();
        mls.push_back(ls);
      }
      CGAL::write_multi_linestring_WKT(ofs, mls);
#endif
    }
    else
      std::copy(input.begin(), input.end(),  std::ostream_iterator<Segment_2>(ofs, "\n"));
  }

}

void
MainWindow::on_actionRecenter_triggered()
{
  this->graphicsView->setSceneRect(isgi->boundingRect());
  this->graphicsView->fitInView(isgi->boundingRect(), Qt::KeepAspectRatio);
}

#include "Snap_rounding_2.moc"
#include <CGAL/Qt/resources.h>

int main(int argc, char **argv)
{
  QApplication app(argc, argv);

  app.setOrganizationDomain("geometryfactory.com");
  app.setOrganizationName("GeometryFactory");
  app.setApplicationName("Snap_rounding_2 demo");

  // Import resources from libCGAL (Qt5).
  // See https://doc.qt.io/qt-5/qdir.html#Q_INIT_RESOURCE
  CGAL_QT_INIT_RESOURCES;
  Q_INIT_RESOURCE(Snap_rounding_2);

  MainWindow mainWindow;
  mainWindow.show();
  mainWindow.resize();
  return app.exec();
}


/**
 * @file tests/tree_test.cpp
 *
 * Tests for tree-building methods.
 *
 * mlpack is free software; you may redistribute it and/or modify it under the
 * terms of the 3-clause BSD license.  You should have received a copy of the
 * 3-clause BSD license along with mlpack.  If not, see
 * http://www.opensource.org/licenses/BSD-3-Clause for more information.
 */
#include <mlpack/core.hpp>
#include <mlpack/core/tree/bounds.hpp>
#include <mlpack/core/tree/binary_space_tree.hpp>
#include <mlpack/core/metrics/lmetric.hpp>
#include <mlpack/core/metrics/mahalanobis_distance.hpp>
#include <mlpack/core/tree/cover_tree/cover_tree.hpp>
#include <mlpack/core/tree/rectangle_tree.hpp>

#include <queue>
#include <stack>

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

using namespace mlpack;
using namespace mlpack::math;
using namespace mlpack::tree;
using namespace mlpack::metric;
using namespace mlpack::bound;

BOOST_AUTO_TEST_SUITE(TreeTest);

/**
 * Ensure that a bound, by default, is empty and has no dimensionality.
 */
BOOST_AUTO_TEST_CASE(HRectBoundEmptyConstructor)
{
  HRectBound<EuclideanDistance> b;

  BOOST_REQUIRE_EQUAL((int) b.Dim(), 0);
  BOOST_REQUIRE_EQUAL(b.MinWidth(), 0.0);
}

/**
 * Ensure that when we specify the dimensionality in the constructor, it is
 * correct, and the bounds are all the empty set.
 */
BOOST_AUTO_TEST_CASE(HRectBoundDimConstructor)
{
  HRectBound<EuclideanDistance> b(2); // We'll do this with 2 and 5 dimensions.

  BOOST_REQUIRE_EQUAL(b.Dim(), 2);
  BOOST_REQUIRE_SMALL(b[0].Width(), 1e-5);
  BOOST_REQUIRE_SMALL(b[1].Width(), 1e-5);

  b = HRectBound<EuclideanDistance>(5);

  BOOST_REQUIRE_EQUAL(b.Dim(), 5);
  BOOST_REQUIRE_SMALL(b[0].Width(), 1e-5);
  BOOST_REQUIRE_SMALL(b[1].Width(), 1e-5);
  BOOST_REQUIRE_SMALL(b[2].Width(), 1e-5);
  BOOST_REQUIRE_SMALL(b[3].Width(), 1e-5);
  BOOST_REQUIRE_SMALL(b[4].Width(), 1e-5);

  BOOST_REQUIRE_EQUAL(b.MinWidth(), 0.0);
}

/**
 * Test the copy constructor.
 */
BOOST_AUTO_TEST_CASE(HRectBoundCopyConstructor)
{
  HRectBound<EuclideanDistance> b(2);
  b[0] = Range(0.0, 2.0);
  b[1] = Range(2.0, 3.0);
  b.MinWidth() = 0.5;

  HRectBound<EuclideanDistance> c(b);

  BOOST_REQUIRE_EQUAL(c.Dim(), 2);
  BOOST_REQUIRE_SMALL(c[0].Lo(), 1e-5);
  BOOST_REQUIRE_CLOSE(c[0].Hi(), 2.0, 1e-5);
  BOOST_REQUIRE_CLOSE(c[1].Lo(), 2.0, 1e-5);
  BOOST_REQUIRE_CLOSE(c[1].Hi(), 3.0, 1e-5);
  BOOST_REQUIRE_CLOSE(c.MinWidth(), 0.5, 1e-5);
}

/**
 * Test the assignment operator.
 */
BOOST_AUTO_TEST_CASE(HRectBoundAssignmentOperator)
{
  HRectBound<EuclideanDistance> b(2);
  b[0] = Range(0.0, 2.0);
  b[1] = Range(2.0, 3.0);
  b.MinWidth() = 0.5;

  HRectBound<EuclideanDistance> c(4);

  c = b;

  BOOST_REQUIRE_EQUAL(c.Dim(), 2);
  BOOST_REQUIRE_SMALL(c[0].Lo(), 1e-5);
  BOOST_REQUIRE_CLOSE(c[0].Hi(), 2.0, 1e-5);
  BOOST_REQUIRE_CLOSE(c[1].Lo(), 2.0, 1e-5);
  BOOST_REQUIRE_CLOSE(c[1].Hi(), 3.0, 1e-5);
  BOOST_REQUIRE_CLOSE(c.MinWidth(), 0.5, 1e-5);
}

/**
 * Test that clearing the dimensions resets the bound to empty.
 */
BOOST_AUTO_TEST_CASE(HRectBoundClear)
{
  HRectBound<EuclideanDistance> b(2); // We'll do this with two dimensions only.

  b[0] = Range(0.0, 2.0);
  b[1] = Range(2.0, 4.0);
  b.MinWidth() = 1.0;

  // Now we just need to make sure that we clear the range.
  b.Clear();

  BOOST_REQUIRE_SMALL(b[0].Width(), 1e-5);
  BOOST_REQUIRE_SMALL(b[1].Width(), 1e-5);
  BOOST_REQUIRE_SMALL(b.MinWidth(), 1e-5);
}

BOOST_AUTO_TEST_CASE(HRectBoundMoveConstructor)
{
  HRectBound<EuclideanDistance> b(2);
  b[0] = Range(0.0, 2.0);
  b[1] = Range(2.0, 4.0);
  b.MinWidth() = 1.0;

  HRectBound<EuclideanDistance> b2(std::move(b));

  BOOST_REQUIRE_EQUAL(b.Dim(), 0);
  BOOST_REQUIRE_EQUAL(b2.Dim(), 2);

  BOOST_REQUIRE_EQUAL(b.MinWidth(), 0.0);
  BOOST_REQUIRE_EQUAL(b2.MinWidth(), 1.0);

  BOOST_REQUIRE_SMALL(b2[0].Lo(), 1e-5);
  BOOST_REQUIRE_CLOSE(b2[0].Hi(), 2.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b2[1].Lo(), 2.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b2[1].Hi(), 4.0, 1e-5);
}

/**
 * Ensure that we get the correct center for our bound.
 */
BOOST_AUTO_TEST_CASE(HRectBoundCenter)
{
  // Create a simple 3-dimensional bound.
  HRectBound<EuclideanDistance> b(3);

  b[0] = Range(0.0, 5.0);
  b[1] = Range(-2.0, -1.0);
  b[2] = Range(-10.0, 50.0);

  arma::vec center;

  b.Center(center);

  BOOST_REQUIRE_EQUAL(center.n_elem, 3);
  BOOST_REQUIRE_CLOSE(center[0], 2.5, 1e-5);
  BOOST_REQUIRE_CLOSE(center[1], -1.5, 1e-5);
  BOOST_REQUIRE_CLOSE(center[2], 20.0, 1e-5);
}

/**
 * Ensure the volume calculation is correct.
 */
BOOST_AUTO_TEST_CASE(HRectBoundVolume)
{
  // Create a simple 3-dimensional bound.
  HRectBound<EuclideanDistance> b(3);

  b[0] = Range(0.0, 5.0);
  b[1] = Range(-2.0, -1.0);
  b[2] = Range(-10.0, 50.0);

  BOOST_REQUIRE_CLOSE(b.Volume(), 300.0, 1e-5);
}

/**
 * Ensure that we calculate the correct minimum distance between a point and a
 * bound.
 */
BOOST_AUTO_TEST_CASE(HRectBoundMinDistancePoint)
{
  // We'll do the calculation in five dimensions, and we'll use three cases for
  // the point: point is outside the bound; point is on the edge of the bound;
  // point is inside the bound.  In the latter two cases, the distance should be
  // zero.
  HRectBound<EuclideanDistance> b(5);

  b[0] = Range(0.0, 2.0);
  b[1] = Range(1.0, 5.0);
  b[2] = Range(-2.0, 2.0);
  b[3] = Range(-5.0, -2.0);
  b[4] = Range(1.0, 2.0);

  arma::vec point = "-2.0 0.0 10.0 3.0 3.0";

  // This will be the Euclidean distance.
  BOOST_REQUIRE_CLOSE(b.MinDistance(point), sqrt(95.0), 1e-5);

  point = "2.0 5.0 2.0 -5.0 1.0";

  BOOST_REQUIRE_SMALL(b.MinDistance(point), 1e-5);

  point = "1.0 2.0 0.0 -2.0 1.5";

  BOOST_REQUIRE_SMALL(b.MinDistance(point), 1e-5);
}

/**
 * Ensure that we calculate the correct minimum distance between a bound and
 * another bound.
 */
BOOST_AUTO_TEST_CASE(HRectBoundMinDistanceBound)
{
  // We'll do the calculation in five dimensions, and we can use six cases.
  // The other bound is completely outside the bound; the other bound is on the
  // edge of the bound; the other bound partially overlaps the bound; the other
  // bound fully overlaps the bound; the other bound is entirely inside the
  // bound; the other bound entirely envelops the bound.
  HRectBound<EuclideanDistance> b(5);

  b[0] = Range(0.0, 2.0);
  b[1] = Range(1.0, 5.0);
  b[2] = Range(-2.0, 2.0);
  b[3] = Range(-5.0, -2.0);
  b[4] = Range(1.0, 2.0);

  HRectBound<EuclideanDistance> c(5);

  // The other bound is completely outside the bound.
  c[0] = Range(-5.0, -2.0);
  c[1] = Range(6.0, 7.0);
  c[2] = Range(-2.0, 2.0);
  c[3] = Range(2.0, 5.0);
  c[4] = Range(3.0, 4.0);

  BOOST_REQUIRE_CLOSE(b.MinDistance(c), sqrt(22.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MinDistance(b), sqrt(22.0), 1e-5);

  // The other bound is on the edge of the bound.
  c[0] = Range(-2.0, 0.0);
  c[1] = Range(0.0, 1.0);
  c[2] = Range(-3.0, -2.0);
  c[3] = Range(-10.0, -5.0);
  c[4] = Range(2.0, 3.0);

  BOOST_REQUIRE_SMALL(b.MinDistance(c), 1e-5);
  BOOST_REQUIRE_SMALL(c.MinDistance(b), 1e-5);

  // The other bound partially overlaps the bound.
  c[0] = Range(-2.0, 1.0);
  c[1] = Range(0.0, 2.0);
  c[2] = Range(-2.0, 2.0);
  c[3] = Range(-8.0, -4.0);
  c[4] = Range(0.0, 4.0);

  BOOST_REQUIRE_SMALL(b.MinDistance(c), 1e-5);
  BOOST_REQUIRE_SMALL(c.MinDistance(b), 1e-5);

  // The other bound fully overlaps the bound.
  BOOST_REQUIRE_SMALL(b.MinDistance(b), 1e-5);
  BOOST_REQUIRE_SMALL(c.MinDistance(c), 1e-5);

  // The other bound is entirely inside the bound / the other bound entirely
  // envelops the bound.
  c[0] = Range(-1.0, 3.0);
  c[1] = Range(0.0, 6.0);
  c[2] = Range(-3.0, 3.0);
  c[3] = Range(-7.0, 0.0);
  c[4] = Range(0.0, 5.0);

  BOOST_REQUIRE_SMALL(b.MinDistance(c), 1e-5);
  BOOST_REQUIRE_SMALL(c.MinDistance(b), 1e-5);

  // Now we must be sure that the minimum distance to itself is 0.
  BOOST_REQUIRE_SMALL(b.MinDistance(b), 1e-5);
  BOOST_REQUIRE_SMALL(c.MinDistance(c), 1e-5);
}

/**
 * Ensure that we calculate the correct maximum distance between a bound and a
 * point.  This uses the same test cases as the MinDistance test.
 */
BOOST_AUTO_TEST_CASE(HRectBoundMaxDistancePoint)
{
  // We'll do the calculation in five dimensions, and we'll use three cases for
  // the point: point is outside the bound; point is on the edge of the bound;
  // point is inside the bound.  In the latter two cases, the distance should be
  // zero.
  HRectBound<EuclideanDistance> b(5);

  b[0] = Range(0.0, 2.0);
  b[1] = Range(1.0, 5.0);
  b[2] = Range(-2.0, 2.0);
  b[3] = Range(-5.0, -2.0);
  b[4] = Range(1.0, 2.0);

  arma::vec point = "-2.0 0.0 10.0 3.0 3.0";

  // This will be the Euclidean distance.
  BOOST_REQUIRE_CLOSE(b.MaxDistance(point), sqrt(253.0), 1e-5);

  point = "2.0 5.0 2.0 -5.0 1.0";

  BOOST_REQUIRE_CLOSE(b.MaxDistance(point), sqrt(46.0), 1e-5);

  point = "1.0 2.0 0.0 -2.0 1.5";

  BOOST_REQUIRE_CLOSE(b.MaxDistance(point), sqrt(23.25), 1e-5);
}

/**
 * Ensure that we calculate the correct maximum distance between a bound and
 * another bound.  This uses the same test cases as the MinDistance test.
 */
BOOST_AUTO_TEST_CASE(HRectBoundMaxDistanceBound)
{
  // We'll do the calculation in five dimensions, and we can use six cases.
  // The other bound is completely outside the bound; the other bound is on the
  // edge of the bound; the other bound partially overlaps the bound; the other
  // bound fully overlaps the bound; the other bound is entirely inside the
  // bound; the other bound entirely envelops the bound.
  HRectBound<EuclideanDistance> b(5);

  b[0] = Range(0.0, 2.0);
  b[1] = Range(1.0, 5.0);
  b[2] = Range(-2.0, 2.0);
  b[3] = Range(-5.0, -2.0);
  b[4] = Range(1.0, 2.0);

  HRectBound<EuclideanDistance> c(5);

  // The other bound is completely outside the bound.
  c[0] = Range(-5.0, -2.0);
  c[1] = Range(6.0, 7.0);
  c[2] = Range(-2.0, 2.0);
  c[3] = Range(2.0, 5.0);
  c[4] = Range(3.0, 4.0);

  BOOST_REQUIRE_CLOSE(b.MaxDistance(c), sqrt(210.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MaxDistance(b), sqrt(210.0), 1e-5);

  // The other bound is on the edge of the bound.
  c[0] = Range(-2.0, 0.0);
  c[1] = Range(0.0, 1.0);
  c[2] = Range(-3.0, -2.0);
  c[3] = Range(-10.0, -5.0);
  c[4] = Range(2.0, 3.0);

  BOOST_REQUIRE_CLOSE(b.MaxDistance(c), sqrt(134.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MaxDistance(b), sqrt(134.0), 1e-5);

  // The other bound partially overlaps the bound.
  c[0] = Range(-2.0, 1.0);
  c[1] = Range(0.0, 2.0);
  c[2] = Range(-2.0, 2.0);
  c[3] = Range(-8.0, -4.0);
  c[4] = Range(0.0, 4.0);

  BOOST_REQUIRE_CLOSE(b.MaxDistance(c), sqrt(102.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MaxDistance(b), sqrt(102.0), 1e-5);

  // The other bound fully overlaps the bound.
  BOOST_REQUIRE_CLOSE(b.MaxDistance(b), sqrt(46.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MaxDistance(c), sqrt(61.0), 1e-5);

  // The other bound is entirely inside the bound / the other bound entirely
  // envelops the bound.
  c[0] = Range(-1.0, 3.0);
  c[1] = Range(0.0, 6.0);
  c[2] = Range(-3.0, 3.0);
  c[3] = Range(-7.0, 0.0);
  c[4] = Range(0.0, 5.0);

  BOOST_REQUIRE_CLOSE(b.MaxDistance(c), sqrt(100.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MaxDistance(b), sqrt(100.0), 1e-5);

  // Identical bounds.  This will be the sum of the squared widths in each
  // dimension.
  BOOST_REQUIRE_CLOSE(b.MaxDistance(b), sqrt(46.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MaxDistance(c), sqrt(162.0), 1e-5);

  // One last additional case.  If the bound encloses only one point, the
  // maximum distance between it and itself is 0.
  HRectBound<EuclideanDistance> d(2);

  d[0] = Range(2.0, 2.0);
  d[1] = Range(3.0, 3.0);

  BOOST_REQUIRE_SMALL(d.MaxDistance(d), 1e-5);
}

/**
 * Ensure that the ranges returned by RangeDistance() are equal to the minimum
 * and maximum distance.  We will perform this test by creating random bounds
 * and comparing the behavior to MinDistance() and MaxDistance() -- so this test
 * is assuming that those passed and operate correctly.
 */
BOOST_AUTO_TEST_CASE(HRectBoundRangeDistanceBound)
{
  for (int i = 0; i < 50; ++i)
  {
    size_t dim = math::RandInt(20);

    HRectBound<EuclideanDistance> a(dim);
    HRectBound<EuclideanDistance> b(dim);

    // We will set the low randomly and the width randomly for each dimension of
    // each bound.
    arma::vec loA(dim);
    arma::vec widthA(dim);

    loA.randu();
    widthA.randu();

    arma::vec lo_b(dim);
    arma::vec width_b(dim);

    lo_b.randu();
    width_b.randu();

    for (size_t j = 0; j < dim; ++j)
    {
      a[j] = Range(loA[j], loA[j] + widthA[j]);
      b[j] = Range(lo_b[j], lo_b[j] + width_b[j]);
    }

    // Now ensure that MinDistance and MaxDistance report the same.
    Range r = a.RangeDistance(b);
    Range s = b.RangeDistance(a);

    BOOST_REQUIRE_CLOSE(r.Lo(), s.Lo(), 1e-5);
    BOOST_REQUIRE_CLOSE(r.Hi(), s.Hi(), 1e-5);

    BOOST_REQUIRE_CLOSE(r.Lo(), a.MinDistance(b), 1e-5);
    BOOST_REQUIRE_CLOSE(r.Hi(), a.MaxDistance(b), 1e-5);

    BOOST_REQUIRE_CLOSE(s.Lo(), b.MinDistance(a), 1e-5);
    BOOST_REQUIRE_CLOSE(s.Hi(), b.MaxDistance(a), 1e-5);
  }
}

/**
 * Ensure that the ranges returned by RangeDistance() are equal to the minimum
 * and maximum distance.  We will perform this test by creating random bounds
 * and comparing the bheavior to MinDistance() and MaxDistance() -- so this test
 * is assuming that those passed and operate correctly.  This is for the
 * bound-to-point case.
 */
BOOST_AUTO_TEST_CASE(HRectBoundRangeDistancePoint)
{
  for (int i = 0; i < 20; ++i)
  {
    size_t dim = math::RandInt(20);

    HRectBound<EuclideanDistance> a(dim);

    // We will set the low randomly and the width randomly for each dimension of
    // each bound.
    arma::vec loA(dim);
    arma::vec widthA(dim);

    loA.randu();
    widthA.randu();

    for (size_t j = 0; j < dim; ++j)
      a[j] = Range(loA[j], loA[j] + widthA[j]);

    // Now run the test on a few points.
    for (int j = 0; j < 10; ++j)
    {
      arma::vec point(dim);

      point.randu();

      Range r = a.RangeDistance(point);

      BOOST_REQUIRE_CLOSE(r.Lo(), a.MinDistance(point), 1e-5);
      BOOST_REQUIRE_CLOSE(r.Hi(), a.MaxDistance(point), 1e-5);
    }
  }
}

/**
 * Test that we can expand the bound to include a new point.
 */
BOOST_AUTO_TEST_CASE(HRectBoundOrOperatorPoint)
{
  // Because this should be independent in each dimension, we can essentially
  // run five test cases at once.
  HRectBound<EuclideanDistance> b(5);

  b[0] = Range(1.0, 3.0);
  b[1] = Range(2.0, 4.0);
  b[2] = Range(-2.0, -1.0);
  b[3] = Range(0.0, 0.0);
  b[4] = Range(); // Empty range.
  b.MinWidth() = 0.0;

  arma::vec point = "2.0 4.0 2.0 -1.0 6.0";

  b |= point;

  BOOST_REQUIRE_CLOSE(b[0].Lo(), 1.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[0].Hi(), 3.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[1].Lo(), 2.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[1].Hi(), 4.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[2].Lo(), -2.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[2].Hi(), 2.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[3].Lo(), -1.0, 1e-5);
  BOOST_REQUIRE_SMALL(b[3].Hi(), 1e-5);
  BOOST_REQUIRE_CLOSE(b[4].Lo(), 6.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[4].Hi(), 6.0, 1e-5);
  BOOST_REQUIRE_SMALL(b.MinWidth(), 1e-5);
}

/**
 * Test that we can expand the bound to include another bound.
 */
BOOST_AUTO_TEST_CASE(HRectBoundOrOperatorBound)
{
  // Because this should be independent in each dimension, we can run many tests
  // at once.
  HRectBound<EuclideanDistance> b(8);

  b[0] = Range(1.0, 3.0);
  b[1] = Range(2.0, 4.0);
  b[2] = Range(-2.0, -1.0);
  b[3] = Range(4.0, 5.0);
  b[4] = Range(2.0, 4.0);
  b[5] = Range(0.0, 0.0);
  b[6] = Range();
  b[7] = Range(1.0, 3.0);

  HRectBound<EuclideanDistance> c(8);

  c[0] = Range(-3.0, -1.0); // Entirely less than the other bound.
  c[1] = Range(0.0, 2.0); // Touching edges.
  c[2] = Range(-3.0, -1.5); // Partially overlapping.
  c[3] = Range(4.0, 5.0); // Identical.
  c[4] = Range(1.0, 5.0); // Entirely enclosing.
  c[5] = Range(2.0, 2.0); // A single point.
  c[6] = Range(1.0, 3.0);
  c[7] = Range(); // Empty set.

  HRectBound<EuclideanDistance> d = c;

  b |= c;
  d |= b;

  BOOST_REQUIRE_CLOSE(b[0].Lo(), -3.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[0].Hi(), 3.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[0].Lo(), -3.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[0].Hi(), 3.0, 1e-5);

  BOOST_REQUIRE_CLOSE(b[1].Lo(), 0.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[1].Hi(), 4.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[1].Lo(), 0.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[1].Hi(), 4.0, 1e-5);

  BOOST_REQUIRE_CLOSE(b[2].Lo(), -3.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[2].Hi(), -1.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[2].Lo(), -3.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[2].Hi(), -1.0, 1e-5);

  BOOST_REQUIRE_CLOSE(b[3].Lo(), 4.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[3].Hi(), 5.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[3].Lo(), 4.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[3].Hi(), 5.0, 1e-5);

  BOOST_REQUIRE_CLOSE(b[4].Lo(), 1.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[4].Hi(), 5.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[4].Lo(), 1.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[4].Hi(), 5.0, 1e-5);

  BOOST_REQUIRE_SMALL(b[5].Lo(), 1e-5);
  BOOST_REQUIRE_CLOSE(b[5].Hi(), 2.0, 1e-5);
  BOOST_REQUIRE_SMALL(d[5].Lo(), 1e-5);
  BOOST_REQUIRE_CLOSE(d[5].Hi(), 2.0, 1e-5);

  BOOST_REQUIRE_CLOSE(b[6].Lo(), 1.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[6].Hi(), 3.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[6].Lo(), 1.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[6].Hi(), 3.0, 1e-5);

  BOOST_REQUIRE_CLOSE(b[7].Lo(), 1.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b[7].Hi(), 3.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[7].Lo(), 1.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d[7].Hi(), 3.0, 1e-5);

  BOOST_REQUIRE_CLOSE(b.MinWidth(), 1.0, 1e-5);
  BOOST_REQUIRE_CLOSE(d.MinWidth(), 1.0, 1e-5);
}

/**
 * Test that the Contains() function correctly figures out whether or not a
 * point is in a bound.
 */
BOOST_AUTO_TEST_CASE(HRectBoundContains)
{
  // We can test a couple different points: completely outside the bound,
  // adjacent in one dimension to the bound, adjacent in all dimensions to the
  // bound, and inside the bound.
  HRectBound<EuclideanDistance> b(3);

  b[0] = Range(0.0, 2.0);
  b[1] = Range(0.0, 2.0);
  b[2] = Range(0.0, 2.0);

  // Completely outside the range.
  arma::vec point = "-1.0 4.0 4.0";
  BOOST_REQUIRE(!b.Contains(point));

  // Completely outside, but one dimension is in the range.
  point = "-1.0 4.0 1.0";
  BOOST_REQUIRE(!b.Contains(point));

  // Outside, but one dimension is on the edge.
  point = "-1.0 0.0 3.0";
  BOOST_REQUIRE(!b.Contains(point));

  // Two dimensions are on the edge, but one is outside.
  point = "0.0 0.0 3.0";
  BOOST_REQUIRE(!b.Contains(point));

  // Completely on the edge (should be contained).
  point = "0.0 0.0 0.0";
  BOOST_REQUIRE(b.Contains(point));

  // Inside the range.
  point = "0.3 1.0 0.4";
  BOOST_REQUIRE(b.Contains(point));
}

BOOST_AUTO_TEST_CASE(TestBallBound)
{
  BallBound<> b1;
  BallBound<> b2;

  // Create two balls with a center distance of 1 from each other.
  // Give the first one a radius of 0.3 and the second a radius of 0.4.
  b1.Center().set_size(3);
  b1.Center()[0] = 1;
  b1.Center()[1] = 2;
  b1.Center()[2] = 3;
  b1.Radius() = 0.3;

  b2.Center().set_size(3);
  b2.Center()[0] = 1;
  b2.Center()[1] = 2;
  b2.Center()[2] = 4;
  b2.Radius() = 0.4;

  BOOST_REQUIRE_CLOSE(b1.MinDistance(b2), 1-0.3-0.4, 1e-5);
  BOOST_REQUIRE_CLOSE(b1.RangeDistance(b2).Hi(), 1+0.3+0.4, 1e-5);
  BOOST_REQUIRE_CLOSE(b1.RangeDistance(b2).Lo(), 1-0.3-0.4, 1e-5);
  BOOST_REQUIRE_CLOSE(b1.RangeDistance(b2).Hi(), 1+0.3+0.4, 1e-5);
  BOOST_REQUIRE_CLOSE(b1.RangeDistance(b2).Lo(), 1-0.3-0.4, 1e-5);

  BOOST_REQUIRE_CLOSE(b2.MinDistance(b1), 1-0.3-0.4, 1e-5);
  BOOST_REQUIRE_CLOSE(b2.MaxDistance(b1), 1+0.3+0.4, 1e-5);
  BOOST_REQUIRE_CLOSE(b2.RangeDistance(b1).Hi(), 1+0.3+0.4, 1e-5);
  BOOST_REQUIRE_CLOSE(b2.RangeDistance(b1).Lo(), 1-0.3-0.4, 1e-5);

  BOOST_REQUIRE(b1.Contains(b1.Center()));
  BOOST_REQUIRE(!b1.Contains(b2.Center()));

  BOOST_REQUIRE(!b2.Contains(b1.Center()));
  BOOST_REQUIRE(b2.Contains(b2.Center()));
  arma::vec b2point(3); // A point that's within the radius but not the center.
  b2point[0] = 1.1;
  b2point[1] = 2.1;
  b2point[2] = 4.1;

  BOOST_REQUIRE(b2.Contains(b2point));

  BOOST_REQUIRE_SMALL(b1.MinDistance(b1.Center()), 1e-5);
  BOOST_REQUIRE_CLOSE(b1.MinDistance(b2.Center()), 1 - 0.3, 1e-5);
  BOOST_REQUIRE_CLOSE(b2.MinDistance(b1.Center()), 1 - 0.4, 1e-5);
  BOOST_REQUIRE_CLOSE(b2.MaxDistance(b1.Center()), 1 + 0.4, 1e-5);
  BOOST_REQUIRE_CLOSE(b1.MaxDistance(b2.Center()), 1 + 0.3, 1e-5);
}

BOOST_AUTO_TEST_CASE(BallBoundMoveConstructor)
{
  BallBound<> b1(2.0, arma::vec("2 1 1"));
  BallBound<> b2(std::move(b1));

  BOOST_REQUIRE_EQUAL(b2.Dim(), 3);
  BOOST_REQUIRE_EQUAL(b1.Dim(), 0);

  BOOST_REQUIRE_CLOSE(b2.Center()[0], 2.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b2.Center()[1], 1.0, 1e-5);
  BOOST_REQUIRE_CLOSE(b2.Center()[2], 1.0, 1e-5);

  BOOST_REQUIRE_CLOSE(b2.MinWidth(), 4.0, 1e-5);
  BOOST_REQUIRE_SMALL(b1.MinWidth(), 1e-5);
}

/**
 * Ensure that we calculate the correct minimum distance between a point and a
 * bound.
 */
BOOST_AUTO_TEST_CASE(HRectBoundRootMinDistancePoint)
{
  // We'll do the calculation in five dimensions, and we'll use three cases for
  // the point: point is outside the bound; point is on the edge of the bound;
  // point is inside the bound.  In the latter two cases, the distance should be
  // zero.
  HRectBound<EuclideanDistance> b(5);

  b[0] = Range(0.0, 2.0);
  b[1] = Range(1.0, 5.0);
  b[2] = Range(-2.0, 2.0);
  b[3] = Range(-5.0, -2.0);
  b[4] = Range(1.0, 2.0);

  arma::vec point = "-2.0 0.0 10.0 3.0 3.0";

  // This will be the Euclidean distance.
  BOOST_REQUIRE_CLOSE(b.MinDistance(point), sqrt(95.0), 1e-5);

  point = "2.0 5.0 2.0 -5.0 1.0";

  BOOST_REQUIRE_SMALL(b.MinDistance(point), 1e-5);

  point = "1.0 2.0 0.0 -2.0 1.5";

  BOOST_REQUIRE_SMALL(b.MinDistance(point), 1e-5);
}

/**
 * Ensure that we calculate the correct minimum distance between a bound and
 * another bound.
 */
BOOST_AUTO_TEST_CASE(HRectBoundRootMinDistanceBound)
{
  // We'll do the calculation in five dimensions, and we can use six cases.
  // The other bound is completely outside the bound; the other bound is on the
  // edge of the bound; the other bound partially overlaps the bound; the other
  // bound fully overlaps the bound; the other bound is entirely inside the
  // bound; the other bound entirely envelops the bound.
  HRectBound<EuclideanDistance> b(5);

  b[0] = Range(0.0, 2.0);
  b[1] = Range(1.0, 5.0);
  b[2] = Range(-2.0, 2.0);
  b[3] = Range(-5.0, -2.0);
  b[4] = Range(1.0, 2.0);

  HRectBound<EuclideanDistance> c(5);

  // The other bound is completely outside the bound.
  c[0] = Range(-5.0, -2.0);
  c[1] = Range(6.0, 7.0);
  c[2] = Range(-2.0, 2.0);
  c[3] = Range(2.0, 5.0);
  c[4] = Range(3.0, 4.0);

  BOOST_REQUIRE_CLOSE(b.MinDistance(c), sqrt(22.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MinDistance(b), sqrt(22.0), 1e-5);

  // The other bound is on the edge of the bound.
  c[0] = Range(-2.0, 0.0);
  c[1] = Range(0.0, 1.0);
  c[2] = Range(-3.0, -2.0);
  c[3] = Range(-10.0, -5.0);
  c[4] = Range(2.0, 3.0);

  BOOST_REQUIRE_SMALL(b.MinDistance(c), 1e-5);
  BOOST_REQUIRE_SMALL(c.MinDistance(b), 1e-5);

  // The other bound partially overlaps the bound.
  c[0] = Range(-2.0, 1.0);
  c[1] = Range(0.0, 2.0);
  c[2] = Range(-2.0, 2.0);
  c[3] = Range(-8.0, -4.0);
  c[4] = Range(0.0, 4.0);

  BOOST_REQUIRE_SMALL(b.MinDistance(c), 1e-5);
  BOOST_REQUIRE_SMALL(c.MinDistance(b), 1e-5);

  // The other bound fully overlaps the bound.
  BOOST_REQUIRE_SMALL(b.MinDistance(b), 1e-5);
  BOOST_REQUIRE_SMALL(c.MinDistance(c), 1e-5);

  // The other bound is entirely inside the bound / the other bound entirely
  // envelops the bound.
  c[0] = Range(-1.0, 3.0);
  c[1] = Range(0.0, 6.0);
  c[2] = Range(-3.0, 3.0);
  c[3] = Range(-7.0, 0.0);
  c[4] = Range(0.0, 5.0);

  BOOST_REQUIRE_SMALL(b.MinDistance(c), 1e-5);
  BOOST_REQUIRE_SMALL(c.MinDistance(b), 1e-5);

  // Now we must be sure that the minimum distance to itself is 0.
  BOOST_REQUIRE_SMALL(b.MinDistance(b), 1e-5);
  BOOST_REQUIRE_SMALL(c.MinDistance(c), 1e-5);
}

/**
 * Ensure that we calculate the correct maximum distance between a bound and a
 * point.  This uses the same test cases as the MinDistance test.
 */
BOOST_AUTO_TEST_CASE(HRectBoundRootMaxDistancePoint)
{
  // We'll do the calculation in five dimensions, and we'll use three cases for
  // the point: point is outside the bound; point is on the edge of the bound;
  // point is inside the bound.  In the latter two cases, the distance should be
  // zero.
  HRectBound<EuclideanDistance> b(5);

  b[0] = Range(0.0, 2.0);
  b[1] = Range(1.0, 5.0);
  b[2] = Range(-2.0, 2.0);
  b[3] = Range(-5.0, -2.0);
  b[4] = Range(1.0, 2.0);

  arma::vec point = "-2.0 0.0 10.0 3.0 3.0";

  // This will be the Euclidean distance.
  BOOST_REQUIRE_CLOSE(b.MaxDistance(point), sqrt(253.0), 1e-5);

  point = "2.0 5.0 2.0 -5.0 1.0";

  BOOST_REQUIRE_CLOSE(b.MaxDistance(point), sqrt(46.0), 1e-5);

  point = "1.0 2.0 0.0 -2.0 1.5";

  BOOST_REQUIRE_CLOSE(b.MaxDistance(point), sqrt(23.25), 1e-5);
}

/**
 * Ensure that we calculate the correct maximum distance between a bound and
 * another bound.  This uses the same test cases as the MinDistance test.
 */
BOOST_AUTO_TEST_CASE(HRectBoundRootMaxDistanceBound)
{
  // We'll do the calculation in five dimensions, and we can use six cases.
  // The other bound is completely outside the bound; the other bound is on the
  // edge of the bound; the other bound partially overlaps the bound; the other
  // bound fully overlaps the bound; the other bound is entirely inside the
  // bound; the other bound entirely envelops the bound.
  HRectBound<EuclideanDistance> b(5);

  b[0] = Range(0.0, 2.0);
  b[1] = Range(1.0, 5.0);
  b[2] = Range(-2.0, 2.0);
  b[3] = Range(-5.0, -2.0);
  b[4] = Range(1.0, 2.0);

  HRectBound<EuclideanDistance> c(5);

  // The other bound is completely outside the bound.
  c[0] = Range(-5.0, -2.0);
  c[1] = Range(6.0, 7.0);
  c[2] = Range(-2.0, 2.0);
  c[3] = Range(2.0, 5.0);
  c[4] = Range(3.0, 4.0);

  BOOST_REQUIRE_CLOSE(b.MaxDistance(c), sqrt(210.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MaxDistance(b), sqrt(210.0), 1e-5);

  // The other bound is on the edge of the bound.
  c[0] = Range(-2.0, 0.0);
  c[1] = Range(0.0, 1.0);
  c[2] = Range(-3.0, -2.0);
  c[3] = Range(-10.0, -5.0);
  c[4] = Range(2.0, 3.0);

  BOOST_REQUIRE_CLOSE(b.MaxDistance(c), sqrt(134.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MaxDistance(b), sqrt(134.0), 1e-5);

  // The other bound partially overlaps the bound.
  c[0] = Range(-2.0, 1.0);
  c[1] = Range(0.0, 2.0);
  c[2] = Range(-2.0, 2.0);
  c[3] = Range(-8.0, -4.0);
  c[4] = Range(0.0, 4.0);

  BOOST_REQUIRE_CLOSE(b.MaxDistance(c), sqrt(102.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MaxDistance(b), sqrt(102.0), 1e-5);

  // The other bound fully overlaps the bound.
  BOOST_REQUIRE_CLOSE(b.MaxDistance(b), sqrt(46.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MaxDistance(c), sqrt(61.0), 1e-5);

  // The other bound is entirely inside the bound / the other bound entirely
  // envelops the bound.
  c[0] = Range(-1.0, 3.0);
  c[1] = Range(0.0, 6.0);
  c[2] = Range(-3.0, 3.0);
  c[3] = Range(-7.0, 0.0);
  c[4] = Range(0.0, 5.0);

  BOOST_REQUIRE_CLOSE(b.MaxDistance(c), sqrt(100.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MaxDistance(b), sqrt(100.0), 1e-5);

  // Identical bounds.  This will be the sum of the squared widths in each
  // dimension.
  BOOST_REQUIRE_CLOSE(b.MaxDistance(b), sqrt(46.0), 1e-5);
  BOOST_REQUIRE_CLOSE(c.MaxDistance(c), sqrt(162.0), 1e-5);

  // One last additional case.  If the bound encloses only one point, the
  // maximum distance between it and itself is 0.
  HRectBound<EuclideanDistance> d(2);

  d[0] = Range(2.0, 2.0);
  d[1] = Range(3.0, 3.0);

  BOOST_REQUIRE_SMALL(d.MaxDistance(d), 1e-5);
}

/**
 * Ensure that the ranges returned by RangeDistance() are equal to the minimum
 * and maximum distance.  We will perform this test by creating random bounds
 * and comparing the behavior to MinDistance() and MaxDistance() -- so this test
 * is assuming that those passed and operate correctly.
 */
BOOST_AUTO_TEST_CASE(HRectBoundRootRangeDistanceBound)
{
  for (int i = 0; i < 50; ++i)
  {
    size_t dim = math::RandInt(20);

    HRectBound<EuclideanDistance> a(dim);
    HRectBound<EuclideanDistance> b(dim);

    // We will set the low randomly and the width randomly for each dimension of
    // each bound.
    arma::vec loA(dim);
    arma::vec widthA(dim);

    loA.randu();
    widthA.randu();

    arma::vec lo_b(dim);
    arma::vec width_b(dim);

    lo_b.randu();
    width_b.randu();

    for (size_t j = 0; j < dim; ++j)
    {
      a[j] = Range(loA[j], loA[j] + widthA[j]);
      b[j] = Range(lo_b[j], lo_b[j] + width_b[j]);
    }

    // Now ensure that MinDistance and MaxDistance report the same.
    Range r = a.RangeDistance(b);
    Range s = b.RangeDistance(a);

    BOOST_REQUIRE_CLOSE(r.Lo(), s.Lo(), 1e-5);
    BOOST_REQUIRE_CLOSE(r.Hi(), s.Hi(), 1e-5);

    BOOST_REQUIRE_CLOSE(r.Lo(), a.MinDistance(b), 1e-5);
    BOOST_REQUIRE_CLOSE(r.Hi(), a.MaxDistance(b), 1e-5);

    BOOST_REQUIRE_CLOSE(s.Lo(), b.MinDistance(a), 1e-5);
    BOOST_REQUIRE_CLOSE(s.Hi(), b.MaxDistance(a), 1e-5);
  }
}

/**
 * Ensure that the ranges returned by RangeDistance() are equal to the minimum
 * and maximum distance.  We will perform this test by creating random bounds
 * and comparing the bheavior to MinDistance() and MaxDistance() -- so this test
 * is assuming that those passed and operate correctly.  This is for the
 * bound-to-point case.
 */
BOOST_AUTO_TEST_CASE(HRectBoundRootRangeDistancePoint)
{
  for (int i = 0; i < 20; ++i)
  {
    size_t dim = math::RandInt(20);

    HRectBound<EuclideanDistance> a(dim);

    // We will set the low randomly and the width randomly for each dimension of
    // each bound.
    arma::vec loA(dim);
    arma::vec widthA(dim);

    loA.randu();
    widthA.randu();

    for (size_t j = 0; j < dim; ++j)
      a[j] = Range(loA[j], loA[j] + widthA[j]);

    // Now run the test on a few points.
    for (int j = 0; j < 10; ++j)
    {
      arma::vec point(dim);

      point.randu();

      Range r = a.RangeDistance(point);

      BOOST_REQUIRE_CLOSE(r.Lo(), a.MinDistance(point), 1e-5);
      BOOST_REQUIRE_CLOSE(r.Hi(), a.MaxDistance(point), 1e-5);
    }
  }
}

/**
 * Ensure that HRectBound::Diameter() works properly.
 */
BOOST_AUTO_TEST_CASE(HRectBoundDiameter)
{
  HRectBound<LMetric<3, true>> b(4);
  b[0] = math::Range(0.0, 1.0);
  b[1] = math::Range(-1.0, 0.0);
  b[2] = math::Range(2.0, 3.0);
  b[3] = math::Range(7.0, 7.0);

  BOOST_REQUIRE_CLOSE(b.Diameter(), std::pow(3.0, 1.0 / 3.0), 1e-5);

  HRectBound<LMetric<2, false>> c(4);
  c[0] = math::Range(0.0, 1.0);
  c[1] = math::Range(-1.0, 0.0);
  c[2] = math::Range(2.0, 3.0);
  c[3] = math::Range(0.0, 0.0);

  BOOST_REQUIRE_CLOSE(c.Diameter(), 3.0, 1e-5);

  HRectBound<LMetric<5, true>> d(2);
  d[0] = math::Range(2.2, 2.2);
  d[1] = math::Range(1.0, 1.0);

  BOOST_REQUIRE_SMALL(d.Diameter(), 1e-5);
}

/**
 * It seems as though Bill has stumbled across a bug where
 * BinarySpaceTree<>::count() returns something different than
 * BinarySpaceTree<>::count_.  So, let's build a simple tree and make sure they
 * are the same.
 */
BOOST_AUTO_TEST_CASE(TreeCountMismatch)
{
  arma::mat dataset = "2.0 5.0 9.0 4.0 8.0 7.0;"
                      "3.0 4.0 6.0 7.0 1.0 2.0 ";

  // Leaf size of 1.
  KDTree<EuclideanDistance, EmptyStatistic, arma::mat> rootNode(dataset, 1);

  BOOST_REQUIRE(rootNode.Count() == 6);
  BOOST_REQUIRE(rootNode.Left()->Count() == 3);
  BOOST_REQUIRE(rootNode.Left()->Left()->Count() == 2);
  BOOST_REQUIRE(rootNode.Left()->Left()->Left()->Count() == 1);
  BOOST_REQUIRE(rootNode.Left()->Left()->Right()->Count() == 1);
  BOOST_REQUIRE(rootNode.Left()->Right()->Count() == 1);
  BOOST_REQUIRE(rootNode.Right()->Count() == 3);
  BOOST_REQUIRE(rootNode.Right()->Left()->Count() == 2);
  BOOST_REQUIRE(rootNode.Right()->Left()->Left()->Count() == 1);
  BOOST_REQUIRE(rootNode.Right()->Left()->Right()->Count() == 1);
  BOOST_REQUIRE(rootNode.Right()->Right()->Count() == 1);
}

BOOST_AUTO_TEST_CASE(CheckParents)
{
  arma::mat dataset = "2.0 5.0 9.0 4.0 8.0 7.0;"
                      "3.0 4.0 6.0 7.0 1.0 2.0 ";

  // Leaf size of 1.
  KDTree<EuclideanDistance, EmptyStatistic, arma::mat> rootNode(dataset, 1);

  BOOST_REQUIRE_EQUAL(rootNode.Parent(),
      (KDTree<EuclideanDistance, EmptyStatistic, arma::mat>*) NULL);
  BOOST_REQUIRE_EQUAL(&rootNode, rootNode.Left()->Parent());
  BOOST_REQUIRE_EQUAL(&rootNode, rootNode.Right()->Parent());
  BOOST_REQUIRE_EQUAL(rootNode.Left(), rootNode.Left()->Left()->Parent());
  BOOST_REQUIRE_EQUAL(rootNode.Left(), rootNode.Left()->Right()->Parent());
  BOOST_REQUIRE_EQUAL(rootNode.Left()->Left(),
      rootNode.Left()->Left()->Left()->Parent());
  BOOST_REQUIRE_EQUAL(rootNode.Left()->Left(),
      rootNode.Left()->Left()->Right()->Parent());
  BOOST_REQUIRE_EQUAL(rootNode.Right(), rootNode.Right()->Left()->Parent());
  BOOST_REQUIRE_EQUAL(rootNode.Right(), rootNode.Right()->Right()->Parent());
  BOOST_REQUIRE_EQUAL(rootNode.Right()->Left(),
      rootNode.Right()->Left()->Left()->Parent());
  BOOST_REQUIRE_EQUAL(rootNode.Right()->Left(),
      rootNode.Right()->Left()->Right()->Parent());
}

BOOST_AUTO_TEST_CASE(CheckDataset)
{
  arma::mat dataset = "2.0 5.0 9.0 4.0 8.0 7.0;"
                      "3.0 4.0 6.0 7.0 1.0 2.0 ";

  // Leaf size of 1.
  KDTree<EuclideanDistance, EmptyStatistic, arma::mat> rootNode(dataset, 1);

  arma::mat* rootDataset = &rootNode.Dataset();
  BOOST_REQUIRE_EQUAL(&rootNode.Left()->Dataset(), rootDataset);
  BOOST_REQUIRE_EQUAL(&rootNode.Right()->Dataset(), rootDataset);
  BOOST_REQUIRE_EQUAL(&rootNode.Left()->Left()->Dataset(), rootDataset);
  BOOST_REQUIRE_EQUAL(&rootNode.Left()->Right()->Dataset(), rootDataset);
  BOOST_REQUIRE_EQUAL(&rootNode.Right()->Left()->Dataset(), rootDataset);
  BOOST_REQUIRE_EQUAL(&rootNode.Right()->Right()->Dataset(), rootDataset);
  BOOST_REQUIRE_EQUAL(&rootNode.Left()->Left()->Left()->Dataset(),
      rootDataset);
  BOOST_REQUIRE_EQUAL(&rootNode.Left()->Left()->Right()->Dataset(),
      rootDataset);
  BOOST_REQUIRE_EQUAL(&rootNode.Right()->Left()->Left()->Dataset(),
      rootDataset);
  BOOST_REQUIRE_EQUAL(&rootNode.Right()->Left()->Right()->Dataset(),
      rootDataset);
}

// Ensure FurthestDescendantDistance() works.
BOOST_AUTO_TEST_CASE(FurthestDescendantDistanceTest)
{
  arma::mat dataset = "1; 3"; // One point.
  KDTree<EuclideanDistance, EmptyStatistic, arma::mat> rootNode(dataset, 1);

  BOOST_REQUIRE_SMALL(rootNode.FurthestDescendantDistance(), 1e-5);

  dataset = "1 -1; 1 -1"; // Square of size [2, 2].

  // Both points are contained in the one node.
  KDTree<EuclideanDistance, EmptyStatistic, arma::mat> twoPoint(dataset);
  BOOST_REQUIRE_CLOSE(twoPoint.FurthestDescendantDistance(), sqrt(2.0), 1e-5);
}

// Ensure that FurthestPointDistance() works.
BOOST_AUTO_TEST_CASE(FurthestPointDistanceTest)
{
  arma::mat dataset;
  dataset.randu(5, 100);

  typedef KDTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
  TreeType tree(dataset);

  // Now, check each node.
  std::queue<TreeType*> nodeQueue;
  nodeQueue.push(&tree);

  while (!nodeQueue.empty())
  {
    TreeType* node = nodeQueue.front();
    nodeQueue.pop();

    if (node->NumChildren() != 0)
      BOOST_REQUIRE_EQUAL(node->FurthestPointDistance(), 0.0);
    else
    {
      // Get center.
      arma::vec center;
      node->Center(center);

      double maxDist = 0.0;
      for (size_t i = 0; i < node->NumPoints(); ++i)
      {
        const double dist = metric::EuclideanDistance::Evaluate(center,
            dataset.col(node->Point(i)));
        if (dist > maxDist)
          maxDist = dist;
      }

      // We don't require an exact value because FurthestPointDistance() can
      // just bound the value instead of returning the exact value.
      BOOST_REQUIRE_LE(maxDist, node->FurthestPointDistance());

      if (node->Left())
        nodeQueue.push(node->Left());
      if (node->Right())
        nodeQueue.push(node->Right());
    }
  }
}

BOOST_AUTO_TEST_CASE(ParentDistanceTest)
{
  arma::mat dataset;
  dataset.randu(5, 500);

  typedef KDTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
  TreeType tree(dataset);

  // The root's parent distance should be 0 (although maybe it doesn't actually
  // matter; I just want to be sure it's not an uninitialized value, which this
  // test *sort* of checks).
  BOOST_REQUIRE_EQUAL(tree.ParentDistance(), 0.0);

  // Do a depth-first traversal and make sure the parent distance is the same as
  // we calculate.
  std::stack<TreeType*> nodeStack;
  nodeStack.push(&tree);

  while (!nodeStack.empty())
  {
    TreeType* node = nodeStack.top();
    nodeStack.pop();

    // If it's a leaf, nothing to check.
    if (node->NumChildren() == 0)
      continue;

    arma::vec center, leftCenter, rightCenter;
    node->Center(center);
    node->Left()->Center(leftCenter);
    node->Right()->Center(rightCenter);

    const double leftDistance = LMetric<2>::Evaluate(center, leftCenter);
    const double rightDistance = LMetric<2>::Evaluate(center, rightCenter);

    BOOST_REQUIRE_CLOSE(leftDistance, node->Left()->ParentDistance(), 1e-5);
    BOOST_REQUIRE_CLOSE(rightDistance, node->Right()->ParentDistance(), 1e-5);

    nodeStack.push(node->Left());
    nodeStack.push(node->Right());
  }
}

BOOST_AUTO_TEST_CASE(ParentDistanceTestWithMapping)
{
  arma::mat dataset;
  dataset.randu(5, 500);
  std::vector<size_t> oldFromNew;

  typedef KDTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
  TreeType tree(dataset, oldFromNew);

  // The root's parent distance should be 0 (although maybe it doesn't actually
  // matter; I just want to be sure it's not an uninitialized value, which this
  // test *sort* of checks).
  BOOST_REQUIRE_EQUAL(tree.ParentDistance(), 0.0);

  // Do a depth-first traversal and make sure the parent distance is the same as
  // we calculate.
  std::stack<TreeType*> nodeStack;
  nodeStack.push(&tree);

  while (!nodeStack.empty())
  {
    TreeType* node = nodeStack.top();
    nodeStack.pop();

    // If it's a leaf, nothing to check.
    if (node->NumChildren() == 0)
      continue;

    arma::vec center, leftCenter, rightCenter;
    node->Center(center);
    node->Left()->Center(leftCenter);
    node->Right()->Center(rightCenter);

    const double leftDistance = LMetric<2>::Evaluate(center, leftCenter);
    const double rightDistance = LMetric<2>::Evaluate(center, rightCenter);

    BOOST_REQUIRE_CLOSE(leftDistance, node->Left()->ParentDistance(), 1e-5);
    BOOST_REQUIRE_CLOSE(rightDistance, node->Right()->ParentDistance(), 1e-5);

    nodeStack.push(node->Left());
    nodeStack.push(node->Right());
  }
}

// Forward declaration of methods we need for the next test.
template<typename TreeType>
bool CheckPointBounds(TreeType& node);

template<typename TreeType>
void GenerateVectorOfTree(TreeType* node,
                          size_t depth,
                          std::vector<TreeType*>& v);

/**
 * Exhaustive kd-tree test based on #125.
 *
 * - Generate a random dataset of a random size.
 * - Build a tree on that dataset.
 * - Ensure all the permutation indices map back to the correct points.
 * - Verify that each point is contained inside all of the bounds of its parent
 *     nodes.
 * - Verify that each bound at a particular level of the tree does not overlap
 *     with any other bounds at that level.
 *
 * Then, we do that whole process a handful of times.
 */
BOOST_AUTO_TEST_CASE(KdTreeTest)
{
  typedef KDTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;

  size_t maxRuns = 10; // Ten total tests.
  size_t pointIncrements = 1000; // Range is from 2000 points to 11000.

  // We use the default leaf size of 20.
  for (size_t run = 0; run < maxRuns; run++)
  {
    size_t dimensions = run + 2;
    size_t maxPoints = (run + 1) * pointIncrements;

    size_t size = maxPoints;
    arma::mat dataset = arma::mat(dimensions, size);

    // Mappings for post-sort verification of data.
    std::vector<size_t> newToOld;
    std::vector<size_t> oldToNew;

    // Generate data.
    dataset.randu();

    // Build the tree itself.
    TreeType root(dataset, newToOld, oldToNew);
    const arma::mat& treeset = root.Dataset();

    // Ensure the size of the tree is correct.
    BOOST_REQUIRE_EQUAL(root.Count(), size);

    // Check the forward and backward mappings for correctness.
    for (size_t i = 0; i < size; ++i)
    {
      for (size_t j = 0; j < dimensions; ++j)
      {
        BOOST_REQUIRE_EQUAL(treeset(j, i), dataset(j, newToOld[i]));
        BOOST_REQUIRE_EQUAL(treeset(j, oldToNew[i]), dataset(j, i));
      }
    }

    // Now check that each point is contained inside of all bounds above it.
    CheckPointBounds(root);

    // Now check that no peers overlap.
    std::vector<TreeType*> v;
    GenerateVectorOfTree(&root, 1, v);

    // Start with the first pair.
    size_t depth = 2;
    // Compare each peer against every other peer.
    while (depth < v.size())
    {
      for (size_t i = depth; i < 2 * depth && i < v.size(); ++i)
        for (size_t j = i + 1; j < 2 * depth && j < v.size(); ++j)
          if (v[i] != NULL && v[j] != NULL)
            BOOST_REQUIRE(!v[i]->Bound().Contains(v[j]->Bound()));

      depth *= 2;
    }
  }

  arma::mat dataset(25, 1000);
  for (size_t col = 0; col < dataset.n_cols; ++col)
    for (size_t row = 0; row < dataset.n_rows; ++row)
      dataset(row, col) = row + col;

  TreeType root(dataset);
}

BOOST_AUTO_TEST_CASE(MaxRPTreeTest)
{
  typedef MaxRPTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;

  size_t maxRuns = 10; // Ten total tests.
  size_t pointIncrements = 1000; // Range is from 2000 points to 11000.

  // We use the default leaf size of 20.
  for (size_t run = 0; run < maxRuns; run++)
  {
    size_t dimensions = run + 2;
    size_t maxPoints = (run + 1) * pointIncrements;

    size_t size = maxPoints;
    arma::mat dataset = arma::mat(dimensions, size);

    // Mappings for post-sort verification of data.
    std::vector<size_t> newToOld;
    std::vector<size_t> oldToNew;

    // Generate data.
    dataset.randu();

    // Build the tree itself.
    TreeType root(dataset, newToOld, oldToNew);
    const arma::mat& treeset = root.Dataset();

    // Ensure the size of the tree is correct.
    BOOST_REQUIRE_EQUAL(root.Count(), size);

    // Check the forward and backward mappings for correctness.
    for (size_t i = 0; i < size; ++i)
    {
      for (size_t j = 0; j < dimensions; ++j)
      {
        BOOST_REQUIRE_EQUAL(treeset(j, i), dataset(j, newToOld[i]));
        BOOST_REQUIRE_EQUAL(treeset(j, oldToNew[i]), dataset(j, i));
      }
    }
  }
}

template<typename TreeType>
bool CheckHyperplaneSplit(const TreeType& tree)
{
  typedef typename TreeType::ElemType ElemType;

  const typename TreeType::Mat& dataset = tree.Dataset();
  arma::Mat<typename TreeType::ElemType> mat(dataset.n_rows + 1,
      tree.Left()->NumDescendants() + tree.Right()->NumDescendants());

  // We will try to find a hyperplane that splits the node.
  // The hyperplane may be represented as
  // a_1 * x_1 + ... + a_n * x_n + a_{n + 1} = 0.
  // We have to solve the system of inequalities (mat^t) * x <= 0,
  // where x[0], ... , x[dataset.n_rows-1] are the components of the normal
  // to the hyperplane and x[dataset.n_rows] is the position of the hyperplane
  // i.e. x = (a_1, ... , a_{n + 1}).
  // Each column of the matrix consists of a point and 1.
  // In such a way, the inner product of a column and x is equal to the value
  // of the hyperplane expression.
  // The hyperplane splits the node if the expression takes on opposite
  // values on node's children.

  for (size_t i = 0; i < tree.Left()->NumDescendants(); ++i)
  {
    for (size_t k = 0; k < dataset.n_rows; ++k)
      mat(k, i) = - dataset(k, tree.Left()->Descendant(i));

    mat(dataset.n_rows, i) = -1;
  }

  for (size_t i = 0; i < tree.Right()->NumDescendants(); ++i)
  {
    for (size_t k = 0; k < dataset.n_rows; ++k)
      mat(k, i + tree.Left()->NumDescendants()) =
          dataset(k, tree.Right()->Descendant(i));

    mat(dataset.n_rows, i + tree.Left()->NumDescendants()) = 1;
  }

  arma::Col<ElemType> x(dataset.n_rows + 1);
  x.zeros();
  // Define an initial value.
  x[0] = 1.0;
  x[1] = -arma::mean(
      dataset.cols(tree.Begin(), tree.Begin() + tree.Count() - 1).row(0));

  const size_t numIters = 1000000;
  const ElemType delta = 1e-4;

  // We will solve the system using a simple gradient method.
  bool success = false;
  for (size_t it = 0; it < numIters; it++)
  {
    success = true;
    for (size_t k = 0; k < tree.Count(); ++k)
    {
      ElemType result = arma::dot(mat.col(k), x);
      if (result > 0)
      {
        x -= mat.col(k) * delta;
        success = false;
      }
    }

    // The norm of the direction shouldn't be equal to zero.
    if (arma::norm(x.rows(0, dataset.n_rows-1)) < 1e-8)
    {
      x[math::RandInt(0, dataset.n_rows)] = 1.0;
      success = false;
    }

    if (success)
      break;
  }

  return success;
}

template<typename TreeType>
void CheckMaxRPTreeSplit(const TreeType& tree)
{
  if (tree.IsLeaf())
    return;

  BOOST_REQUIRE_EQUAL(CheckHyperplaneSplit(tree), true);

  CheckMaxRPTreeSplit(*tree.Left());
  CheckMaxRPTreeSplit(*tree.Right());
}

BOOST_AUTO_TEST_CASE(MaxRPTreeSplitTest)
{
  typedef MaxRPTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
  arma::mat dataset;
  dataset.randu(8, 1000);
  TreeType root(dataset);

  CheckMaxRPTreeSplit(root);
}

BOOST_AUTO_TEST_CASE(RPTreeTest)
{
  typedef RPTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;

  size_t maxRuns = 10; // Ten total tests.
  size_t pointIncrements = 1000; // Range is from 2000 points to 11000.

  // We use the default leaf size of 20.
  for (size_t run = 0; run < maxRuns; run++)
  {
    size_t dimensions = run + 2;
    size_t maxPoints = (run + 1) * pointIncrements;

    size_t size = maxPoints;
    arma::mat dataset = arma::mat(dimensions, size);

    // Mappings for post-sort verification of data.
    std::vector<size_t> newToOld;
    std::vector<size_t> oldToNew;

    // Generate data.
    dataset.randu();

    // Build the tree itself.
    TreeType root(dataset, newToOld, oldToNew);
    const arma::mat& treeset = root.Dataset();

    // Ensure the size of the tree is correct.
    BOOST_REQUIRE_EQUAL(root.Count(), size);

    // Check the forward and backward mappings for correctness.
    for (size_t i = 0; i < size; ++i)
    {
      for (size_t j = 0; j < dimensions; ++j)
      {
        BOOST_REQUIRE_EQUAL(treeset(j, i), dataset(j, newToOld[i]));
        BOOST_REQUIRE_EQUAL(treeset(j, oldToNew[i]), dataset(j, i));
      }
    }
  }
}

template<typename TreeType, typename MetricType>
void CheckRPTreeSplit(const TreeType& tree)
{
  typedef typename TreeType::ElemType ElemType;
  if (tree.IsLeaf())
    return;

  if (!CheckHyperplaneSplit(tree))
  {
    // Check if that was mean split.
    arma::Col<ElemType> center;
    tree.Left()->Bound().Center(center);
    ElemType maxDist = 0;
    for (size_t k =0; k < tree.Left()->NumDescendants(); ++k)
    {
      ElemType dist = MetricType::Evaluate(center,
          tree.Dataset().col(tree.Left()->Descendant(k)));

      if (dist > maxDist)
        maxDist = dist;
    }

    for (size_t k =0; k < tree.Right()->NumDescendants(); ++k)
    {
      ElemType dist = MetricType::Evaluate(center,
          tree.Dataset().col(tree.Right()->Descendant(k)));

      BOOST_REQUIRE_LE(maxDist, dist *
          (1.0 + 10.0 * std::numeric_limits<ElemType>::epsilon()));
    }
  }

  CheckRPTreeSplit<TreeType, MetricType>(*tree.Left());
  CheckRPTreeSplit<TreeType, MetricType>(*tree.Right());
}

BOOST_AUTO_TEST_CASE(RPTreeSplitTest)
{
  typedef RPTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
  arma::mat dataset;
  dataset.randu(8, 1000);
  TreeType root(dataset);

  CheckRPTreeSplit<TreeType, EuclideanDistance>(root);
}

// Recursively checks that each node contains all points that it claims to have.
template<typename TreeType>
bool CheckPointBounds(TreeType& node)
{
  // Check that each point which this tree claims is actually inside the tree.
  for (size_t index = 0; index < node.NumDescendants(); index++)
    if (!node.Bound().Contains(node.Dataset().col(node.Descendant(index))))
      return false;

  bool result = true;
  for (size_t child = 0; child < node.NumChildren(); ++child)
    result &= CheckPointBounds(node.Child(child));
  return result;
}

/**
 * Exhaustive ball tree test based on #125.
 *
 * - Generate a random dataset of a random size.
 * - Build a tree on that dataset.
 * - Ensure all the permutation indices map back to the correct points.
 * - Verify that each point is contained inside all of the bounds of its parent
 *     nodes.
 *
 * Then, we do that whole process a handful of times.
 */
BOOST_AUTO_TEST_CASE(BallTreeTest)
{
  typedef BallTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;

  size_t maxRuns = 10; // Ten total tests.
  size_t pointIncrements = 1000; // Range is from 2000 points to 11000.

  // We use the default leaf size of 20.
  for (size_t run = 0; run < maxRuns; run++)
  {
    size_t dimensions = run + 2;
    size_t maxPoints = (run + 1) * pointIncrements;

    size_t size = maxPoints;
    arma::mat dataset = arma::mat(dimensions, size);
    arma::mat datacopy; // Used to test mappings.

    // Mappings for post-sort verification of data.
    std::vector<size_t> newToOld;
    std::vector<size_t> oldToNew;

    // Generate data.
    dataset.randu();

    // Build the tree itself.
    TreeType root(dataset, newToOld, oldToNew);
    const arma::mat& treeset = root.Dataset();

    // Ensure the size of the tree is correct.
    BOOST_REQUIRE_EQUAL(root.NumDescendants(), size);

    // Check the forward and backward mappings for correctness.
    for (size_t i = 0; i < size; ++i)
    {
      for (size_t j = 0; j < dimensions; ++j)
      {
        BOOST_REQUIRE_EQUAL(treeset(j, i), dataset(j, newToOld[i]));
        BOOST_REQUIRE_EQUAL(treeset(j, oldToNew[i]), dataset(j, i));
      }
    }

    // Now check that each point is contained inside of all bounds above it.
    CheckPointBounds(root);
  }
}

/**
 * Ensure that we can build a ball tree with a custom instantiated metric type.
 */
BOOST_AUTO_TEST_CASE(MahalanobisBallTreeTest)
{
  arma::mat dataset(10, 1000, arma::fill::randu);
  arma::mat cov = arma::eye<arma::mat>(10, 10);
  cov(2, 2) = 2.0; // Just so it's not completely the identity matrix.
  MahalanobisDistance<> m(std::move(cov));

  typedef BallTree<MahalanobisDistance<>, EmptyStatistic, arma::mat> TreeType;

  TreeType tree(dataset);

  // As long as it built successfully, I am okay with that.
  BOOST_REQUIRE_EQUAL(tree.NumDescendants(), 1000);

  // Also test when we give oldFromNew, since this uses a different code path.
  std::vector<size_t> oldFromNew;
  TreeType tree2(std::move(dataset), oldFromNew);

  BOOST_REQUIRE_EQUAL(tree.NumDescendants(), 1000);
}

template<typename TreeType>
void GenerateVectorOfTree(TreeType* node,
                          size_t depth,
                          std::vector<TreeType*>& v)
{
  if (node == NULL)
    return;

  if (depth >= v.size())
    v.resize(2 * depth + 1, NULL); // Resize to right size; fill with NULL.

  v[depth] = node;

  // Recurse to the left and right children.
  GenerateVectorOfTree(node->Left(), depth * 2, v);
  GenerateVectorOfTree(node->Right(), depth * 2 + 1, v);

  return;
}

/**
 * Exhaustive sparse kd-tree test based on #125.
 *
 * - Generate a random dataset of a random size.
 * - Build a tree on that dataset.
 * - Ensure all the permutation indices map back to the correct points.
 * - Verify that each point is contained inside all of the bounds of its parent
 *     nodes.
 * - Verify that each bound at a particular level of the tree does not overlap
 *     with any other bounds at that level.
 *
 * Then, we do that whole process a handful of times.
 */
BOOST_AUTO_TEST_CASE(ExhaustiveSparseKDTreeTest)
{
  typedef KDTree<EuclideanDistance, EmptyStatistic, arma::SpMat<double>>
      TreeType;

  size_t maxRuns = 2; // Two total tests.
  size_t pointIncrements = 200; // Range is from 200 points to 400.

  // We use the default leaf size of 20.
  for (size_t run = 0; run < maxRuns; run++)
  {
    size_t dimensions = run + 2;
    size_t maxPoints = (run + 1) * pointIncrements;

    size_t size = maxPoints;
    arma::SpMat<double> dataset = arma::SpMat<double>(dimensions, size);
    arma::SpMat<double> datacopy; // Used to test mappings.

    // Mappings for post-sort verification of data.
    std::vector<size_t> newToOld;
    std::vector<size_t> oldToNew;

    // Generate data.
    dataset.sprandu(dimensions, size, 0.1);
    datacopy = dataset; // Save a copy.

    // Build the tree itself.
    TreeType root(dataset, newToOld, oldToNew);
    const arma::sp_mat& treeset = root.Dataset();

    // Ensure the size of the tree is correct.
    BOOST_REQUIRE_EQUAL(root.Count(), size);

    // Check the forward and backward mappings for correctness.
    for (size_t i = 0; i < size; ++i)
    {
      for (size_t j = 0; j < dimensions; ++j)
      {
        BOOST_REQUIRE_EQUAL(treeset(j, i), dataset(j, newToOld[i]));
        BOOST_REQUIRE_EQUAL(treeset(j, oldToNew[i]), dataset(j, i));
      }
    }

    // Now check that each point is contained inside of all bounds above it.
    CheckPointBounds(root);

    // Now check that no peers overlap.
    std::vector<TreeType*> v;
    GenerateVectorOfTree(&root, 1, v);

    // Start with the first pair.
    size_t depth = 2;
    // Compare each peer against every other peer.
    while (depth < v.size())
    {
      for (size_t i = depth; i < 2 * depth && i < v.size(); ++i)
        for (size_t j = i + 1; j < 2 * depth && j < v.size(); ++j)
          if (v[i] != NULL && v[j] != NULL)
            BOOST_REQUIRE(!v[i]->Bound().Contains(v[j]->Bound()));

      depth *= 2;
    }
  }

  arma::SpMat<double> dataset(25, 1000);
  for (size_t col = 0; col < dataset.n_cols; ++col)
    for (size_t row = 0; row < dataset.n_rows; ++row)
      dataset(row, col) = row + col;

  TreeType root(dataset);
}

BOOST_AUTO_TEST_CASE(BinarySpaceTreeMoveConstructorTest)
{
  arma::mat dataset(5, 1000);
  dataset.randu();

  BinarySpaceTree<EuclideanDistance> tree(dataset);
  BinarySpaceTree<EuclideanDistance> tree2(std::move(tree));

  BOOST_REQUIRE_EQUAL(tree.NumChildren(), 0);
  BOOST_REQUIRE_EQUAL(tree2.NumChildren(), 2);
}

template<typename TreeType>
void RecurseTreeCountLeaves(const TreeType& node, arma::vec& counts)
{
  for (size_t i = 0; i < node.NumChildren(); ++i)
  {
    if (node.Child(i).NumChildren() == 0)
      counts[node.Child(i).Point()]++;
    else
      RecurseTreeCountLeaves<TreeType>(node.Child(i), counts);
  }
}

template<typename TreeType>
void CheckSelfChild(const TreeType& node)
{
  if (node.NumChildren() == 0)
    return; // No self-child applicable here.

  bool found = false;
  for (size_t i = 0; i < node.NumChildren(); ++i)
  {
    if (node.Child(i).Point() == node.Point())
      found = true;

    // Recursively check the children.
    CheckSelfChild(node.Child(i));
  }

  // Ensure this has its own self-child.
  BOOST_REQUIRE_EQUAL(found, true);
}

template<typename TreeType, typename MetricType>
void CheckCovering(const TreeType& node)
{
  // Return if a leaf.  No checking necessary.
  if (node.NumChildren() == 0)
    return;

  const typename TreeType::Mat& dataset = node.Dataset();
  const size_t nodePoint = node.Point();

  // To ensure that this node satisfies the covering principle, we must ensure
  // that the distance to each child is less than pow(base, scale).
  double maxDistance = pow(node.Base(), node.Scale());
  for (size_t i = 0; i < node.NumChildren(); ++i)
  {
    const size_t childPoint = node.Child(i).Point();

    double distance = MetricType::Evaluate(dataset.col(nodePoint),
        dataset.col(childPoint));

    BOOST_REQUIRE_LE(distance, maxDistance);

    // Check the child.
    CheckCovering<TreeType, MetricType>(node.Child(i));
  }
}

/**
 * Create a simple cover tree and then make sure it is valid.
 */
BOOST_AUTO_TEST_CASE(SimpleCoverTreeConstructionTest)
{
  // 20-point dataset.
  arma::mat data = arma::trans(arma::mat("0.0 0.0;"
                                         "1.0 0.0;"
                                         "0.5 0.5;"
                                         "2.0 2.0;"
                                         "-1.0 2.0;"
                                         "3.0 0.0;"
                                         "1.5 5.5;"
                                         "-2.0 -2.0;"
                                         "-1.5 1.5;"
                                         "0.0 4.0;"
                                         "2.0 1.0;"
                                         "2.0 1.2;"
                                         "-3.0 -2.5;"
                                         "-5.0 -5.0;"
                                         "3.5 1.5;"
                                         "2.0 2.5;"
                                         "-1.0 -1.0;"
                                         "-3.5 1.5;"
                                         "3.5 -1.5;"
                                         "2.0 1.0;"));

  // The root point will be the first point, (0, 0).
  typedef StandardCoverTree<EuclideanDistance, EmptyStatistic, arma::mat>
      TreeType;
  TreeType tree(data); // Expansion constant of 2.0.

  // The furthest point from the root will be (-5, -5), with a distance of
  // of sqrt(50).  This means the scale of the root node should be 3 (because
  // 2^3 = 8).
  BOOST_REQUIRE_EQUAL(tree.Scale(), 3);

  // Now loop through the tree and ensure that each leaf is only created once.
  arma::vec counts;
  counts.zeros(20);
  RecurseTreeCountLeaves(tree, counts);

  // Each point should only have one leaf node representing it.
  for (size_t i = 0; i < 20; ++i)
    BOOST_REQUIRE_EQUAL(counts[i], 1);

  // Each non-leaf should have a self-child.
  CheckSelfChild<TreeType>(tree);

  // Each node must satisfy the covering principle (its children must be less
  // than or equal to a certain distance apart).
  CheckCovering<TreeType, LMetric<2, true>>(tree);

  // There's no need to check the separation invariant because that is relaxed
  // in our implementation.
}

/**
 * Create a large cover tree and make sure it's accurate.
 */
BOOST_AUTO_TEST_CASE(CoverTreeConstructionTest)
{
  arma::mat dataset;
  // 50-dimensional, 1000 point.
  dataset.randu(50, 1000);

  typedef StandardCoverTree<EuclideanDistance, EmptyStatistic, arma::mat>
      TreeType;
  TreeType tree(dataset);

  // Ensure each leaf is only created once.
  arma::vec counts;
  counts.zeros(1000);
  RecurseTreeCountLeaves(tree, counts);

  for (size_t i = 0; i < 1000; ++i)
    BOOST_REQUIRE_EQUAL(counts[i], 1);

  // Each non-leaf should have a self-child.
  CheckSelfChild<TreeType>(tree);

  // Each node must satisfy the covering principle (its children must be less
  // than or equal to a certain distance apart).
  CheckCovering<TreeType, LMetric<2, true> >(tree);

  // There's no need to check the separation because that is relaxed in our
  // implementation.
}

/**
 * Create a cover tree on sparse data and make sure it's accurate.
 */
BOOST_AUTO_TEST_CASE(SparseCoverTreeConstructionTest)
{
  arma::sp_mat dataset;
  // 50-dimensional, 1000 point.
  dataset.sprandu(50, 1000, 0.3);

  typedef StandardCoverTree<EuclideanDistance, EmptyStatistic, arma::sp_mat>
      TreeType;
  TreeType tree(dataset);

  // Ensure each leaf is only created once.
  arma::vec counts;
  counts.zeros(1000);
  RecurseTreeCountLeaves(tree, counts);

  for (size_t i = 0; i < 1000; ++i)
    BOOST_REQUIRE_EQUAL(counts[i], 1);

  // Each non-leaf should have a self-child.
  CheckSelfChild<TreeType>(tree);

  // Each node must satisfy the covering principle (its children must be less
  // than or equal to a certain distance apart).
  CheckCovering<TreeType, LMetric<2, true> >(tree);

  // There's no need to check the separation invariant because that is relaxed
  // in our implementation.
}

/**
 * Test the manual constructor.
 */
BOOST_AUTO_TEST_CASE(CoverTreeManualConstructorTest)
{
  arma::mat dataset;
  dataset.zeros(10, 10);

  typedef StandardCoverTree<EuclideanDistance, EmptyStatistic, arma::mat>
      TreeType;
  TreeType node(dataset, 1.3, 3, 2, NULL, 1.5, 2.75);

  BOOST_REQUIRE_EQUAL(&node.Dataset(), &dataset);
  BOOST_REQUIRE_EQUAL(node.Base(), 1.3);
  BOOST_REQUIRE_EQUAL(node.Point(), 3);
  BOOST_REQUIRE_EQUAL(node.Scale(), 2);
  BOOST_REQUIRE_EQUAL(node.Parent(), (CoverTree<>*) NULL);
  BOOST_REQUIRE_EQUAL(node.ParentDistance(), 1.5);
  BOOST_REQUIRE_EQUAL(node.FurthestDescendantDistance(), 2.75);
}

/**
 * Make sure cover trees work in different metric spaces.
 */
BOOST_AUTO_TEST_CASE(CoverTreeAlternateMetricTest)
{
  arma::mat dataset;
  // 5-dimensional, 300-point dataset.
  dataset.randu(5, 300);

  typedef StandardCoverTree<ManhattanDistance, EmptyStatistic, arma::mat>
      TreeType;
  TreeType tree(dataset);

  // Ensure each leaf is only created once.
  arma::vec counts;
  counts.zeros(300);
  RecurseTreeCountLeaves<TreeType>(tree, counts);

  for (size_t i = 0; i < 300; ++i)
    BOOST_REQUIRE_EQUAL(counts[i], 1);

  // Each non-leaf should have a self-child.
  CheckSelfChild<TreeType>(tree);

  // Each node must satisfy the covering principle (its children must be less
  // than or equal to a certain distance apart).
  CheckCovering<TreeType, ManhattanDistance>(tree);

  // There's no need to check the separation invariant because that is relaxed
  // in our implementation.
}

/**
 * Make sure copy constructor works for the cover tree.
 */
BOOST_AUTO_TEST_CASE(CoverTreeCopyConstructor)
{
  arma::mat dataset;
  dataset.randu(10, 10); // dataset is irrelevant.
  typedef StandardCoverTree<EuclideanDistance, EmptyStatistic, arma::mat>
      TreeType;
  TreeType c(dataset, 1.3, 0, 5, NULL, 1.45, 5.2); // Random parameters.
  c.Children().push_back(new TreeType(dataset, 1.3, 1, 4, &c, 1.3, 2.45));
  c.Children().push_back(new TreeType(dataset, 1.5, 2, 3, &c, 1.2, 5.67));

  TreeType d = c;

  // Check that everything is the same.
  // As the tree being copied doesn't own the dataset, they must share the same
  // pointer.
  BOOST_REQUIRE_EQUAL(c.Dataset().memptr(), d.Dataset().memptr());
  BOOST_REQUIRE_CLOSE(c.Base(), d.Base(), 1e-50);
  BOOST_REQUIRE_EQUAL(c.Point(), d.Point());
  BOOST_REQUIRE_EQUAL(c.Scale(), d.Scale());
  BOOST_REQUIRE_EQUAL(c.Parent(), d.Parent());
  BOOST_REQUIRE_EQUAL(c.ParentDistance(), d.ParentDistance());
  BOOST_REQUIRE_EQUAL(c.FurthestDescendantDistance(),
                      d.FurthestDescendantDistance());
  BOOST_REQUIRE_EQUAL(c.NumChildren(), d.NumChildren());
  BOOST_REQUIRE_NE(&c.Child(0), &d.Child(0));
  BOOST_REQUIRE_NE(&c.Child(1), &d.Child(1));

  BOOST_REQUIRE_EQUAL(c.Child(0).Parent(), &c);
  BOOST_REQUIRE_EQUAL(c.Child(1).Parent(), &c);
  BOOST_REQUIRE_EQUAL(d.Child(0).Parent(), &d);
  BOOST_REQUIRE_EQUAL(d.Child(1).Parent(), &d);

  // Check that the children are okay.
  BOOST_REQUIRE_EQUAL(c.Child(0).Dataset().memptr(), c.Dataset().memptr());
  BOOST_REQUIRE_CLOSE(c.Child(0).Base(), d.Child(0).Base(), 1e-50);
  BOOST_REQUIRE_EQUAL(c.Child(0).Point(), d.Child(0).Point());
  BOOST_REQUIRE_EQUAL(c.Child(0).Scale(), d.Child(0).Scale());
  BOOST_REQUIRE_EQUAL(c.Child(0).ParentDistance(), d.Child(0).ParentDistance());
  BOOST_REQUIRE_EQUAL(c.Child(0).FurthestDescendantDistance(),
                      d.Child(0).FurthestDescendantDistance());
  BOOST_REQUIRE_EQUAL(c.Child(0).NumChildren(), d.Child(0).NumChildren());

  BOOST_REQUIRE_EQUAL(c.Child(1).Dataset().memptr(), c.Dataset().memptr());
  BOOST_REQUIRE_CLOSE(c.Child(1).Base(), d.Child(1).Base(), 1e-50);
  BOOST_REQUIRE_EQUAL(c.Child(1).Point(), d.Child(1).Point());
  BOOST_REQUIRE_EQUAL(c.Child(1).Scale(), d.Child(1).Scale());
  BOOST_REQUIRE_EQUAL(c.Child(1).ParentDistance(), d.Child(1).ParentDistance());
  BOOST_REQUIRE_EQUAL(c.Child(1).FurthestDescendantDistance(),
                      d.Child(1).FurthestDescendantDistance());
  BOOST_REQUIRE_EQUAL(c.Child(1).NumChildren(), d.Child(1).NumChildren());

  // Check copy constructor when the tree being copied owns the dataset.
  TreeType e(std::move(dataset), 1.3);
  TreeType f = e;
  // As the tree being copied owns the dataset, they must have different
  // instances.
  BOOST_REQUIRE_NE(e.Dataset().memptr(), f.Dataset().memptr());
}

BOOST_AUTO_TEST_CASE(CoverTreeMoveDatasetTest)
{
  arma::mat dataset = arma::randu<arma::mat>(3, 1000);
  typedef StandardCoverTree<EuclideanDistance, EmptyStatistic, arma::mat>
      TreeType;

  TreeType t(std::move(dataset));

  BOOST_REQUIRE_EQUAL(dataset.n_elem, 0);
  BOOST_REQUIRE_EQUAL(t.Dataset().n_rows, 3);
  BOOST_REQUIRE_EQUAL(t.Dataset().n_cols, 1000);

  EuclideanDistance ed; // Test the other constructor.
  dataset = arma::randu<arma::mat>(3, 1000);
  TreeType t2(std::move(dataset), ed);

  BOOST_REQUIRE_EQUAL(dataset.n_elem, 0);
  BOOST_REQUIRE_EQUAL(t2.Dataset().n_rows, 3);
  BOOST_REQUIRE_EQUAL(t2.Dataset().n_cols, 1000);
}

/**
 * Make sure copy constructor works right for the binary space tree.
 */
BOOST_AUTO_TEST_CASE(BinarySpaceTreeCopyConstructor)
{
  arma::mat data("1");
  typedef KDTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
  TreeType b(data);
  b.Begin() = 10;
  b.Count() = 50;

  b.Left() = new TreeType(data);
  b.Left()->Begin() = 10;
  b.Left()->Count() = 30;
  b.Left()->Parent() = &b;
  b.Right() = new TreeType(data);
  b.Right()->Begin() = 40;
  b.Right()->Count() = 20;
  b.Right()->Parent() = &b;

  // Copy the tree.
  TreeType c(b);

  // Ensure everything copied correctly.
  BOOST_REQUIRE_EQUAL(b.Begin(), c.Begin());
  BOOST_REQUIRE_EQUAL(b.Count(), c.Count());
  BOOST_REQUIRE_NE(b.Left(), c.Left());
  BOOST_REQUIRE_NE(b.Right(), c.Right());

  // Check the children.
  BOOST_REQUIRE_EQUAL(b.Left()->Begin(), c.Left()->Begin());
  BOOST_REQUIRE_EQUAL(b.Left()->Count(), c.Left()->Count());
  BOOST_REQUIRE_EQUAL(b.Left()->Left(), (TreeType*) NULL);
  BOOST_REQUIRE_EQUAL(b.Left()->Left(), c.Left()->Left());
  BOOST_REQUIRE_EQUAL(b.Left()->Right(), (TreeType*) NULL);
  BOOST_REQUIRE_EQUAL(b.Left()->Right(), c.Left()->Right());

  BOOST_REQUIRE_EQUAL(b.Right()->Begin(), c.Right()->Begin());
  BOOST_REQUIRE_EQUAL(b.Right()->Count(), c.Right()->Count());
  BOOST_REQUIRE_EQUAL(b.Right()->Left(), (TreeType*) NULL);
  BOOST_REQUIRE_EQUAL(b.Right()->Left(), c.Right()->Left());
  BOOST_REQUIRE_EQUAL(b.Right()->Right(), (TreeType*) NULL);
  BOOST_REQUIRE_EQUAL(b.Right()->Right(), c.Right()->Right());

  // Clean memory (we built the tree by hand, so this is what we have to do
  // since the destructor won't free the children's datasets).
  delete &b.Left()->Dataset();
  delete &b.Right()->Dataset();
}

//! Count the number of leaves under this node.
template<typename TreeType>
size_t NumLeaves(TreeType* node)
{
  if (node->NumChildren() == 0)
    return 1;

  size_t count = 0;
  for (size_t i = 0; i < node->NumChildren(); ++i)
    count += NumLeaves(&node->Child(i));

  return count;
}

//! Returns true if the index is contained somewhere under this node.
template<typename TreeType>
bool FindIndex(TreeType* node, const size_t index)
{
  for (size_t i = 0; i < node->NumPoints(); ++i)
    if (node->Point(i) == index)
      return true;

  for (size_t i = 0; i < node->NumChildren(); ++i)
    if (FindIndex(&node->Child(i), index))
      return true;

  return false;
}

//! Check that the points in the given node are accessible through the
//! Descendant() function of the root node.
template<typename TreeType>
bool CheckAccessibility(TreeType* childNode, TreeType* rootNode)
{
  for (size_t i = 0; i < childNode->NumPoints(); ++i)
  {
    bool found = false;
    for (size_t j = 0; j < rootNode->NumDescendants(); ++j)
    {
      if (childNode->Point(i) == rootNode->Descendant(j))
      {
        found = true;
        break;
      }
    }

    if (!found)
    {
      Log::Debug << "Did not find descendant " << childNode->Point(i) << ".\n";
      return false;
    }
  }

  // Now check the children.
  for (size_t i = 0; i < childNode->NumChildren(); ++i)
    if (!CheckAccessibility(&childNode->Child(i), rootNode))
      return false;

  return true;
}

//! Check that Descendant() and NumDescendants() is right for this node.
template<typename TreeType>
void CheckDescendants(TreeType* node)
{
  // In a cover tree, the number of leaves should be the number of descendant
  // points.
  const size_t numLeaves = NumLeaves(node);
  BOOST_REQUIRE_EQUAL(numLeaves, node->NumDescendants());

  // Now check that each descendant is somewhere in the tree.
  for (size_t i = 0; i < node->NumDescendants(); ++i)
  {
    Log::Debug << "Check for descendant " << node->Descendant(i) << " (i " <<
        i << ").\n";
    BOOST_REQUIRE_EQUAL(FindIndex(node, node->Descendant(i)), true);
  }

  // Now check that every actual descendant is accessible through the
  // Descendant() function.
  BOOST_REQUIRE_EQUAL(CheckAccessibility(node, node), true);

  // Now check that there are no duplicates in the list of descendants.
  std::vector<size_t> descendants;
  descendants.resize(node->NumDescendants());
  for (size_t i = 0; i < node->NumDescendants(); ++i)
    descendants[i] = node->Descendant(i);

  // Sort the list.
  std::sort(descendants.begin(), descendants.end());

  // Check that there are no duplicates (this is easy because it's sorted).
  for (size_t i = 1; i < descendants.size(); ++i)
    BOOST_REQUIRE_NE(descendants[i], descendants[i - 1]);

  // Now perform these same checks for the children.
  for (size_t i = 0; i < node->NumChildren(); ++i)
    CheckDescendants(&node->Child(i));
}

/**
 * Make sure Descendant() and NumDescendants() works properly for the cover
 * tree.
 */
BOOST_AUTO_TEST_CASE(CoverTreeDescendantTest)
{
  arma::mat dataset;
  dataset.randu(3, 100);

  StandardCoverTree<EuclideanDistance, EmptyStatistic, arma::mat> tree(dataset);

  // Now check that the NumDescendants() count and each Descendant() is right
  // using the recursive function above.
  CheckDescendants(&tree);
}

BOOST_AUTO_TEST_SUITE_END();


/*
 ___ ___ __     __ ____________
|   |   |  |   |__|__|__   ___/  Ubiquitous Internet @ IIT-CNR
|   |   |  |  /__/  /  /  /      Stateful FaaS Model Latency Simulator
|   |   |  |/__/  /   /  /       https://github.com/ccicconetti/markovsim/
|_______|__|__/__/   /__/

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2021 Claudio Cicconetti <https://ccicconetti.github.io/>

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.
*/

/*
Determine the min number of containers required for a given number of clients,
which alternate between having a stateful (= they prefer having a dedicated
container) vs. stateless nature (= they are OK with being assigned to a pool
of shared stateless containers), so that the system is stable and the
probability that a stateful container is assigned to a shared pool of
stateless containers is below a given threshold (epsilon).
*/

#include "Support/chrono.h"
#include "Support/glograii.h"

#include <boost/program_options.hpp>

#include <glog/logging.h>

#include <cassert>
#include <cmath>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <vector>

namespace po = boost::program_options;

double compute_C_F_max(const size_t C_k, const size_t N_k,
                       const double lambda_k, const double mu_L) {
  return C_k * (mu_L - lambda_k * N_k / C_k) / (mu_L - lambda_k);
}

double binom(const size_t n, const size_t k) {
  // prepare input
  std::vector<double> myVec1(k);
  std::vector<double> myVec2(k);
  for (size_t i = n - k + 1, j = 0; i <= n; i++, j++) {
    myVec1[j] = i;
  }
  for (size_t i = k, j = 0; i >= 1; i--, j++) {
    myVec2[j] = i;
  }

  // compute return value
  double ret = 1.0;
  for (size_t i = 0; i < k; i++) {
    ret *= myVec1[i] / myVec2[i];
  }
  return ret;
}

double P_0(const size_t N_k, const double q_L, const double q_F) {
  return std::pow(q_L / (q_F + q_L), N_k);
}

double P_i(const size_t N_k, const size_t i, const double q_L,
           const double q_F) {
  return P_0(N_k, q_L, q_F) * binom(N_k, i) * std::pow(q_F / q_L, i);
}

/**
 * \return the probability that a function requiring a dedicated container
 * is assigned instead to a pool of shared stateless containers.
 */
double compute_P_v(const size_t C_F_max, const size_t N_k, const double q_L,
                   const double q_F) {
  assert(C_F_max > 0);
  assert(N_k > 0);

  double ret = 0;

  VLOG(2) << "q_L = " << q_L << ", q_F = " << q_F << " N_k = " << N_k << ", P0 "
          << P_0(N_k, q_L, q_F);

  for (size_t i = C_F_max; i <= N_k; i++) {
    ret += P_i(N_k, i, q_L, q_F);
  }

  return ret / (1 - P_0(N_k, q_L, q_F));
}

int main(int argc, char *argv[]) {
  uiiit::support::GlogRaii myGlogRaii(argv[0]);

  size_t N_k; // number of clients
  double inv_mu_F;
  double inv_mu_L;
  double lambda_k;
  double q_F;
  double q_L;
  double epsilon;

#ifndef NDEBUG
  assert(std::abs(binom(10, 4)) - 210.0 < 0.1);
  assert(std::abs(binom(20, 10)) - 184756.0 < 0.1);
  assert(std::abs(binom(30, 10)) - 30045015.0 < 0.1);
#endif

  po::options_description myDesc("Allowed options");
  // clang-format off
  myDesc.add_options()
    ("help,h", "produce help message")
    ("arrival-rate",
     po::value<double>(&lambda_k)->default_value(0.075),
     "Arrival rate, in Hz.")
    ("clients",
     po::value<size_t>(&N_k)->default_value(70),
     "Number of clients")
    ("service-time-full",
     po::value<double>(&inv_mu_F)->default_value(1.0),
     "Service time for clients assigned a dedicated container, in s.")
    ("service-time-less",
     po::value<double>(&inv_mu_L)->default_value(3.0),
     "Service time for clients sharing a pool of non-dedicated containers, in s.")
    ("q-full",
     po::value<double>(&q_F)->default_value(20),
     "Transition rate of clients in a stateless state.")
    ("q-less",
     po::value<double>(&q_L)->default_value(80),
     "Transition rate of clients in a stateful state.")
    ("epsilon",
     po::value<double>(&epsilon)->default_value(0.01),
     "Maximum accepted probability that a client in stateful state is served by a shared container.")
    ;
  // clang-format on

  try {
    po::variables_map myVarMap;
    po::store(po::parse_command_line(argc, argv, myDesc), myVarMap);
    po::notify(myVarMap);

    if (myVarMap.count("help")) {
      std::cout << myDesc << std::endl;
      return EXIT_FAILURE;
    }

    if (inv_mu_F <= 0) {
      throw std::runtime_error("Invalid service time (full): " +
                               std::to_string(inv_mu_F));
    }
    double mu_F = 1.0 / inv_mu_F;
    if (inv_mu_L <= 0) {
      throw std::runtime_error("Invalid service time (less): " +
                               std::to_string(inv_mu_L));
    }
    double mu_L = 1.0 / inv_mu_L;

    if (q_F <= 0) {
      throw std::runtime_error("Invalid transition rate (full): " +
                               std::to_string(q_F));
    }
    if (q_L <= 0) {
      throw std::runtime_error("Invalid transition rate (less): " +
                               std::to_string(q_L));
    }
    if (epsilon <= 0 or epsilon >= 1) {
      throw std::runtime_error("Invalid epsilon: " + std::to_string(epsilon));
    }

    for (size_t C_k = 1; C_k <= N_k; C_k++) {
      // maximum number of containers that can be dedicated to stateful use
      // while allowing the stateless clients to remain stable
      // note: the number can be negative, in which case the system will not be
      // stable for stateless clients even though they are left with _all_ the
      /// containers
      auto C_F_max_real = compute_C_F_max(C_k, N_k, lambda_k, mu_L);
      auto C_F_max_int =
          static_cast<size_t>(C_F_max_real < 0 ? 0 : C_F_max_real);

      if (C_F_max_int == 0) {
        VLOG(1) << "C_F_max = " << C_F_max_real << ": system unstable";
        continue;
      }

      // probability that a stateful container "overflows" to the pool
      // of shared stateless containers
      auto P_v = compute_P_v(C_F_max_int, N_k, q_L, q_F);

      VLOG(1) << "mu_F = " << mu_F << ", mu_L = " << mu_L << ", C_k = " << C_k
              << ", C_F_max = " << C_F_max_real << ", P_v = " << P_v;

      // if the probability is below threshold, quit
      if (P_v <= epsilon) {
        std::cout << C_k << ' ' << (static_cast<double>(C_k) / N_k) << ' '
                  << (C_k / (N_k * q_F / (q_F + q_L))) << std::endl;
        break;
      }
    }

    return EXIT_SUCCESS;

  } catch (const std::exception &aErr) {
    LOG(ERROR) << "Exception caught: " << aErr.what();

  } catch (...) {
    LOG(ERROR) << "Unknown exception caught";
  }

  return EXIT_FAILURE;
}


#include <boost/lexical_cast.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <cmath>
#include <iostream>
#include <map>
#include <string>

using namespace std;
using boost::lexical_cast;
using boost::multiprecision::cpp_int;

// Generate the n'th term in the Fibonacci sequence.
cpp_int fib(cpp_int n) {
	static map<cpp_int, cpp_int> memory;
	if(n <= 1) {
		return n;
	}
	if(memory.count(n) > 0) {
		return memory[n];
	}
	cpp_int ret = fib(n - 1) + fib(n - 2);
	memory[n] = ret;
	return ret;
}

int main(int argc, char *argv[]) {
	int index = 1;
	int num_digits = 0;
	while(num_digits != 1000) {
		string s = lexical_cast<string>(fib(index++));
		num_digits = s.size();
	}
	cout << (index - 1) << endl;
	return 0;
}


#define BOOST_TEST_MODULE Gpufit

#include "Gpufit/gpufit.h"

#include <boost/test/included/unit_test.hpp>

#include <array>
#include <cmath>

template<std::size_t SIZE>
void generate_gauss_2d_elliptic(std::array< REAL, SIZE>& values, std::array< REAL, 6 > const & parameters)
{
    int const size_x = int(std::sqrt(SIZE));
    int const size_y = size_x;

    REAL const a = parameters[0];
    REAL const x0 = parameters[1];
    REAL const y0 = parameters[2];
    REAL const sx = parameters[3];
    REAL const sy = parameters[4];
    REAL const b = parameters[5];

    for (int point_index_y = 0; point_index_y < size_y; point_index_y++)
    {
        for (int point_index_x = 0; point_index_x < size_x; point_index_x++)
        {
            int const point_index = point_index_y * size_x + point_index_x;
            REAL const argx = ((point_index_x - x0)*(point_index_x - x0)) / (2 * sx * sx);
            REAL const argy = ((point_index_y - y0)*(point_index_y - y0)) / (2* sy * sy);
            REAL const ex = exp(-argx) * exp(-argy);
            values[point_index] = a * ex + b;
        }
    }
}

BOOST_AUTO_TEST_CASE( Gauss_Fit_2D_Elliptic )
{
    std::size_t const n_fits{ 1 } ;
    std::size_t const n_points{ 25 } ;

    std::array< REAL, 6 > const true_parameters{ { 4, 2, 2, .4f, .6f, 1 } };

    std::array< REAL, n_points > data{};
    generate_gauss_2d_elliptic(data, true_parameters);

    std::array< REAL, n_points > weights{};
    std::fill(weights.begin(), weights.end(), 1.f);
    std::array< REAL, 6 > initial_parameters{ { 2, 1.8f, 2.2f, .5f, .5f, 0 } };
    REAL tolerance{ .001f };
    int max_n_iterations{ 10 };
    std::array< int, 6 > parameters_to_fit{ { 1, 1, 1, 1, 1, 1 } };
    std::array< REAL, 6 > output_parameters;
    int output_state;
    REAL output_chi_square;
    int output_n_iterations;

    int const status
            = gpufit
            (
                n_fits,
                n_points,
                data.data(),
                weights.data(),
                GAUSS_2D_ELLIPTIC,
                initial_parameters.data(),
                tolerance,
                max_n_iterations,
                parameters_to_fit.data(),
                LSE,
                0,
                0,
                output_parameters.data(),
                &output_state,
                &output_chi_square,
                &output_n_iterations
            ) ;

    BOOST_CHECK(status == 0);
    BOOST_CHECK(output_state == 0);
    BOOST_CHECK(output_n_iterations <= max_n_iterations);
    BOOST_CHECK(output_chi_square < 1e-6f);

    BOOST_CHECK(std::abs(output_parameters[0] - true_parameters[0]) < 1e-6f);
    BOOST_CHECK(std::abs(output_parameters[1] - true_parameters[1]) < 1e-6f);
    BOOST_CHECK(std::abs(output_parameters[2] - true_parameters[2]) < 1e-6f);
    BOOST_CHECK(std::abs(output_parameters[3] - true_parameters[3]) < 1e-6f);
    BOOST_CHECK(std::abs(output_parameters[4] - true_parameters[4]) < 1e-6f);
    BOOST_CHECK(std::abs(output_parameters[5] - true_parameters[5]) < 1e-6f);
}


#include <boost/test/unit_test.hpp>
#include "algorithms/math/fibonacci_numbers.hpp"

BOOST_AUTO_TEST_SUITE(TestFibbonacciNumbers)

BOOST_AUTO_TEST_CASE(small_numbers) {
    {
        std::vector<long long> expected = {0};
        BOOST_CHECK(expected == Algo::Math::FibonacciNumbers::ListOfNums(0));
    }

    {
        std::vector<long long> expected = {0, 1};
        BOOST_CHECK(expected == Algo::Math::FibonacciNumbers::ListOfNums(1));
    }

    {
        std::vector<long long> expected = {0, 1, 1};
        BOOST_CHECK(expected == Algo::Math::FibonacciNumbers::ListOfNums(2));
    }

    {
        std::vector<long long> expected = {0, 1, 1, 2, 3, 5};
        BOOST_CHECK(expected == Algo::Math::FibonacciNumbers::ListOfNums(5));
    }

    {
        std::vector<long long> expected = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55};
        BOOST_CHECK(expected == Algo::Math::FibonacciNumbers::ListOfNums(10));
    }
}

BOOST_AUTO_TEST_CASE(last_digit) {
    BOOST_CHECK(0 == Algo::Math::FibonacciNumbers::LastDigitOfNum(0));
    BOOST_CHECK(1 == Algo::Math::FibonacciNumbers::LastDigitOfNum(1));
    BOOST_CHECK(5 == Algo::Math::FibonacciNumbers::LastDigitOfNum(5));
    BOOST_CHECK(4 == Algo::Math::FibonacciNumbers::LastDigitOfNum(9));
    BOOST_CHECK(9 == Algo::Math::FibonacciNumbers::LastDigitOfNum(331));
    BOOST_CHECK(5 == Algo::Math::FibonacciNumbers::LastDigitOfNum(327305));
}

BOOST_AUTO_TEST_SUITE_END()


//
//  Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
//
//  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)
//
//  The authors gratefully acknowledge the support of
//  Fraunhofer IOSB, Ettlingen, Germany
//

#include <boost/numeric/ublas/tensor.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <ostream>

int main()
{
	using namespace boost::numeric::ublas;

	using tensorf = tensor<float>;
	using matrixf = matrix<float>;
	using vectorf = vector<float>;

	auto A = tensorf{3,4,2};
	auto B = A = 2;

	// Calling overloaded operators
	// and using simple tensor expression templates.
	if( A != (B+1) )
		A += 2*B - 1;

	// formatted output
	std::cout << "% --------------------------- " << std::endl;
	std::cout << "% --------------------------- " << std::endl << std::endl;
	std::cout << "A=" << A << ";" << std::endl << std::endl;

	auto n = shape{3,4};
	auto D = matrixf(n[0],n[1],1);
	auto e = vectorf(n[1],1);
	auto f = vectorf(n[0],2);

	// Calling constructor with
	// vector expression templates
	tensorf C = 2*f;
	// formatted output
	std::cout << "% --------------------------- " << std::endl;
	std::cout << "% --------------------------- " << std::endl << std::endl;
	std::cout << "C=" << C << ";" << std::endl << std::endl;

	// Calling overloaded operators
	// and mixing simple tensor and matrix expression templates
	tensorf F = 3*C + 4*prod(2*D,e);

	// formatted output
	std::cout << "% --------------------------- " << std::endl;
	std::cout << "% --------------------------- " << std::endl << std::endl;
	std::cout << "F=" << F << ";" << std::endl << std::endl;

}


///////////////////////////////////////////////////////////////////////////////
// moving_average.hpp                                                        //
//                                                                           //
//  Copyright 2008 Erwann Rogard. Distributed under the Boost                //
//  Software License, Version 1.0. (See accompanying file                    //
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)         //
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_ACCUMULATORS_RANDOM_MOVING_AVERAGE_HPP_ER_2008_04
#define BOOST_ACCUMULATORS_RANDOM_MOVING_AVERAGE_HPP_ER_2008_04

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/fir.hpp>
#include <boost/range/iterator_range.hpp>
namespace boost{namespace random
{

// Simulates a Moving average process
template<typename T>
class moving_average{
public:
    typedef T               input_type;
    typedef T               result_type ;
    template<typename R>
    moving_average(const R& coeffs)
        :acc(
            accumulators::tag::fir::coefficients=coeffs,
            accumulators::tag::delay<>::cache_size=coeffs.size()){}
    moving_average(const moving_average& that)
        :acc(that.acc){}
    moving_average& operator=(const moving_average& that){
        if(&that!=this){
            acc = that.acc;
        }
        return *this;
    }
    template<typename G>//G models NumberGenerator
    result_type operator()(G& gen){
        T x = gen();
        acc(x);
        return accumulators::extract::fir(acc);
    }
private:
    typedef accumulators::accumulator_set<
        T,
        accumulators::stats<
            accumulators::tag::fir,
            accumulators::tag::delay<>
        >
    > acc_type;
    acc_type acc;
};

}}
#endif