#pragma once

#include <cassert>          // assert
#include <vector>
#include <iostream>
#include <cmath>
#include <tuple>
#include <string>
#include <algorithm>
#include <fstream>
#include <stdexcept>
#include <list>
using namespace std;

// -------------- Task A --------------

// Returns arithmetic, geometric and harmonic mean for 3 values a,b,c.
tuple<double, double, double> means0(double a, double b, double c);

// Returns arithmetic, geometric and harmonic mean for a vector.
tuple<double, double, double> means(const vector<double>& v);

// -------------- Task B --------------

/**
  This function opens the ASCII-file named @p file_name and reads the
  double data into the C++ vector @p v.
  If the file  @p file_name does not exist then the code stops with an appropriate message.
  @param[in]    file_name   name of the ASCII-file
  @param[out]   v           C++ vector with double values
*/

void read_vector_from_file(const string& file_name, vector<double>& v);


/**
  This function opens the ASCII-file named @p file_name and rewrites its with the
  double data from the C++ vector @p v.
  If there are problems in opening/generating file  @p file_name
  then the code stops with an appropriate message.
  @param[in]    file_name   name of the ASCII-file
  @param[in]    v           C++ vector with double values
*/

void write_vector_to_file(const string& file_name, const vector<double>& v);

/**
  Fills the double-vector @p v with data from an input stream @p istr until this input stream
  ends regularily. The vector is cleared and its memory is automatically allocated.
  @param[in]    istr        input stream
  @param[out]    v           C++ vector with double values
  @warning     An exception is thrown in case of wrong data format or corrupted data.
*/
void fill_vector(istream& istr, vector<double>& v);

// -------------- Task C --------------

// Sums up all positive integers less or equal n which are multiples of 3 or of 5 (including or!) by brute force.
long int sum_of_spec(int n);

// Sums up all positive integers less or equal n which are multiples of 3 or of 5 (including or!) by inclusion-exclusion principle. 
double formula(int n);

// -------------- Task D --------------

long double Kahan_skalar(std::vector<double> const &input);

long double normal_sum(std::vector<double> const &input);

// -------------- Task E --------------

// Inserts n random numbers into sorted vector v such that v remains sorted.
void insert_into_vector(vector<int>& vec, int n);

// Inserts n random numbers into sorted list such that the list remains sorted.
void insert_into_list(list<int>& lst, int n);


// -------------- Task F --------------

// Counts number of possible decompositions with 2 primes that sum up to k.
int single_goldbach(int k);

// Counts number of possible decompositions with 2 primes that sum up to k for all even numbers k \in {4,...,n}.
vector<int> count_goldbach(int n);

// Prints all decompositions of k.
void print_decomps(int k);

// -------------- Task G --------------

// Sigmoid function 1/(1+exp(-x))
double sigmoid(double x);

class DenseMatrix {
private:
    double sigmoid(double x);
    size_t rows;
    size_t cols;
    vector<double> matrix;
public:
    DenseMatrix(size_t n, size_t m); // Constructor
    vector<double> Mult(const vector<double>& vec) const;
    vector<double> MultT(const vector<double>& vec) const;
    void print() const;
};

class DenseMatrix2 {
private:
    size_t rows;
    size_t cols;
    vector<double> u_;
    vector<double> v_;
public:
    DenseMatrix2(vector<double> const u, vector<double> const v); // Constructor
    vector<double> Mult(const vector<double>& vec) const;
    vector<double> MultT(const vector<double>& vec) const;
};
