#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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: // rules это отображение обязательных значений аргументов, к // значениями функции, которые не должны при них изменяться explicit FixedIniter(map, int> rules) : _rules(rules), _cur_values(BASE*BASE, 0) { for (auto it = rules.begin(); it != rules.end(); ++it) { size_t arg1 = it->first.first; size_t arg2 = it->first.second; int value = it->second; _cur_values.at(FiniteFunction::get_index(arg1, arg2)) = value; _used_indexes.insert(FiniteFunction::get_index(arg1, arg2)); } } int operator() (int first, int second) const { return _cur_values[FiniteFunction::get_index(first, second)]; } // Возвращает true, пока может построить следующую функцию // если не может это сделать, то возвращает false bool set_next() { bool is_overflow = true; for (size_t i = 0; is_overflow; ++i) { if ( i >= _cur_values.size() ) return false; if ( _used_indexes.count(i) > 0 ) continue; _cur_values.at(i) += 1; bool is_overflow = (_cur_values.at(i) > static_cast(BASE) - 1); if ( is_overflow ) _cur_values.at(i) = 0; else return true; } throw "Wrong logic"; } private: set _used_indexes; map, int> _rules; vector _cur_values; }; template void write_function_class(ofstream &f_out, Iterable begin, Iterable end) { for (;begin != end; ++begin) f_out << *begin << " "; f_out << endl; } /* template void get_permutations(vector> &permutations) { permutations.clear(); array cur_perm; for (int i = 0; i < BASE; ++i) cur_perm[i] = i; do { permutations.push_back(cur_perm); } while ( next_permutation(cur_perm.begin(), cur_perm.end()) ); } */ template bool is_one_arg_func(const TripleArgsFiniteFunction &h) { bool is_equaled_x = true; bool is_equaled_y = true; bool is_equaled_z = true; for (CellType x = 0; x < CUR_BASE; ++x) for (CellType y = 0; y < CUR_BASE; ++y) { for (CellType z = 0; z < CUR_BASE; ++z) { is_equaled_x = is_equaled_x && (h(x,y,z) == x); is_equaled_y = is_equaled_y && (h(x,y,z) == y); is_equaled_z = is_equaled_z && (h(x,y,z) == z); } if ( !is_equaled_x && !is_equaled_y && !is_equaled_z ) return false; } return true; } template bool is_projection(const TripleArgsFiniteFunction &h) { bool is_projection = true; for (CellType x = 0; x < CUR_BASE; ++x) for (CellType y = 0; y < CUR_BASE; ++y) { is_projection = (is_projection && h(x,x,y) == h(x,y,x) && h(x,y,x) == h(y,x,x) && h(y,x,x) == x); } return is_projection; } template bool is_semiprojection(const TripleArgsFiniteFunction &h) { bool is_equaled_x = true; bool is_equaled_y = true; bool is_equaled_z = true; for (CellType x = 0; x < CUR_BASE; ++x) for (CellType y = 0; y < CUR_BASE; ++y) for (CellType z = 0; z < CUR_BASE; ++z) { // если все различны, то не рассматриваем if ( x != y && x != z && y != z ) continue; is_equaled_x = is_equaled_x && (h(x,y,z) == x); is_equaled_y = is_equaled_y && (h(x,y,z) == y); is_equaled_z = is_equaled_z && (h(x,y,z) == z); } return is_equaled_x || is_equaled_y || is_equaled_z; } bool is_passed_rosenberg(const FiniteFunction &f) { auto h_1 = [f](const CellType x, const CellType y, CellType z) -> CellType { return f( f(x,y), f(x,z) ); }; if ( !is_one_arg_func(h_1) ) { if ( is_projection(h_1) || is_semiprojection(h_1) ) return false; } auto h_2 = [f](const CellType x, const CellType y, CellType z) -> CellType { return f( f(x, y), f(z, x) ); }; if ( !is_one_arg_func(h_2) ) { if ( is_projection(h_2) || is_semiprojection(h_2) ) return false; } auto h_3 = [f](const CellType x, const CellType y, CellType z) -> CellType { return f( f(x,y), f(y,z) ); }; if ( !is_one_arg_func(h_3) ) { if ( is_projection(h_3) || is_semiprojection(h_3) ) return false; } auto h_4 = [f](const CellType x, const CellType y, CellType z) -> CellType { return f( f(x,y), f(z,y) ); }; if ( !is_one_arg_func(h_4) ) { if ( is_projection(h_4) || is_semiprojection(h_4) ) return false; } return true; } template vector> get_funcs() { size_t count = 0; map, int> rules; for (int i = 0; i < BASE; ++i) rules[make_pair(i,i)] = i; FixedIniter initer(rules); //vector> permutations; //get_permutations(permutations); vector> funcs; set< FiniteFunction > permutated_funcs; do { ++count; auto cur_func = FiniteFunction(initer); //if ( permutated_funcs.find(cur_func) != permutated_funcs.end() ) // continue; // если закомментить, то 17 классов, вместо 20 //for (auto&& permutation: permutations) // permutated_funcs.insert(cur_func.apply_permutation(permutation)); funcs.push_back(cur_func); } while (initer.set_next()); cout << "Total " << count << " functions" << endl; funcs.erase( remove_if( funcs.begin(), funcs.end(), [](const FiniteFunction & f) { return !is_passed_rosenberg(f); } ), funcs.end() ); cout << "After Rosenberg " << funcs.size() << " functions" << endl; //if ( permutated_funcs.size() != count ) // throw "Permutation's logic error!"; return funcs; } template set> generate_function_class(FiniteFunction base_function) { auto FiniteFunctionHasher = [](const FiniteFunction &f) -> uint32_t { return f.get_hash(); }; unordered_set< FiniteFunction, decltype(FiniteFunctionHasher) > func_class(1024, FiniteFunctionHasher); func_class.insert(base_function); //cout << "start with " << base_function << " "; 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()); //new_funcs.insert(f_main.equaled()); for (const auto& f_applied: func_class) { //FiniteFunction f_left_1, f_left_2; //tie(f_left_1, f_left_2) = f_main.apply_to_first(f_applied); FiniteFunction f_left; f_left = f_main.apply_to_first_partial(f_applied); new_funcs.insert(f_left); } } if ( new_funcs.size() == last_size ) { break; } func_class.insert(new_funcs.begin(), new_funcs.end()); last_size = new_funcs.size(); } 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 ) { if ( base_class.size() >= max_size ) return make_pair( set>(base_class.begin(), base_class.end()), false ); FiniteFunction identical_x(string("000 111 222")); FiniteFunction identical_y(string("012 012 012")); 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()); func_class.erase(identical_x); func_class.erase(identical_y); 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; } size_t total_possible_functions; atomic completed_tasks; atomic tasks_to_extend; // количество тасков, которые не обработаны list< set> > shared_function_classes; mutex shared_functions_mutex; deque task_list; mutex task_mutex; vector 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 { cout << "thread " << this_thread::get_id() << ": " << " finished" << endl; break; } } tie(task.current, task.is_finished) = extend_function_class( task.current, get_math_coeff(task.current_max_coeff) ); processed_task_mutex.lock(); processed_task_list.push_back(task); processed_task_mutex.unlock(); --tasks_to_extend; } } void process_task_lists() { cout << "processing starts " << endl; std::chrono::milliseconds SLEEP_TIME(10); while ( completed_tasks < total_possible_functions ) { if ( tasks_to_extend ) { // подождём, пока не закончатся таски в очереди std::this_thread::sleep_for(SLEEP_TIME); continue; } task_mutex.lock(); task_list.shrink_to_fit(); task_mutex.unlock(); // опустошим выполненные таски processed_task_mutex.lock(); vector local_processed_tasks = processed_task_list; processed_task_list.clear(); processed_task_list.shrink_to_fit(); processed_task_mutex.unlock(); cout << "sorting finished of "<< local_processed_tasks.size() << endl; // Обеспечим увеличение размеров, чтобы не было проблем со включением одного // в другое sort( local_processed_tasks.begin(), local_processed_tasks.end(), [](const FunctionTask& a, const FunctionTask& b) { return a.current.size() < b.current.size(); } ); for ( auto&& task: local_processed_tasks ) { if ( !task.is_finished ) { if ( is_bad_class(task.current, bad_functions) ) { //cout << "bad class" << endl; ++completed_tasks; print_progress(completed_tasks, total_possible_functions); } else { ++task.current_max_coeff; task_mutex.lock(); ++tasks_to_extend; task_list.push_back(task); task_mutex.unlock(); } } else { //cout << "task finished, appending" << endl; ++completed_tasks; print_progress(completed_tasks, total_possible_functions); 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() ) ) { cout << "includes!!" << endl; // новый класс функций часть уже существующего 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_tasks.clear(); // Поспим, чтобы не работать слишком часто std::this_thread::sleep_for(SLEEP_TIME); } } int main() { auto FiniteFunctionHasher = [](const FiniteFunction &f) -> uint32_t { return f.get_hash(); }; auto THREADS_COUNT = max(static_cast(thread::hardware_concurrency()), 2); cout << "Using " << THREADS_COUNT << " threads" << endl; auto funcs = get_funcs(); cout << "Removing permutations " << funcs.size() << " functions" << endl; /*vector> permutations; get_permutations<3>(permutations); string function_to_str("000 112 212"); cout << FiniteFunction<3>(function_to_str).apply_permutation(permutations[1]) << endl; cout << FiniteFunction<3>(function_to_str).apply_permutation(permutations[2]) << endl; cout << FiniteFunction<3>(function_to_str).apply_permutation(permutations[3]) << endl; cout << FiniteFunction<3>(function_to_str).apply_permutation(permutations[4]) << endl; cout << FiniteFunction<3>(function_to_str).apply_permutation(permutations[5]) << endl; */ //cout << "022_210_002 -> " << FiniteFunction<3>(string("022 210 002")) << endl; list< set> > function_classes; unordered_set< FiniteFunction, decltype(FiniteFunctionHasher) > allowed_functions(funcs.begin(), funcs.end(), 128, FiniteFunctionHasher); FiniteFunction identical_x(string("000 111 222")); FiniteFunction identical_y(string("012 012 012")); allowed_functions.erase(identical_x); allowed_functions.erase(identical_y); 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); } cout << "Total funcs in list " << task_list.size() << " functions" << endl; total_possible_functions = task_list.size(); tasks_to_extend = task_list.size(); vector< thread > thread_pool; thread task_processer(process_task_lists); 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; // перегоняем список с классами в массив с классами vector< set> > vector_classes( shared_function_classes.begin(), shared_function_classes.end() ); /*// фильтруем перестановки vector> permutations; get_permutations(permutations); map>>::iterator> > classes_per_size; for (auto it = vector_classes.begin(); it != vector_classes.end(); ++it) { classes_per_size[it->size()].push_back(it); } set>>::iterator> classes_to_remove; for (auto&& class_fixed_size: classes_per_size) { typedef pair,vector>>::iterator> sorting_arr_type; cout << class_fixed_size.first << " -> " << class_fixed_size.second.size() << endl; vector< sorting_arr_type > all_class_elements; for (auto &&cur_class_it: class_fixed_size.second) { for (auto&& cur_fn: (*cur_class_it)) { if ( (cur_fn == identical_x) || (cur_fn == identical_y) ) continue; for (auto&& permutation: permutations) all_class_elements.push_back(make_pair( cur_fn.apply_permutation(permutation), cur_class_it )); } } cout << all_class_elements.size() << endl; // сортируем массив sort(all_class_elements.begin(),all_class_elements.end()); for (auto&& el: all_class_elements) cout << el.first << "|"; // выбираем, кого удалить for (size_t i = 0; i < all_class_elements.size(); ++i) { decltype(classes_to_remove) cur_vals_to_remove; size_t j; for ( j = i; (j < all_class_elements.size()) && (all_class_elements.at(i).first == all_class_elements.at(j).first); ++j ) { cout << all_class_elements.at(i).first << "<->" << all_class_elements.at(j).first << " " << (all_class_elements.at(i).second == all_class_elements.at(j).second ) <