diff --git a/main.cpp b/main.cpp index 1298bf1..f250b0d 100644 --- a/main.cpp +++ b/main.cpp @@ -1,9 +1,575 @@ #include +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace std; +typedef int8_t CellType; +const CellType CUR_BASE = 3; +const int ARGS_COUNT = 2; + +// Пока положим, что только два аргумента, чтобы упростить реализацию +template +class FiniteFunction { + public: + FiniteFunction() {} + + // Устанавливает результат функции, использую другую функцию как + // инициализатор + template + FiniteFunction(Callable initer) : _num(0) { + for (CellType first = 0; first < BASE; ++first) + for (CellType second = 0; second < BASE; ++second) { + auto inited_result = initer(first, second); + set_result(first, second, inited_result); + } + update_num(); + } + + explicit FiniteFunction(string text_repr) { + size_t cur_ind = 0; + for (auto ch: text_repr) { + if ( !isdigit(ch) ) + continue; + _results.at(cur_ind) = stoi(string(1, ch)); + ++cur_ind; + } + update_num(); + } + ~FiniteFunction() {} + + // Устанавливает результат функции по двум аргументам + void set_result(CellType first, CellType second, CellType result) { + _results[get_index(first, second)] = result; + } + + int operator() (CellType first, CellType second) const { + return _results[get_index(first, second)]; + } + + bool operator < (const FiniteFunction &f) const { + return _num < f._num; + } + + bool operator == (const FiniteFunction &f) const { + return _num == f._num; + } + + FiniteFunction reversed() const { + // f(x,y) -> f(y,x) + FiniteFunction res; + for (CellType first = 0; first < BASE; ++first) + for (CellType second = 0; second < BASE; ++second) { + res.set_result(first, second, (*this)(second, first)); + } + res.update_num(); + return res; + } + + FiniteFunction equaled() const { + // f(x,y) -> f(x,x) + FiniteFunction res; + for (CellType first = 0; first < BASE; ++first) + for (CellType second = 0; second < BASE; ++second) { + res.set_result(first, second, (*this)(first, first)); + } + res.update_num(); + return res; + } + + FiniteFunction apply_to_first_partial(const FiniteFunction &g) const { + // -> this(g(x,y), x) + FiniteFunction res; + for (CellType first = 0; first < BASE; ++first) + for (CellType second = 0; second < BASE; ++second) { + res.set_result(first, second, (*this)(g(first, second), first)); + } + res.update_num(); + return res; + } + + tuple apply_to_first(const FiniteFunction &g) const { + // -> this(g(x,y), x), this(g(x,y), y) + FiniteFunction res_1, res_2; + for (CellType first = 0; first < BASE; ++first) + for (CellType second = 0; second < BASE; ++second) { + res_1.set_result(first, second, (*this)(g(first, second), first)); + res_2.set_result(first, second, (*this)(g(first, second), second)); + } + res_1.update_num(); + res_2.update_num(); + return make_tuple(res_1, res_2); + } + + FiniteFunction apply_two(const FiniteFunction &g, const FiniteFunction &h) const { + FiniteFunction res; + for (CellType first = 0; first < BASE; ++first) + for (CellType second = 0; second < BASE; ++second) { + res.set_result( + first, + second, + (*this)(g(first, second), h(first, second)) + ); + } + res.update_num(); + return res; + } + + FiniteFunction apply_permutation(array perm) const { + FiniteFunction res; + for (CellType first = 0; first < BASE; ++first) + for (CellType second = 0; second < BASE; ++second) { + res.set_result( + first, + second, + find( + perm.begin(), + perm.end(), + (*this)(perm[first], perm[second]) + ) - perm.begin() + ); + } + res.update_num(); + return res; + } + + uint32_t get_hash() const { + return _num; + } + + static size_t get_index(CellType first, CellType second) { + return first * BASE + second; + } + template + friend ostream& operator << (ostream& os, const FiniteFunction<_BASE> &f); + private: + void update_num() { + _num = 0; + for (auto&& val: _results) { + _num *= BASE; + _num += val; + } + } + uint32_t _num; + array _results; +}; + + +template +ostream& operator << (ostream& os, const FiniteFunction &f){ + for (int first = 0; first < BASE; ++first) { + for (int second = 0; second < BASE; ++second) { + os << f(first, second); + } + if ( first != BASE-1 ) + os << " "; + } + return os; +} + +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 ) + <