#pragma once

#include <cassert>
#include <omp.h>
#include <vector>

/** \brief Zaehlt fuer eine gegebene Zahl @k die Anzahl der moeglichen Zerlegungen als Summe zweier Primzahlen
 *
 * \param[in]   k   fuer diese Zahl wird die Anzahl der Zerlegungen berechnet
 * \return  Anzahl der Zerlegungen
 *
 */
int single_goldbach(const int &k);


/** \brief Zaehlt fuer eine gegebene Zahl @k die Anzahl der moeglichen Zerlegungen als Summe zweier Primzahlen [parallel]
 *
 * \param[in]   k   fuer diese Zahl wird die Anzahl der Zerlegungen berechnet
 * \return  Anzahl der Zerlegungen
 *
 */
int single_goldbach_par(const int &k);


/** \brief Zaehlt die Anzahl der Dekomposition für alle geraden Zahlen in [4,n]
 *
 * \param[in]   n   obere Intervallgrenze (in diesem Bereich werden die Dekompositionen berechnet
 * \return Vektor mit den Anzahl der Dekompositionen (ad Adressierung: x[0] = (n=4), x[1] = (n=6), x[2] = (n=8), Umrechnung *2 + 4
 *
 */
std::vector<int> count_goldbach(const int &n);


/** \brief Zaehlt die Anzahl der Dekomposition für alle geraden Zahlen in [4,n] - [parallel]
 *
 * \param[in]   n   obere Intervallgrenze (in diesem Bereich werden die Dekompositionen berechnet
 * \return Vektor mit den Anzahl der Dekompositionen (ad Adressierung: x[0] = (n=4), x[1] = (n=6), x[2] = (n=8), Umrechnung *2 + 4
 *
 */
std::vector<int> count_goldbach_par(const int &n);


/** 	 Vector @p b adds its elements to vector @p a .
	@param[in] a	vector
	@param[in] b	vector
	@return 	     a+=b componentwise
*/
template<class T>
std::vector<T> &operator+=(std::vector<T> &a, std::vector<T> const &b)
{
    assert(a.size()==b.size());
    for (size_t k = 0; k < a.size(); ++k) {
        a[k] += b[k];
    }
    return a;
}

#pragma omp declare reduction(VecAdd : std::vector<int>  : omp_out += omp_in) \
 initializer (omp_priv=omp_orig)
