Files
cmc-finite-functions/main.cpp
2018-04-19 15:48:02 +03:00

576 lines
21 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <array>
#include <map>
#include <set>
#include <unordered_set>
#include <utility>
#include <cstring>
#include <functional>
#include <list>
#include <cctype>
using namespace std;
typedef int8_t CellType;
const CellType CUR_BASE = 3;
const int ARGS_COUNT = 2;
// Пока положим, что только два аргумента, чтобы упростить реализацию
template <CellType BASE>
class FiniteFunction {
public:
FiniteFunction() {}
// Устанавливает результат функции, использую другую функцию как
// инициализатор
template <class Callable>
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<FiniteFunction, FiniteFunction> 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<int, BASE> 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 <CellType _BASE>
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<CellType, BASE*BASE> _results;
};
template <CellType BASE>
ostream& operator << (ostream& os, const FiniteFunction<BASE> &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 <size_t BASE>
class FixedIniter {
public:
// rules это отображение обязательных значений аргументов, к
// значениями функции, которые не должны при них изменяться
explicit FixedIniter(map<pair<size_t, size_t>, 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<BASE>::get_index(arg1, arg2)) = value;
_used_indexes.insert(FiniteFunction<BASE>::get_index(arg1, arg2));
}
}
int operator() (int first, int second) const {
return _cur_values[FiniteFunction<BASE>::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<int>(BASE) - 1);
if ( is_overflow )
_cur_values.at(i) = 0;
else
return true;
}
throw "Wrong logic";
}
private:
set<size_t> _used_indexes;
map<pair<size_t, size_t>, int> _rules;
vector<int> _cur_values;
};
template <class Iterable>
void write_function_class(ofstream &f_out, Iterable begin, Iterable end) {
for (;begin != end; ++begin)
f_out << *begin << " ";
f_out << endl;
}
/*
template <int BASE>
void get_permutations(vector<array<int, BASE>> &permutations) {
permutations.clear();
array<int, BASE> 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<class TripleArgsFiniteFunction>
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<class TripleArgsFiniteFunction>
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<class TripleArgsFiniteFunction>
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<CUR_BASE> &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 <CellType BASE>
vector<FiniteFunction<BASE>> get_funcs() {
size_t count = 0;
map<pair<size_t, size_t>, int> rules;
for (int i = 0; i < BASE; ++i)
rules[make_pair<size_t, size_t>(i,i)] = i;
FixedIniter<BASE> initer(rules);
//vector<array<int, BASE>> permutations;
//get_permutations<BASE>(permutations);
vector<FiniteFunction<BASE>> funcs;
set< FiniteFunction<BASE> > permutated_funcs;
do {
++count;
auto cur_func = FiniteFunction<BASE>(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<BASE> & 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 <CellType BASE>
set<FiniteFunction<BASE>> generate_function_class(FiniteFunction<BASE> base_function) {
auto FiniteFunctionHasher = [](const FiniteFunction<BASE> &f) -> uint32_t {
return f.get_hash();
};
unordered_set<
FiniteFunction<CUR_BASE>,
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<CUR_BASE>,
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<BASE> f_left_1, f_left_2;
//tie(f_left_1, f_left_2) = f_main.apply_to_first(f_applied);
FiniteFunction<BASE> 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<FiniteFunction<BASE>>(func_class.begin(), func_class.end());
}
int main() {
auto FiniteFunctionHasher = [](const FiniteFunction<CUR_BASE> &f) -> uint32_t {
return f.get_hash();
};
auto funcs = get_funcs<CUR_BASE>();
cout << "Removing permutations " << funcs.size() << " functions" << endl;
/*vector<array<int, 3>> 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<FiniteFunction<3>> allowed_functions(funcs.begin(), funcs.end());
list< set<FiniteFunction<CUR_BASE>> > function_classes;
unordered_set<
FiniteFunction<CUR_BASE>,
decltype(FiniteFunctionHasher)
> allowed_functions(funcs.begin(), funcs.end(), 128, FiniteFunctionHasher);
FiniteFunction<CUR_BASE> identical_x(string("000 111 222"));
FiniteFunction<CUR_BASE> 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<CUR_BASE> > 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<decltype(function_classes)::iterator> 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<FiniteFunction<CUR_BASE>> > vector_classes(
function_classes.begin(),
function_classes.end()
);
/*// фильтруем перестановки
vector<array<int, CUR_BASE>> permutations;
get_permutations<CUR_BASE>(permutations);
map<size_t, vector<vector<set<FiniteFunction<CUR_BASE>>>::iterator> > classes_per_size;
for (auto it = vector_classes.begin(); it != vector_classes.end(); ++it) {
classes_per_size[it->size()].push_back(it);
}
set<vector<set<FiniteFunction<CUR_BASE>>>::iterator> classes_to_remove;
for (auto&& class_fixed_size: classes_per_size) {
typedef pair<FiniteFunction<CUR_BASE>,vector<set<FiniteFunction<CUR_BASE>>>::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 )
<<endl;
cur_vals_to_remove.insert(all_class_elements.at(j).second);
}
for (
auto it = next(cur_vals_to_remove.begin());
it != cur_vals_to_remove.end();
++it
) {
classes_to_remove.insert(*it);
}
cout << "size " << cur_vals_to_remove.size() << endl;
i = j;
}
}
cout << "classes_to_remove.size() = " <<classes_to_remove.size() << endl;
// удаляем
{
decltype(vector_classes) new_vector_classes;
for (auto it = vector_classes.begin(); it != vector_classes.end(); ++it)
if ( classes_to_remove.find(it) == classes_to_remove.end() )
new_vector_classes.push_back(*it);
swap(new_vector_classes, vector_classes);
}*/
std::ofstream f_out("classes.txt");
for (const auto& func_class: vector_classes) {
write_function_class(f_out, func_class.begin(), func_class.end());
}
f_out.close();
return 0;
}