/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2023, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

/**
 * random
 * The example demonstrates the use of the random library.
 */

#include <mrpt/gui/CDisplayWindowPlots.h>
#include <mrpt/math/distributions.h>
#include <mrpt/random.h>

#include <iostream>

using namespace mrpt;
using namespace mrpt::gui;
using namespace mrpt::math;
using namespace mrpt::random;
using namespace mrpt::system;
using namespace std;

// not run by default. Uncomment corresponding line in the main function.
void TestHist()
{
	CHistogram hist(0.0, 100.0, 10u);
	hist.add(86);
	hist.add(7);
	hist.add(45);

	cout << "Histogram test:" << endl;
	cout << "Should be 1: " << hist.getBinCount(0) << endl;	 // Result: "1"
	cout << "Should be 0.33: " << hist.getBinRatio(0)
		 << endl;  // Result: "0.33"
}

// ------------------------------------------------------
//				TestRandomGenerators
// ------------------------------------------------------
void TestRandomGenerators()
{
	vector<double> x, y;

	getRandomGenerator().randomize();

	// Uniform numbers integers:
	CDisplayWindowPlots win1("Unif(0,5) (integers)");
	win1.setPos(10, 10);
	win1.resize(400, 400);
	{
		// CVectorDouble v1(100000);
		std::vector<size_t> v1(100000);
		getRandomGenerator().drawUniformVector(v1, 0, 5.999);

		CHistogram hist(-2, 15, 100);
		hist.add(v1);
		hist.getHistogramNormalized(x, y);

		win1.plot(x, y, "b");

		win1.axis_fit();
	}

	// Normalized Gauss:
	CDisplayWindowPlots win2("N(mean=0,std=1)");
	win2.setPos(420, 10);
	win2.resize(400, 400);
	{
		CVectorDouble v1(100000);
		getRandomGenerator().drawGaussian1DVector(v1, 0, 1);

		CHistogram hist(-5, 5, 100);
		hist.add(v1);
		hist.getHistogramNormalized(x, y);

		win2.plot(x, y, "b");

		CVectorDouble y_real(y.size());
		for (CVectorDouble::Index k = 0; k < y_real.size(); k++)
			y_real[k] = mrpt::math::normalPDF(x[k], 0, 1);
		win2.plot(x, y_real, "k-", "real");

		win2.axis_fit();
	}

	// Example Gauss:
	CDisplayWindowPlots win3("N(mean=3,std=2)");
	win3.setPos(10, 430);
	win3.resize(400, 400);
	{
		CVectorDouble v1(100000);
		getRandomGenerator().drawGaussian1DVector(v1, 3, 2);

		CHistogram hist(-5, 15, 100);
		hist.add(v1);
		hist.getHistogramNormalized(x, y);

		win3.plot(x, y, "b");

		CVectorDouble y_real(y.size());
		for (CVectorDouble::Index k = 0; k < y_real.size(); k++)
			y_real[k] = mrpt::math::normalPDF(x[k], 3, 2);
		win3.plot(x, y_real, "k-", "real");

		win3.axis_fit();
	}

	// Example multi-variate Gauss:
	CDisplayWindowPlots win4("N(mean=[3 4],var=[4 -2;-2 4])");
	win4.setPos(420, 430);
	win4.resize(400, 400);
	{
		vector<CVectorDouble> v1;
		CVectorDouble Mean(2);
		Mean[0] = 3;
		Mean[1] = 2;

		CMatrixDouble22 cov;
		cov.fromMatlabStringFormat("[7.5 -7;-7 8]");

		getRandomGenerator().drawGaussianMultivariateMany(
			v1, 10000, cov, &Mean);

#if 0
		CVectorDouble m;
		CMatrixDouble c;
		mrpt::math::meanAndCov(v1,m,c);
		cout << "Mean: " << m << endl;
		cout << "Std: " << endl << c << endl;
#endif

		// pass to (x,y) vectors:
		CVectorDouble vx(v1.size()), vy(v1.size());
		for (size_t i = 0; i < v1.size(); i++)
		{
			vx[i] = v1[i][0];
			vy[i] = v1[i][1];
		}

		win4.plot(vx, vy, "b.3");

		win4.plotEllipse(
			Mean[0], Mean[1], cov, 3.0, "k-2", "99% ellipse", true);

		win4.axis_fit();
	}

	win4.waitForKey();
}

// ------------------------------------------------------
//						MAIN
// ------------------------------------------------------
int main()
{
	try
	{
		// TestHist();
		TestRandomGenerators();

		return 0;
	}
	catch (const std::exception& e)
	{
		std::cerr << "MRPT error: " << mrpt::exception_to_str(e) << std::endl;
		return -1;
	}
}
