#include "include/helpers.hpp"
#include <iostream>
#include <armadillo>

using namespace std;
using namespace arma;
int main(int argc, char** argv) {
    int N = 6;
    if (argc > 1){ // Allow user to specify matrix size during call
        N = std::stoi(argv[1]);
    }

    // Setup of the matrix
    double h = 1.0 / (N + 1);
    mat A = create_tridiagonal_matrix(N, h);
    cout << "Tridiagonal matrix A:" << endl << A << endl;

    // Using Armadillo's built-in solver for comparison
    vec eigenvalues;
    mat eigenvectors;
    // Calling arma
    eig_sym(eigenvalues, eigenvectors, A);
    // Sorting and normalizing the results
    normalize_columns(eigenvectors);
    sort_eigenpairs(eigenvalues, eigenvectors);
    cout << "Eigenvalues:" << endl << eigenvalues << endl;
    cout << "Normalized eigenvectors:" << endl << eigenvectors << endl;

    // Generate analytical solution
    vec analytical_eigenvalues;
    mat analytical_eigenvectors;
    analytical_solution(N, h, analytical_eigenvalues, analytical_eigenvectors);
    // Again: Sort the pairs of eigenvalues and eigenvectors by eigenvalue magnitude
    normalize_columns(analytical_eigenvectors);
    sort_eigenpairs(analytical_eigenvalues, analytical_eigenvectors);
    cout << "Analytical Eigenvalues:" << endl << analytical_eigenvalues << endl;
    cout << "Analytical Normalized Eigenvectors:" << endl << analytical_eigenvectors << endl;

    // Using self-made Jacobi solver
    // Setup variables to capture output
    vec jacobi_eigenvalues;
    mat jacobi_eigenvectors;
    int iterations;
    bool converged;
    double eps = 1e-8;
    int maxiter = 1e5;
    // Calling the solver
    jacobi_eigensolver(A, eps, jacobi_eigenvalues, jacobi_eigenvectors, maxiter, iterations, converged);
    if (converged) {
        cout << "Jacobi method converged in " << iterations << " iterations." << endl;
    } else {
        cout << "Jacobi method did not converge within the maximum number of iterations." << endl;
    }
    normalize_columns(jacobi_eigenvectors); // Normalize the eigenvectors
    sort_eigenpairs(jacobi_eigenvalues, jacobi_eigenvectors);
    cout << "Jacobi Eigenvalues:" << endl << jacobi_eigenvalues << endl;
    cout << "Jacobi Normalized Eigenvectors:" << endl << jacobi_eigenvectors << endl;

    return 0;
}