#include "CrsMatrix.h"
#include "Matrix.h"
#include "Vector.h"

void testVector()
{
	int n = 4;
	std::vector<double> v1(n, 1.0);
	std::vector<double> v2(n, 1.1);
	std::vector<double> v3;

	// multiplication by scalar
	v3 <= v2 * 1.2;
	std::cout << v3;

	// plus
	v3 <= v1 + v2;
	std::cout << v3;
	v3 <= v1 + 1.3 * v2;
	std::cout << v3;
	v3 <= 1.3 * v2 + v1;
	std::cout << v3;

	//	// minus
	//	v3 <= v1 - v2;
	//	std::cout<<v3;
	//	v3 <= v1 - 0.5*v2;
	//	std::cout<<v3;
	//	v3 <= 0.5*v2 - v1;
	//	std::cout<<v3;
}

void testMatrix()
{
	SizeType n = 4;
	PsimagLite::Matrix<double> m1(n, n);
	for (SizeType i = 0; i < n; ++i) {
		m1(i, i) = i;
		SizeType iPlus1 = i + 1;
		if (iPlus1 >= n)
			iPlus1 = 0;
		m1(i, iPlus1) = m1(iPlus1, i) = 0.1;
	}

	PsimagLite::Matrix<double> m2;
	// multiplication by scalar
	m2 = m1 * 1.2;
	std::cout << m2;

	// plus
	PsimagLite::Matrix<double> m3;
	m3 = m1 + m2;
	std::cout << m3;
	m3 = m1 + 1.3 * m2;
	std::cout << m3;
	m3 = 1.3 * m2 + m1;
	std::cout << "--------------\n";
	std::cout << m3;
	std::cout << m2;
	m3 = 0.5 * (m3 - m2);
	std::cout << m3;
	std::cout << "--------------\n";
	m3 += m2;
	std::cout << m3;
	m3 -= m2;
	std::cout << m3;
	std::cout << "--------------\n";

	// minus tests omitted here

	// matrix * matrix
	m3 = m1 * m2;
	std::cout << m3;

	// matrix * vector
	std::vector<double> v1(n, 3.0);
	std::vector<double> v2;
	v2 <= m3* v1;
	std::cout << v2;
	v2 <= v1* m3;
	std::cout << v2;
}

template <typename T>
void createRandomCrs(PsimagLite::CrsMatrix<T>& crs, SizeType seed, SizeType nonZeros, T maxValue)
{
	srand48(seed);
	PsimagLite::Matrix<T> m(crs.rows(), crs.cols());
	for (SizeType i = 0; i < nonZeros; i++) {
		// pick a row
		SizeType row = SizeType(drand48() * m.rows());
		// and a column
		SizeType col = SizeType(drand48() * m.cols());
		// and a value
		T val = drand48() * maxValue;
		m(row, col) = val;
	}

	fullMatrixToCrsMatrix(crs, m);
}

template <typename T>
bool checkCrs(const PsimagLite::CrsMatrix<T>& m,
    const PsimagLite::Matrix<T>& fm)
{
	PsimagLite::Matrix<T> mf;
	crsMatrixToFullMatrix(mf, m);
	for (SizeType i = 0; i < fm.rows(); ++i) {
		for (SizeType j = 0; j < fm.cols(); ++j) {
			if (fabs(mf(i, j) - fm(i, j)) > 1e-6) {
				std::cout << mf;
				std::cout << fm;
				return false;
			}
		}
	}

	return true;
}

void testCrsMatrix()
{
	SizeType n = 10;
	unsigned int long seed = 343981;
	double ratio = 0.5;
	SizeType nonZeros = SizeType(ratio * n * n);
	double maxValue = 10.0;
	PsimagLite::CrsMatrix<double> m1(n, n);
	createRandomCrs(m1, seed, nonZeros, maxValue);
	PsimagLite::Matrix<double> fm1;
	crsMatrixToFullMatrix(fm1, m1);
	// std::cout<<m1;
	// std::cout<<"-------------\n";

	seed += 111;
	PsimagLite::CrsMatrix<double> m2(n, n);
	createRandomCrs(m2, seed, nonZeros, maxValue);
	PsimagLite::Matrix<double> fm2;
	crsMatrixToFullMatrix(fm2, m2);
	// std::cout<<m2;
	std::cout << "---operator+=scalar*crs----TEST 1/4\n";
	m1 += 1.2 * m2;
	//	std::cout<<m1;
	fm1 += 1.2 * fm2;
	std::cout << "CHECK PASSES=" << checkCrs(m1, fm1) << "\n";
	std::cout << "-------------\n";

	std::cout << "---ctor(crs*crs)----TEST 2/4\n";
	PsimagLite::CrsMatrix<double> m3 = m1 * m2;
	PsimagLite::Matrix<double> fm3 = fm1 * fm2;
	std::cout << "CHECK PASSES=" << checkCrs(m3, fm3) << "\n";
	//	std::cout<<m3;
	//	std::cout<<"-------------\n";

	std::cout << "---ctor(scalar*crs)----TEST 3/4\n";
	PsimagLite::CrsMatrix<double> m4 = 1.3 * m2;
	PsimagLite::Matrix<double> fm4;
	fm4 = 1.3 * fm2;
	std::cout << "CHECK PASSES=" << checkCrs(m4, fm4) << "\n";
	//	std::cout<<m4;
	//	std::cout<<"-------------\n";

	std::cout << "---ctor(scalar*crs)----TEST 4/4\n";
	m4 += 1.4 * m1 * m3;
	PsimagLite::Matrix<double> fm5;
	fm5 = 1.4 * fm1 * fm3;
	fm4 += fm5;
	//	std::cout<<m4;
	std::cout << "CHECK PASSES=" << checkCrs(m4, fm4) << "\n";
	std::cout << "-------------\n";
}

int main(int, char**)
{
	testVector();
	testMatrix();
	testCrsMatrix();
}
