Files
cmc-finite-functions/main.cpp
2018-04-19 18:08:43 +03:00

505 lines
18 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>
#include <thread>
#include <mutex>
#include <atomic>
#include <iterator>
#include "finite_function.hpp"
using namespace std;
const CellType CUR_BASE = 3;
const int ARGS_COUNT = 2;
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());
}
vector <FiniteFunction<CUR_BASE>> possible_functions;
size_t total_possible_functions;
atomic<long> current_function;
mutex possible_functions_mutex;
list< set<FiniteFunction<CUR_BASE>> > shared_function_classes;
mutex shared_functions_mutex;
void do_work() {
list< set<FiniteFunction<CUR_BASE>> > local_function_classes;
FiniteFunction<CUR_BASE> identical_x(string("000 111 222"));
FiniteFunction<CUR_BASE> identical_y(string("012 012 012"));
while ( true ) {
possible_functions_mutex.lock();
if ( current_function >= total_possible_functions ) {
possible_functions_mutex.unlock();
break;
}
FiniteFunction<CUR_BASE> base_function = possible_functions.at(
current_function
);
++current_function;
possible_functions_mutex.unlock();
set< FiniteFunction<CUR_BASE> > func_class = generate_function_class(base_function);
func_class.erase(identical_x);
func_class.erase(identical_y);
bool is_need_append = true;
vector<decltype(local_function_classes)::iterator> functions_to_remove;
for (auto it = local_function_classes.begin(); it != local_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 )
local_function_classes.push_back(func_class);
for (auto&& to_remove: functions_to_remove)
local_function_classes.erase(to_remove);
}
cout << "local " << this_thread::get_id() << ": "
<< local_function_classes.size() << " functions" << endl;
// Сливаем всё вметсе
shared_functions_mutex.lock();
for (auto it_local = local_function_classes.begin(); it_local != local_function_classes.end(); ++it_local) {
auto func_class = *it_local;
bool is_need_append = true;
vector<decltype(local_function_classes)::iterator> 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()
)
) {
// новый класс функций часть уже существующего
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&& to_remove: functions_to_remove)
shared_function_classes.erase(to_remove);
}
shared_functions_mutex.unlock();
cout << "shared_functions_mutex unlocked" << endl;
}
int main() {
auto FiniteFunctionHasher = [](const FiniteFunction<CUR_BASE> &f) -> uint32_t {
return f.get_hash();
};
auto THREADS_COUNT = thread::hardware_concurrency();
cout << "Using " << THREADS_COUNT << " threads" << endl;
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;
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 " << allowed_functions.size() << " functions" << endl;
copy(
allowed_functions.begin(),
allowed_functions.end(),
back_inserter(possible_functions)
);
total_possible_functions = possible_functions.size();
current_function = 0;
vector< thread > thread_pool;
for (size_t i = 0; i < THREADS_COUNT; ++i)
thread_pool.push_back(thread(do_work));
for (auto&& t: thread_pool)
t.join();
cout << "Shared " << shared_function_classes.size() << " functions!" << endl;
// перегоняем список с классами в массив с классами
vector< set<FiniteFunction<CUR_BASE>> > vector_classes(
shared_function_classes.begin(),
shared_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;
}