#pragma once
#include <vector>
#include <cstddef>

//EXERCISE 4
// scalar and vector operations
double sum_basic(const std::vector<double>& x);          
double dot_basic(const std::vector<double>& x, const std::vector<double>& y); 
double dot_kahan(const std::vector<double>& x, const std::vector<double>& y);
double norm_basic(const std::vector<double>& x);

// matrix-vector, matrix-matrix, polynomial
void matvec_rowmajor(const std::vector<double>& A, std::size_t M, std::size_t N,
                     const std::vector<double>& x, std::vector<double>& b);

void matmul_rowmajor(const std::vector<double>& A, std::size_t M, std::size_t L,
                     const std::vector<double>& B, std::size_t N,
                     std::vector<double>& C);

void polyp_horner(const std::vector<double>& a, const std::vector<double>& x,
                  std::vector<double>& y);


// EXERCISE 5
struct CSR {
    std::size_t n;
    std::vector<double> val;
    std::vector<std::size_t> col;
    std::vector<std::size_t> row_ptr;
};

void jacobi_csr(const CSR& K, const std::vector<double>& f, std::vector<double>& u,
                std::size_t max_iter, double omega, double tol);

// build tridiagonal FEM matrix K and rhs f (parallel)
void build_fem_system(std::size_t n, CSR& K, std::vector<double>& f);

//Jacobi iteration (parallel)
void jacobi_csr_parallel(const CSR& K, const std::vector<double>& f,
                         std::vector<double>& u,
                         std::size_t max_iter, double omega, double tol);

// EXERCISE 6

// parallel element assembly with atomics
void build_fem_system_atomic(std::size_t n, CSR &K, std::vector<double> &f);

// No-atomic grouped assembly (method (a))
void build_fem_system_no_atomic(std::size_t n, CSR &K, std::vector<double> &f);

