#include #include #include #include #include #include #include #include #include #include #include #include #include #include "finite_function.hpp" using namespace std; const CellType CUR_BASE = 3; const int ARGS_COUNT = 2; 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()); } int main() { auto FiniteFunctionHasher = [](const FiniteFunction &f) -> uint32_t { return f.get_hash(); }; 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; //set> allowed_functions(funcs.begin(), funcs.end()); 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); cout << "Total " << allowed_functions.size() << " functions" << endl; std::ofstream f_all_out("all_classes.txt"); while ( allowed_functions.size() > 0 ) { //if (allowed_functions.size() % 10 == 0) //cout << 100 - allowed_functions.size() * 100. / funcs.size() << "%" << endl; auto base_function = *allowed_functions.begin(); allowed_functions.erase(base_function); set< FiniteFunction > func_class = generate_function_class(base_function); func_class.erase(identical_x); func_class.erase(identical_y); //f_all_out << base_function << " -> "; //write_function_class(f_all_out, func_class.begin(), func_class.end()); bool is_need_append = true; vector functions_to_remove; for (auto it = function_classes.begin(); it != 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 ) function_classes.push_back(func_class); for (auto&& to_remove: functions_to_remove) function_classes.erase(to_remove); } cout << function_classes.size() << " functions!" << endl; // перегоняем список с классами в массив с классами vector< set> > vector_classes( function_classes.begin(), 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 ) <