First working version

This commit is contained in:
2018-04-19 15:48:02 +03:00
parent d3c8d4b8bc
commit 40c5ae2564

566
main.cpp
View File

@@ -1,9 +1,575 @@
#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;
}