843 lines
30 KiB
C++
843 lines
30 KiB
C++
#include <iostream>
|
||
#include <fstream>
|
||
#include <vector>
|
||
#include <deque>
|
||
#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 "al_utility.hpp"
|
||
#include "finite_function.hpp"
|
||
|
||
using namespace std;
|
||
|
||
const CellType CUR_BASE = 4;
|
||
const int ARGS_COUNT = 2;
|
||
const string CLASSES_FILENAME = "classes.txt";
|
||
|
||
FiniteFunction<CUR_BASE> identical_x;
|
||
FiniteFunction<CUR_BASE> identical_y;
|
||
|
||
template <CellType BASE>
|
||
pair<FiniteFunction<BASE>, FiniteFunction<BASE>> get_identicals() {
|
||
if ( BASE == 3 )
|
||
return make_pair(
|
||
FiniteFunction<CUR_BASE>(string("000 111 222")),
|
||
FiniteFunction<CUR_BASE>(string("012 012 012"))
|
||
);
|
||
else if ( BASE == 4 )
|
||
return make_pair(
|
||
FiniteFunction<CUR_BASE>(string("0000 1111 2222 3333")),
|
||
FiniteFunction<CUR_BASE>(string("0123 0123 0123 0123"))
|
||
);
|
||
}
|
||
|
||
struct FunctionTask {
|
||
bool is_finished;
|
||
vector<FiniteFunction<CUR_BASE>> current;
|
||
};
|
||
|
||
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 <class ClassesContainer>
|
||
void append_classes(const ClassesContainer& classes) {
|
||
std::ofstream f_out(CLASSES_FILENAME.c_str(), ios_base::app);
|
||
for (const auto& func_class: classes) {
|
||
write_function_class(f_out, func_class.begin(), func_class.end());
|
||
}
|
||
f_out.close();
|
||
}
|
||
|
||
/*
|
||
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) {
|
||
auto h_res = h(x,y,z);
|
||
is_equaled_x = is_equaled_x && (h_res == x);
|
||
is_equaled_y = is_equaled_y && (h_res == y);
|
||
is_equaled_z = is_equaled_z && (h_res == z);
|
||
}
|
||
if ( !is_equaled_x && !is_equaled_y && !is_equaled_z )
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
template<class FourthArgsFiniteFunction>
|
||
bool is_one_arg_func_fourth(const FourthArgsFiniteFunction &h) {
|
||
bool is_equaled_x = true;
|
||
bool is_equaled_y = true;
|
||
bool is_equaled_z = true;
|
||
bool is_equaled_w = 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) {
|
||
for (CellType w = 0; w < CUR_BASE; ++w) {
|
||
auto h_res = h(x,y,z,w);
|
||
is_equaled_x = is_equaled_x && (h_res == x);
|
||
is_equaled_y = is_equaled_y && (h_res == y);
|
||
is_equaled_z = is_equaled_z && (h_res == z);
|
||
is_equaled_w = is_equaled_w && (h_res == w);
|
||
}
|
||
}
|
||
if ( !is_equaled_x && !is_equaled_y && !is_equaled_z && !is_equaled_w)
|
||
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 FourthArgsFiniteFunction>
|
||
bool is_projection_fourth(const FourthArgsFiniteFunction &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,x,y) == h(x,x,y,x)
|
||
&& h(x,x,y,x) == h(x,y,x,x)
|
||
&& h(x,y,x,x) == h(y,x,x,x)
|
||
&& h(y,x,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;
|
||
|
||
auto h_res = h(x,y,z);
|
||
is_equaled_x = is_equaled_x && (h_res == x);
|
||
is_equaled_y = is_equaled_y && (h_res == y);
|
||
is_equaled_z = is_equaled_z && (h_res == z);
|
||
if (
|
||
!is_equaled_x
|
||
&& !is_equaled_y
|
||
&& !is_equaled_z
|
||
)
|
||
return false;
|
||
}
|
||
return is_equaled_x || is_equaled_y || is_equaled_z;
|
||
}
|
||
|
||
template<class FourthArgsFiniteFunction>
|
||
bool is_semiprojection_fourth(const FourthArgsFiniteFunction &h) {
|
||
bool is_equaled_x = true;
|
||
bool is_equaled_y = true;
|
||
bool is_equaled_z = true;
|
||
bool is_equaled_w = 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) {
|
||
for (CellType w = 0; w < CUR_BASE; ++w) {
|
||
set<CellType> s;
|
||
s.insert(x);
|
||
s.insert(y);
|
||
s.insert(z);
|
||
s.insert(w);
|
||
if ( s.size() == 4 )
|
||
// если все различны, то не рассматриваем
|
||
continue;
|
||
|
||
auto h_res = h(x,y,z,w);
|
||
is_equaled_x = is_equaled_x && (h_res == x);
|
||
is_equaled_y = is_equaled_y && (h_res == y);
|
||
is_equaled_z = is_equaled_z && (h_res == z);
|
||
is_equaled_w = is_equaled_w && (h_res == w);
|
||
if (
|
||
!is_equaled_x
|
||
&& !is_equaled_y
|
||
&& !is_equaled_z
|
||
&& !is_equaled_w
|
||
)
|
||
return false;
|
||
}
|
||
}
|
||
return is_equaled_x || is_equaled_y || is_equaled_z || is_equaled_w;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
if ( CUR_BASE == 4 ) {
|
||
auto g_1 = [f, h_1](const CellType x, const CellType y, CellType z, CellType u) -> CellType {
|
||
return f( h_1(x,y,z), u );
|
||
};
|
||
if ( !is_one_arg_func_fourth(g_1) ) {
|
||
if ( is_projection_fourth(g_1) || is_semiprojection_fourth(g_1) )
|
||
return false;
|
||
}
|
||
|
||
auto g_2 = [f, h_2](const CellType x, const CellType y, CellType z, CellType u) -> CellType {
|
||
return f( h_2(x,y,z), u );
|
||
};
|
||
if ( !is_one_arg_func_fourth(g_2) ) {
|
||
if ( is_projection_fourth(g_2) || is_semiprojection_fourth(g_2) )
|
||
return false;
|
||
}
|
||
|
||
auto g_3 = [f, h_3](const CellType x, const CellType y, CellType z, CellType u) -> CellType {
|
||
return f( h_3(x,y,z), u );
|
||
};
|
||
if ( !is_one_arg_func_fourth(g_3) ) {
|
||
if ( is_projection_fourth(g_3) || is_semiprojection_fourth(g_3) )
|
||
return false;
|
||
}
|
||
|
||
auto g_4 = [f, h_4](const CellType x, const CellType y, CellType z, CellType u) -> CellType {
|
||
return f( h_4(x,y,z), u );
|
||
};
|
||
if ( !is_one_arg_func_fourth(g_4) ) {
|
||
if ( is_projection_fourth(g_4) || is_semiprojection_fourth(g_4) )
|
||
return false;
|
||
}
|
||
|
||
auto g_both = [f](const CellType x, const CellType y, CellType z, CellType u) -> CellType {
|
||
return f( f(x,y), f(z,u) );
|
||
};
|
||
if ( !is_one_arg_func_fourth(g_both) ) {
|
||
if ( is_projection_fourth(g_both) || is_semiprojection_fourth(g_both) )
|
||
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());
|
||
}
|
||
|
||
|
||
// Возвращает новый функциональный класс, размером не сильно больше, чем max_size
|
||
// Вторым результатом возвращает true, если вычисления закончились успешно
|
||
// и false, если прервались по достижению max_size
|
||
template <CellType BASE>
|
||
pair<vector<FiniteFunction<BASE>>, bool> extend_function_class(
|
||
const vector<FiniteFunction<BASE>>& base_class,
|
||
size_t max_size
|
||
) {
|
||
if ( base_class.size() >= max_size ) {
|
||
return make_pair(
|
||
vector<FiniteFunction<BASE>>(base_class),
|
||
false
|
||
);
|
||
}
|
||
auto FiniteFunctionHasher = [](const FiniteFunction<BASE> &f) -> uint32_t {
|
||
return f.get_hash();
|
||
};
|
||
unordered_set<
|
||
FiniteFunction<CUR_BASE>,
|
||
decltype(FiniteFunctionHasher)
|
||
> func_class(1024, FiniteFunctionHasher);
|
||
for (auto&& base_function: base_class)
|
||
func_class.insert(base_function);
|
||
|
||
bool is_finished = false;
|
||
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());
|
||
for (const auto& f_applied: func_class) {
|
||
FiniteFunction<BASE> f_left;
|
||
f_left = f_main.apply_to_first_partial(f_applied);
|
||
new_funcs.insert(f_left);
|
||
}
|
||
}
|
||
new_funcs.erase(identical_x);
|
||
new_funcs.erase(identical_y);
|
||
if ( new_funcs.size() == last_size ) {
|
||
is_finished = true;
|
||
break;
|
||
}
|
||
|
||
func_class.insert(new_funcs.begin(), new_funcs.end());
|
||
last_size = new_funcs.size();
|
||
|
||
// слишком много насчитали -- выходим
|
||
if ( func_class.size() > max_size ) {
|
||
break;
|
||
}
|
||
}
|
||
vector<FiniteFunction<BASE>> res(func_class.begin(), func_class.end());
|
||
res.shrink_to_fit();
|
||
return make_pair(
|
||
res,
|
||
is_finished
|
||
);
|
||
}
|
||
|
||
|
||
template <class Iterable>
|
||
bool is_bad_class(
|
||
const Iterable& func_class,
|
||
const set<FiniteFunction<CUR_BASE>>& bad_funcs
|
||
) {
|
||
for (auto&& func: func_class)
|
||
if ( bad_funcs.find(func) != bad_funcs.end() )
|
||
return true;
|
||
return false;
|
||
}
|
||
|
||
|
||
size_t total_possible_functions;
|
||
atomic<long> completed_tasks;
|
||
atomic<long> tasks_to_extend; // количество тасков, которые не обработаны
|
||
list< vector<FiniteFunction<CUR_BASE>> > shared_function_classes;
|
||
mutex shared_functions_mutex;
|
||
|
||
|
||
deque<FunctionTask> task_list;
|
||
mutex task_mutex;
|
||
|
||
vector<FunctionTask> processed_task_list;
|
||
mutex processed_task_mutex;
|
||
|
||
set<FiniteFunction<CUR_BASE>> bad_functions;
|
||
set<FiniteFunction<CUR_BASE>> good_functions;
|
||
atomic<int> current_max_coeff;
|
||
|
||
void do_work() {
|
||
std::chrono::milliseconds SLEEP_TIME(10);
|
||
while ( true ) {
|
||
FunctionTask task;
|
||
task_mutex.lock();
|
||
if ( task_list.begin() != task_list.end() ) {
|
||
task = task_list.front();
|
||
task_list.pop_front();
|
||
task_mutex.unlock();
|
||
} else {
|
||
task_mutex.unlock();
|
||
if ( completed_tasks < total_possible_functions ) {
|
||
// Не все таски, подождём, пока добавят ещё
|
||
std::this_thread::sleep_for(SLEEP_TIME);
|
||
continue;
|
||
} else {
|
||
cout << "thread " << this_thread::get_id() << ": "
|
||
<< " finished" << endl;
|
||
break;
|
||
}
|
||
}
|
||
|
||
tie(task.current, task.is_finished) = extend_function_class(
|
||
task.current,
|
||
get_math_coeff(current_max_coeff)
|
||
);
|
||
processed_task_mutex.lock();
|
||
processed_task_list.push_back(task);
|
||
processed_task_mutex.unlock();
|
||
--tasks_to_extend;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
void process_task_lists() {
|
||
cout << "processing starts " << endl;
|
||
|
||
std::chrono::milliseconds SLEEP_TIME(10);
|
||
|
||
vector<FunctionTask> local_processed_tasks;
|
||
|
||
while ( completed_tasks < total_possible_functions ) {
|
||
if ( tasks_to_extend ) {
|
||
// подождём, пока не закончатся таски в очереди
|
||
std::this_thread::sleep_for(SLEEP_TIME);
|
||
continue;
|
||
}
|
||
task_mutex.lock();
|
||
if ( task_list.size() != 0 )
|
||
cout << "IMPOSSIBLE task_list.size!!" << endl;
|
||
task_list.clear();
|
||
task_list.shrink_to_fit();
|
||
task_mutex.unlock();
|
||
|
||
// опустошим выполненные таски
|
||
processed_task_mutex.lock();
|
||
for (auto && task: processed_task_list)
|
||
local_processed_tasks.push_back(task);
|
||
processed_task_list.clear();
|
||
processed_task_list.shrink_to_fit();
|
||
processed_task_mutex.unlock();
|
||
|
||
cout << "sorting finished of "<< local_processed_tasks.size() << endl;
|
||
size_t total_funcs = 0;
|
||
for (auto&& task: local_processed_tasks)
|
||
total_funcs += task.current.size();
|
||
cout << "estimated size: "
|
||
<< sizeof(FunctionTask) * total_funcs / 1024 / 1024 << " MB" << endl;
|
||
// Обеспечим увеличение размеров, чтобы не было проблем со включением одного
|
||
// в другое
|
||
sort(
|
||
local_processed_tasks.begin(),
|
||
local_processed_tasks.end(),
|
||
[](const FunctionTask& a, const FunctionTask& b) {
|
||
return a.current.size() < b.current.size();
|
||
}
|
||
);
|
||
|
||
// сохраним, чем должен был равняться максимальный размер
|
||
auto last_math_coeff = get_math_coeff(current_max_coeff);
|
||
// а для всех новых увеличим его
|
||
++current_max_coeff;
|
||
|
||
for ( auto&& task: local_processed_tasks ) {
|
||
// если в каких-то больше, чем положено, то не трогаем их
|
||
if ( task.current.size() > last_math_coeff)
|
||
break;
|
||
if ( !task.is_finished ) {
|
||
if ( is_bad_class(task.current, bad_functions) ) {
|
||
//cout << "bad class" << endl;
|
||
++completed_tasks;
|
||
if ( print_progress(completed_tasks, total_possible_functions) ) {
|
||
append_classes(shared_function_classes);
|
||
shared_function_classes.clear();
|
||
}
|
||
} else {
|
||
task_mutex.lock();
|
||
++tasks_to_extend;
|
||
task_list.push_back(task);
|
||
task_mutex.unlock();
|
||
}
|
||
|
||
} else {
|
||
//cout << "task finished, appending" << endl;
|
||
++completed_tasks;
|
||
if ( print_progress(completed_tasks, total_possible_functions) ) {
|
||
append_classes(shared_function_classes);
|
||
shared_function_classes.clear();
|
||
}
|
||
sort(task.current.begin(), task.current.end());
|
||
auto func_class = task.current;
|
||
bool is_need_append = true;
|
||
vector<decltype(shared_function_classes)::iterator> functions_to_remove;
|
||
|
||
is_need_append = !is_bad_class(task.current, bad_functions);
|
||
|
||
for (auto&& f: task.current)
|
||
if ( good_functions.find(f) == good_functions.end() ) {
|
||
is_need_append = false;
|
||
break;
|
||
}
|
||
|
||
|
||
/*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()
|
||
)
|
||
) {
|
||
cout << "includes!!" << endl;
|
||
// новый класс функций часть уже существующего
|
||
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 )
|
||
for (auto&& func: func_class)
|
||
bad_functions.insert(func);
|
||
if ( is_need_append ) {
|
||
shared_function_classes.push_back(func_class);
|
||
}
|
||
for (auto&& to_remove: functions_to_remove) {
|
||
shared_function_classes.erase(to_remove);
|
||
cout << "Removing class from shared_function_classes" << endl;
|
||
}
|
||
}
|
||
}
|
||
local_processed_tasks.erase(
|
||
remove_if(
|
||
local_processed_tasks.begin(),
|
||
local_processed_tasks.end(),
|
||
[last_math_coeff](const FunctionTask& task) {
|
||
return task.current.size() <= last_math_coeff;
|
||
}),
|
||
local_processed_tasks.end()
|
||
);
|
||
local_processed_tasks.shrink_to_fit();
|
||
|
||
// Поспим, чтобы не работать слишком часто
|
||
std::this_thread::sleep_for(SLEEP_TIME);
|
||
}
|
||
}
|
||
|
||
|
||
int main() {
|
||
tie(identical_x, identical_y) = get_identicals<CUR_BASE>();
|
||
|
||
cout << "sizeof FiniteFunction<" << (int)CUR_BASE << "> = "
|
||
<< sizeof(FiniteFunction<CUR_BASE>) << endl;
|
||
cout << "sizeof FunctionTask = "<< sizeof(FunctionTask) << endl;
|
||
auto FiniteFunctionHasher = [](const FiniteFunction<CUR_BASE> &f) -> uint32_t {
|
||
return f.get_hash();
|
||
};
|
||
|
||
auto THREADS_COUNT = max(static_cast<int>(thread::hardware_concurrency()), 2);
|
||
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);
|
||
|
||
allowed_functions.erase(identical_x);
|
||
allowed_functions.erase(identical_y);
|
||
|
||
completed_tasks = 0;
|
||
current_max_coeff = 1;
|
||
for (auto&& func: allowed_functions) {
|
||
good_functions.insert(func);
|
||
FunctionTask task;
|
||
task.current = {func};
|
||
task.is_finished = false;
|
||
task_list.push_back(task);
|
||
}
|
||
|
||
cout << "Total funcs in list " << task_list.size() << " functions" << endl;
|
||
|
||
total_possible_functions = task_list.size();
|
||
tasks_to_extend = task_list.size();
|
||
vector< thread > thread_pool;
|
||
thread task_processer(process_task_lists);
|
||
|
||
// удалим старый контент
|
||
std::ofstream f_out("classes.txt");
|
||
f_out.close();
|
||
|
||
for (int i = 0; i < THREADS_COUNT - 1; ++i)
|
||
thread_pool.push_back(thread(do_work));
|
||
|
||
for (auto&& t: thread_pool)
|
||
t.join();
|
||
|
||
task_processer.join();
|
||
|
||
cout << "Shared " << shared_function_classes.size() << " functions!" << endl;
|
||
// перегоняем список с классами в массив с классами
|
||
vector< vector<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);
|
||
}*/
|
||
append_classes(vector_classes);
|
||
return 0;
|
||
}
|