Note: The default ITS GitLab runner is a shared resource and is subject to slowdowns during heavy usage.
You can run your own GitLab runner that is dedicated just to your group if you need to avoid processing delays.

Commit 85ad80e6 authored by Guangting Yu's avatar Guangting Yu
Browse files

print soln after all working threads exit

ready to be called by MPI node
parent 2532ba47
#include <iostream>
#include <numeric>
#include <atomic>
#include <limits>
#include <thread>
#include <vector>
#include <cmath>
#include <mutex>
#include <condition_variable>
#include <gmpxx.h>
using namespace std;
using std::mutex;
using std::vector;
using std::thread;
using std::unique_lock;
using std::numeric_limits;
template<class num>
num gcd(num a, num b){
......@@ -27,25 +33,37 @@ auto gcd(container C){
class EulerSum{
const long double max_sum =
static_cast<double>(numeric_limits<size_t>::max());
size_t length;
size_t power;
size_t range;
vector<vector<size_t>> result;
std::condition_variable cv;
std::atomic<size_t> counter;
std::atomic<bool> found;
vector<thread> tasks;
const size_t length;
const size_t power;
const size_t range;
bool search_min;
mutex m;
// multithread faster than OpenMP parallel for
void thread_parent(){
vector<thread> v;
v.reserve(range);
for(size_t i=range; i<2*range; ++i){
v.push_back(thread([this,i]{thread_child(i);}));
void thread_parent(size_t up_bound){
counter=0;
found=false;
tasks.reserve(up_bound-range);
for(size_t i=range; i<up_bound; ++i){
tasks.push_back(thread([this,i]{thread_child(i);}));
// thread_child(i);
}
for(auto& n:v) n.join();
for(auto& n:tasks) n.join();
unique_lock<mutex> lck(m);
cv.wait(lck, [this]{return counter==tasks.size();});
}
void thread_child(size_t sum){
vector<size_t> v(length,1);
generate_simplex(v,sum,0);
unique_lock<mutex> _(m);
counter++;
cv.notify_one();
}
void check_sum(const vector<size_t>& v){
......@@ -53,6 +71,7 @@ class EulerSum{
for(auto&n:v){
powersum+=pow(n, power);
}
// not tested for large exponent (power>10)
long double sumroot = round(pow(powersum, 1.0/power));
if(abs(powersum-pow(sumroot, power))<1e-3){
check_sum(v, static_cast<size_t>(sumroot));
......@@ -75,18 +94,15 @@ class EulerSum{
}
void print_solution(const vector<size_t>& v, const size_t sum){
m.lock(); // avoid mixing outputs from different threads
printf("%lu^%lu\t=\t", sum, power);
printf("%lu^%lu", v.front(), power);
for(auto it=v.begin()+1; it!=v.end();it++){
printf("\t+\t%lu^%lu", *it, power);
}
printf("\n");
m.unlock();
unique_lock<mutex> _(m);
found=true;
result.push_back({sum});
result.back().insert(result.back().end(), v.begin(), v.end());
}
// single thread, recursion
void generate_simplex(vector<size_t>& v, const size_t sum, size_t idx){
if(search_min && found) return;
if(idx+1==v.size()){
v.back()=sum-accumulate(v.begin(), v.begin()+idx, 0);
if(gcd(v)==1){
......@@ -104,26 +120,44 @@ class EulerSum{
public:
EulerSum(size_t l, size_t p, size_t r):
length(l), power(p), range(r) {
if(range<length){
range=length;
}
length(l), power(p), range(std::max(r,l)) {
if(power>10){
cerr << "warning: unstable\n";
std::cerr << "warning: unstable\n";
}
search_min = true;
}
// stop after finding minimum
size_t configure(bool find_min){
search_min = find_min;
return thread::hardware_concurrency();
}
// called by MPI node
void run(size_t width){
thread_parent(range+width);
for(auto&v : result){
printf("%lu^%lu\t=\t", v[0], power);
printf("%lu^%lu", v[1], power);
for(auto it=v.begin()+2; it!=v.end();it++){
printf("\t+\t%lu^%lu", *it, power);
}
thread_parent();
printf("\n");
}
}
};
int main(int argc, char* argv[]){
if(argc!=4){
cerr << "input:\tlength\tpower\trange\n";
std::cerr << "input:\tlength\tpower\trange\n";
return EXIT_FAILURE;
}
EulerSum _(
EulerSum instance(
static_cast<size_t>(atoi(argv[1])),
static_cast<size_t>(atoi(argv[2])),
static_cast<size_t>(atoi(argv[3]))
);
instance.configure(true);
instance.run(1024);
return EXIT_SUCCESS;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment