#include "bsp_5_3_lib.h"
#include "mayer_primes.h"
#include "algorithm"
#include <iostream>
#ifdef _OPENMP
#include <omp.h>
#endif

using namespace std;

int single_goldbach(const int &k)
{
    vector<int> primes = get_primes(k);
    int amount = 0;
    for(size_t it = 0; primes[it]<=k/2.0; ++it) //für Primzahl größer als k/2 haben wir bereits Zerlegung gezählt: 3+7 = 7+3
    {
       for(size_t j = it; j<primes.size(); ++j)
       {
           if(primes[it] + primes[j] == k)
           {
               amount += 1;
           }
       }
    }

    return amount;
}


int single_goldbach_par(const int &k)
{
    vector<int> primes = get_primes(k);
    int amount = 0;
    size_t it_max = 0;
    // to get a barrier for the loop; omp needs a fix upper bound
	while (it_max < primes.size() && primes[it_max] <= k/2)
    {
		++it_max;
	}
    
#pragma omp parallel for default(none) shared(primes, k, it_max) reduction(+:amount)
    for(size_t it = 0; it<it_max; ++it) //für Primzahl größer als k/2 haben wir bereits Zerlegung gezählt: 3+7 = 7+3
    {
       for(size_t j = it; j<primes.size(); ++j)
       {
           if(primes[it] + primes[j] == k)
           {
               amount += 1;
           }
       }
    }

    return amount;
}


vector<int> count_goldbach(const int &n)
{
    vector<int> count_vec((n-4)/2+1,0);
    vector<int> primes = get_primes(n);
    for(size_t k=0; k < primes.size() && primes[k]<=n/2; ++k)
    {
        for(size_t i=k; i<primes.size(); ++i)
        {
            int sum = primes[k] + primes[i];
            if(sum<=n)
            {
                count_vec[(sum-4)/2] += 1;
            }
        }
    }

    return count_vec;
}


vector<int> count_goldbach_par(const int &n)
{
    vector<int> count_vec((n-4)/2+1,0);
    vector<int> primes = get_primes(n);
    size_t it_max = 0;
    while (it_max < primes.size() && primes[it_max] <= n/2)
    {
		++it_max;
	}
    
#pragma omp parallel for schedule(dynamic) shared(primes, n, it_max) reduction(VecAdd:count_vec)
    for(size_t k=0; k<it_max; ++k)
    {
        for(size_t i=k; i<primes.size(); ++i)
        {
            int sum = primes[k] + primes[i];
            if(sum<=n)
            {
                count_vec[(sum-4)/2] += 1;
            }
        }
    }

    return count_vec;
}
