#include "Gauss.h"
#include "Matrix.h"
#include "test_assert.h"

#include <chrono>
#include <iostream>

static constexpr int MATRIX_MAX_SIZE = 300;
static constexpr int EXECUTION_COUNT = 1;

struct Test {
	Matrix mat;
	Matrix res;
};

static const std::vector<Test> TEST_MATRICES = {
    // test 1
    {{3, 3, {
        1, 2, 3,
        4, 5, 6,
        7, 8, 9,
    }}, {3, 3, {
        1, 0, -1,
        0, 1, 2,
        0, 0, 0,
    }}},
    // test 2
    {{3, 3, {
        4, 5, 6,
        1, 2, 3,
        7, 8, 9,
    }}, {3, 3, {
        1, 0, -1,
        0, 1, 2,
        0, 0, 0,
    }}}
};

static unsigned int GetRandomInt() {
	return rand() % MATRIX_MAX_SIZE + 1;
}

static Matrix GetRandomMatrix(std::size_t a_Raw, std::size_t a_Column) {
	Matrix matrix {a_Raw, a_Column};

	for (std::size_t i = 0; i < matrix.GetRawCount(); i++) {
		for (std::size_t j = 0; j < matrix.GetColumnCount(); j++) {
			matrix.at(i, j) = GetRandomInt();
		}
	}

	return matrix;
}

void test() {
	for (Test test : TEST_MATRICES) {
		Gauss::GaussJordan(test.mat, true, true);
		test_assert(test.mat == test.res);
	}
}

void gaussTest() {
    auto start = std::chrono::system_clock::now();

	for (int i = 0; i < EXECUTION_COUNT; i++) {
		Matrix mat = GetRandomMatrix(500, 500);
		Gauss::GaussJordan(mat, false, false);
	}

	auto end = std::chrono::system_clock::now();
	std::chrono::duration<double> elapsed_seconds = end - start;
	std::cout << "\tgauss jordan elapsed time : " << elapsed_seconds.count() << "s" << std::endl;
}

void speedTest() {
    gaussTest();
   // gaussColumnTest();
}

int main(int argc, char** argv) {
	test();
	speedTest();
	return 0;
}
