From 6d07558df8e73f5106a270258022e8be1a79a37d Mon Sep 17 00:00:00 2001 From: Aleksey Lobanov Date: Wed, 25 Apr 2018 23:57:18 +0300 Subject: [PATCH] First version with advanced algorithm --- al_utility.cpp | 19 ++++ al_utility.hpp | 11 ++ main.cpp | 302 +++++++++++++++++++++++++++++++++---------------- 3 files changed, 233 insertions(+), 99 deletions(-) create mode 100644 al_utility.cpp create mode 100644 al_utility.hpp diff --git a/al_utility.cpp b/al_utility.cpp new file mode 100644 index 0000000..59ccf01 --- /dev/null +++ b/al_utility.cpp @@ -0,0 +1,19 @@ +#include "al_utility.hpp" + +bool print_progress(long current, long total, double print_every) { + long integer_part = total * print_every; + if ( current % integer_part != 0 ) + return false; + + // сделаем потокобезопасным + std::stringstream ss; + ss << "Progress " << current << " of " << total + << " " << std::fixed << std::setw(5) << std::setprecision(2) + << 100. * current / total << "%" << std::endl; + std::cout << ss.str(); + return true; +} + +int get_math_coeff(int k) { + return static_cast(pow(1.4, k + 2)); +} diff --git a/al_utility.hpp b/al_utility.hpp new file mode 100644 index 0000000..4f14944 --- /dev/null +++ b/al_utility.hpp @@ -0,0 +1,11 @@ +#ifndef _AL_UTILITY_ +#define _AL_UTILITY_ + +#include +#include +#include +#include + +bool print_progress(long current, long total, double print_every=0.1); +int get_math_coeff(int k); +#endif // _AL_UTILITY_ diff --git a/main.cpp b/main.cpp index 1fd98e1..bcc0107 100644 --- a/main.cpp +++ b/main.cpp @@ -16,15 +16,20 @@ #include #include +#include "al_utility.hpp" #include "finite_function.hpp" using namespace std; - - const CellType CUR_BASE = 3; const int ARGS_COUNT = 2; +struct FunctionTask { + set> current; + bool is_finished; + int current_max_coeff; +}; + template class FixedIniter { public: @@ -257,120 +262,207 @@ set> generate_function_class(FiniteFunction base_func return set>(func_class.begin(), func_class.end()); } + +// Возвращает новый функциональный класс, размером не сильно больше, чем max_size +// Вторым результатом возвращает true, если вычисления закончились успешно +// и false, если прервались по достижению max_size +template +pair>, bool> extend_function_class( + const set>& base_class, + size_t max_size +) { + auto FiniteFunctionHasher = [](const FiniteFunction &f) -> uint32_t { + return f.get_hash(); + }; + unordered_set< + FiniteFunction, + decltype(FiniteFunctionHasher) + > func_class(1024, FiniteFunctionHasher); + for (auto&& base_function: base_class) + func_class.insert(base_function); + + bool is_finished = false; + size_t last_size = 0; // размер в прошлой итерации + while (true) { + unordered_set< + FiniteFunction, + decltype(FiniteFunctionHasher) + > new_funcs(1024, FiniteFunctionHasher); + + for (const auto& f_main: func_class) { + new_funcs.insert(f_main.reversed()); + for (const auto& f_applied: func_class) { + FiniteFunction f_left; + f_left = f_main.apply_to_first_partial(f_applied); + new_funcs.insert(f_left); + } + } + if ( new_funcs.size() == last_size ) { + is_finished = true; + break; + } + + func_class.insert(new_funcs.begin(), new_funcs.end()); + last_size = new_funcs.size(); + + // слишком много насчитали -- выходим + if ( func_class.size() > max_size ) { + break; + } + } + return make_pair( + set>(func_class.begin(), func_class.end()), + is_finished + ); +} + + +bool is_bad_class( + set> func_class, + const set>& bad_funcs +) { + for (auto&& func: func_class) + if ( bad_funcs.find(func) != bad_funcs.end() ) + return true; + return false; +} + vector > possible_functions; + size_t total_possible_functions; atomic current_function; + +atomic completed_tasks; mutex possible_functions_mutex; list< set> > shared_function_classes; mutex shared_functions_mutex; -void do_work() { - list< set> > local_function_classes; - - FiniteFunction identical_x(string("000 111 222")); - FiniteFunction identical_y(string("012 012 012")); - - while ( true ) { - possible_functions_mutex.lock(); - if ( current_function >= total_possible_functions ) { - possible_functions_mutex.unlock(); - break; - } - FiniteFunction base_function = possible_functions.at( - current_function - ); - ++current_function; - possible_functions_mutex.unlock(); - - set< FiniteFunction > func_class = generate_function_class(base_function); - func_class.erase(identical_x); - func_class.erase(identical_y); - bool is_need_append = true; - vector functions_to_remove; - for (auto it = local_function_classes.begin(); it != local_function_classes.end(); ++it) { - if ( func_class.size() < it->size() ) { - if (includes( - it->begin(), - it->end(), - func_class.begin(), - func_class.end() - ) - ) { - // новый класс функций часть уже существующего - functions_to_remove.push_back(it); - } +list task_list; +mutex task_mutex; + +list processed_task_list; +mutex processed_task_mutex; + +set> bad_functions; + + +void do_work() { + std::chrono::milliseconds SLEEP_TIME(10); + while ( true ) { + FunctionTask task; + task_mutex.lock(); + if ( task_list.begin() != task_list.end() ) { + task = task_list.front(); + task_list.pop_front(); + task_mutex.unlock(); + } else { + task_mutex.unlock(); + if ( completed_tasks < total_possible_functions ) { + // Не все таски, подождём, пока добавят ещё + std::this_thread::sleep_for(SLEEP_TIME); + continue; } else { - if (includes( - func_class.begin(), - func_class.end(), - it->begin(), - it->end() - ) - ) { - // новый класс функций надмножество существующего - is_need_append = false; - break; - } + cout << "thread " << this_thread::get_id() << ": " + << " finished" << endl; + break; } } - if ( is_need_append ) - local_function_classes.push_back(func_class); - for (auto&& to_remove: functions_to_remove) - local_function_classes.erase(to_remove); + + tie(task.current, task.is_finished) = extend_function_class( + task.current, + get_math_coeff(task.current_max_coeff) + ); + cout << "k=" << task.current_max_coeff << endl; + processed_task_mutex.lock(); + processed_task_list.push_back(task); + processed_task_mutex.unlock(); } - cout << "local " << this_thread::get_id() << ": " - << local_function_classes.size() << " functions" << endl; - - // Сливаем всё вметсе - shared_functions_mutex.lock(); - for (auto it_local = local_function_classes.begin(); it_local != local_function_classes.end(); ++it_local) { - auto func_class = *it_local; - bool is_need_append = true; - vector functions_to_remove; - for (auto it = shared_function_classes.begin(); it != shared_function_classes.end(); ++it) { - if ( func_class.size() < it->size() ) { - if (includes( - it->begin(), - it->end(), - func_class.begin(), - func_class.end() - ) - ) { - // новый класс функций часть уже существующего - functions_to_remove.push_back(it); - } - } else { - if (includes( - func_class.begin(), - func_class.end(), - it->begin(), - it->end() - ) - ) { - // новый класс функций надмножество существующего - is_need_append = false; - break; - } - } - } - if ( is_need_append ) - shared_function_classes.push_back(func_class); - for (auto&& to_remove: functions_to_remove) - shared_function_classes.erase(to_remove); - } - shared_functions_mutex.unlock(); - cout << "shared_functions_mutex unlocked" << endl; } + +void process_task_lists() { + cout << "processing starts " << endl; + + std::chrono::milliseconds SLEEP_TIME(10); + while ( completed_tasks < total_possible_functions ) { + // опустошим выполненные таски + processed_task_mutex.lock(); + list local_processed_task_list = processed_task_list; + processed_task_list.clear(); + processed_task_mutex.unlock(); + + for ( auto&& task: local_processed_task_list ) { + if ( !task.is_finished ) { + if ( is_bad_class(task.current, bad_functions) ) { + //cout << "bad class" << endl; + ++completed_tasks; + } else { + ++task.current_max_coeff; + task_mutex.lock(); + task_list.push_back(task); + task_mutex.unlock(); + } + + } else { + cout << "task finished, appending" << endl; + ++completed_tasks; + auto func_class = task.current; + bool is_need_append = true; + vector functions_to_remove; + for (auto it = shared_function_classes.begin(); it != shared_function_classes.end(); ++it) { + if ( func_class.size() < it->size() ) { + if (includes( + it->begin(), + it->end(), + func_class.begin(), + func_class.end() + ) + ) { + // новый класс функций часть уже существующего + functions_to_remove.push_back(it); + } + } else { + if (includes( + func_class.begin(), + func_class.end(), + it->begin(), + it->end() + ) + ) { + // новый класс функций надмножество существующего + is_need_append = false; + break; + } + } + } + if ( is_need_append ) { + shared_function_classes.push_back(func_class); + for (auto&& func: func_class) + bad_functions.insert(func); + } + for (auto&& to_remove: functions_to_remove) { + shared_function_classes.erase(to_remove); + cout << "Removing class from shared_function_classes" << endl; + } + } + } + local_processed_task_list.clear(); + + // Поспим, чтобы не работать слишком часто + std::this_thread::sleep_for(SLEEP_TIME); + } +} + + int main() { auto FiniteFunctionHasher = [](const FiniteFunction &f) -> uint32_t { return f.get_hash(); }; - auto THREADS_COUNT = thread::hardware_concurrency(); + auto THREADS_COUNT = max(static_cast(thread::hardware_concurrency()), 2); cout << "Using " << THREADS_COUNT << " threads" << endl; auto funcs = get_funcs(); @@ -404,17 +496,29 @@ int main() { allowed_functions.end(), back_inserter(possible_functions) ); + completed_tasks = 0; + for (auto&& func: allowed_functions) { + FunctionTask task; + task.current.insert(func); + task.is_finished = false; + task.current_max_coeff = 1; + task_list.push_back(task); + } - total_possible_functions = possible_functions.size(); - current_function = 0; + cout << "Total funcs in list" << task_list.size() << " functions" << endl; + + total_possible_functions = task_list.size(); vector< thread > thread_pool; + thread task_processer(process_task_lists); - for (size_t i = 0; i < THREADS_COUNT; ++i) + for (size_t i = 0; i < THREADS_COUNT - 1; ++i) thread_pool.push_back(thread(do_work)); - + for (auto&& t: thread_pool) t.join(); + + task_processer.join(); cout << "Shared " << shared_function_classes.size() << " functions!" << endl; // перегоняем список с классами в массив с классами