#include <iostream>
#include <vector>   
#include <cmath>
using namespace std;


// Inner product
double benchmark_A(const vector<double> &x, const vector<double> &y)
{
    double sum = 0.0;
     for (unsigned int i = 0; i < x.size(); i++)
    {
        sum += x[i]*y[i];
    }
    return sum;
}

//Matrix-vector product
vector<double> benchmark_B(const vector<double> &A, const vector<double> &x)
{
    unsigned int N = x.size();
    unsigned int M = A.size() / N;
    vector<double> b(M, 0.0);

    for (unsigned int i = 0; i < M; i++)
    {
        double bi = 0.0;
        for (unsigned int j = 0; j < N; j++)
        {
            bi += A[i*N+j]*x[j];
        }
        b[i] = bi;
    }

    return b;
}


//Matrix-Matrix product
vector<double> benchmark_C(const vector<double> &A, const vector<double> &B, unsigned int M)
{
    unsigned int L = A.size()/M;
    unsigned int N = B.size()/L;
    vector<double> C(M*N,0.0);
     for (unsigned int i = 0; i < M; i++)
    {
        for (unsigned int j = 0; j < N; j++)
        {
            double sum = 0.0;
            for (unsigned int k = 0; k < L; k++)
            {
                sum += A[i*L+k]*B[k*N+j];
            }
            C[i*N+j] = sum;
        }
    }

    return C;

}

//polynomial evaluation
vector<double> benchmark_D(const vector<double>& coeff, const vector<double>& x)
{
    unsigned int p  = coeff.size();   // p coefficients, degree p-1
    unsigned int N  = x.size();
    vector<double> y(N);

    for (unsigned int i = 0; i < N; i++){
        double yi = coeff[p-1];
        double xi = x[i];
        for(int j=p-2; j>=0; --j)
        {
            yi = yi*xi+coeff[j];
        }
        y[i] = yi;
    }
    return y;
}

//TASK 5
double norm2(const vector<double>& x)
{
    double s = 0.0;
    for (unsigned int i = 0; i < x.size(); ++i)
        s += x[i]*x[i];
    return sqrt(s);
}

double scalar_kahan(const vector<double>& x, const vector<double>& y)
{
    double sum = 0.0;
    double c   = 0.0;   

    for (unsigned int i = 0; i < x.size(); i++)
    {
        double prod = x[i]*y[i];
        double yk = prod - c;
        double t  = sum+yk;
        c= (t - sum) - yk;
        sum = t;
    }
    return sum;
}

//Matrix-Matrix product
vector<double> matrixMultColumnWise(const vector<double> &A, const vector<double> &B, unsigned int M)
{
    unsigned int L = A.size()/M;
    unsigned int N = B.size()/L;
    vector<double> C(M*N,0.0);
     for (unsigned int i = 0; i < M; i++)
    {
        for (unsigned int j = 0; j < N; j++)
        {
            double sum = 0.0;
            for (unsigned int k = 0; k < L; k++)
            {
                sum += A[k*L+i]*B[k*N+j];
            }
            C[i*N+j] = sum;
        }
    }

    return C;

}