261 lines
11 KiB
C++
261 lines
11 KiB
C++
#include <iostream>
|
|
#include <cstdint>
|
|
#include <vector>
|
|
#include <set>
|
|
#include <cassert>
|
|
#include <fstream>
|
|
|
|
#include "al_function.hpp"
|
|
#include "al_bool_matrix.hpp"
|
|
|
|
using namespace std;
|
|
|
|
typedef uint16_t Storage;
|
|
const size_t ARGS_COUNT = 3;
|
|
const size_t FUNCTION_LEN = 1ll << ARGS_COUNT;
|
|
const size_t FUNCTIONS_COUNT = 1ll << FUNCTION_LEN;
|
|
typedef Function<Storage, FUNCTION_LEN> MyFunction;
|
|
typedef BoolSquareMatrix<Storage, ARGS_COUNT> MyMatrix;
|
|
|
|
void test_function() {
|
|
Function<uint16_t, 8> f_8(16);
|
|
assert(("sizeof(sizeof(Function<uint16_t, 8>)", sizeof(Function<uint16_t, 8>)==2));
|
|
assert(("f_8(16) = 00010000", "00010000" == f_8.string()));
|
|
assert(("f_8(15) = 00001111", "00001111" == Function<uint16_t, 8>(15).string()));
|
|
|
|
assert(("converting 01001001", Function<uint16_t, 8>("01001001").string() == "01001001"));
|
|
assert(("converting 00000000", Function<uint16_t, 8>("00000000").string() == "00000000"));
|
|
assert(("converting 11111111", Function<uint16_t, 8>("11111111").string() == "11111111"));
|
|
|
|
Function<uint16_t, 8> a(12);
|
|
Function<uint16_t, 8> b(5);
|
|
assert(("a = 00001100", a.string() == "00001100"));
|
|
assert(("b = 00000101", b.string() == "00000101"));
|
|
assert(("a ^ b = 00001001", (a xor b).string() == "00001001"));
|
|
assert(("a | b = 00001101", (a or b).string() == "00001101"));
|
|
assert(("a & b = 00000100", (a and b).string() == "00000100"));
|
|
// no changed in this objects
|
|
assert(("a = 00001100", a.string() == "00001100"));
|
|
assert(("b = 00000101", b.string() == "00000101"));
|
|
|
|
Function<uint16_t, 8> negation(107);
|
|
assert(("f(x_1 + 1 + 1, x_2, x_3) == f", negation == negation.var_negation(1).var_negation(1)));
|
|
assert(("f(x_1, x_2 + 1 + 1, x_3) == f", negation == negation.var_negation(2).var_negation(2)));
|
|
assert(("f(x_1, x_2, x_3 + 1 + 1) == f", negation == negation.var_negation(3).var_negation(3)));
|
|
/*
|
|
cout << "f(x_1, x_2, x_3) = " << negation.string() << endl;
|
|
cout << "f(x_1 + 1, x_2, x_3) = " << negation.var_negation(1).string() << endl;
|
|
cout << "f(x_1 + 1 + 1, x_2, x_3) = " << negation.var_negation(1).var_negation(1).string() << endl;
|
|
cout << "f(x_1, x_2 + 1, x_3) = " << negation.var_negation(2).string() << endl;
|
|
cout << "f(x_1, x_2 + 1 + 1, x_3) = " << negation.var_negation(2).var_negation(2).string() << endl;
|
|
cout << "f(x_1, x_2, x_3 + 1) = " << negation.var_negation(3).string() << endl;
|
|
*/
|
|
|
|
BoolSquareMatrix<uint16_t, 3> ones_matrix((1 << 10) - 1), i_matrix(0b100010001), minus_i_matrix(0b001010100);
|
|
assert(ones_matrix.string("") == "111111111");
|
|
assert(ones_matrix.get_determinant() == 0);
|
|
assert(i_matrix.string("") == "100010001");
|
|
assert(i_matrix.get_determinant() == 1);
|
|
assert(minus_i_matrix.string("") == "001010100");
|
|
assert(minus_i_matrix.get_determinant() == uint16_t(-1));
|
|
|
|
cout << "self-test passed" << endl;
|
|
}
|
|
|
|
template<class STORAGE, size_t ARGUMENTS_COUNT, class Callable>
|
|
Function<STORAGE, 1ll << ARGUMENTS_COUNT > get_function_from_callable(Callable INPUT_FUNCTION) {
|
|
const STORAGE values_count = 1ll << ARGUMENTS_COUNT;
|
|
STORAGE function_values(0);
|
|
for (STORAGE cur_vec_value = values_count; cur_vec_value != 0; --cur_vec_value) {
|
|
BoolVector<STORAGE, ARGUMENTS_COUNT> vec(cur_vec_value - 1);
|
|
function_values *= 2;
|
|
function_values += INPUT_FUNCTION(vec);
|
|
}
|
|
return Function<STORAGE, values_count >(function_values);
|
|
}
|
|
|
|
vector< MyMatrix > get_good_matrices() {
|
|
vector< MyMatrix > res;
|
|
for (size_t cur_val = 1ll << (ARGS_COUNT * ARGS_COUNT); cur_val != 0; --cur_val) {
|
|
MyMatrix cur_matrix(cur_val);
|
|
if ( cur_matrix.get_determinant() != 0 )
|
|
res.push_back(cur_matrix);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
vector<MyFunction> get_function_class(MyFunction f, const vector< MyMatrix >& tranformations, ostream& out) {
|
|
set<MyFunction> cur_res;
|
|
for (Storage i = 0; i < FUNCTION_LEN; ++i) {
|
|
MyFunction cur_f = f;
|
|
for (Storage arg_ind = 0; arg_ind < ARGS_COUNT; ++arg_ind)
|
|
if ( (i >> arg_ind) % 2 == 1 )
|
|
cur_f = cur_f.var_negation(arg_ind + 1);
|
|
cur_res.insert(cur_f);
|
|
}
|
|
|
|
set<MyFunction> transformed_res;
|
|
for (auto f: cur_res) {
|
|
for (auto transformation: tranformations) {
|
|
MyFunction linear_transformed = get_function_from_callable<Storage, ARGS_COUNT>(
|
|
[transformation, f](const BoolVector<Storage, ARGS_COUNT> vec) -> Storage {
|
|
return f.at((transformation * vec).get_value());
|
|
}
|
|
);
|
|
bool is_inserted = transformed_res.insert(linear_transformed).second;
|
|
if ( is_inserted ) {
|
|
out << linear_transformed.string() << " = " << f.string() << " with ("
|
|
<< transformation.string(",") << ")" << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
return vector<MyFunction>(transformed_res.begin(), transformed_res.end());
|
|
}
|
|
|
|
|
|
vector<MyFunction> get_linear_components() {
|
|
vector<MyFunction> res;
|
|
if ( ARGS_COUNT == 3 ) {
|
|
res.push_back(MyFunction("11111111")); // f = 1
|
|
res.push_back(MyFunction("00001111")); // f = x_1
|
|
res.push_back(MyFunction("00110011")); // f = x_2
|
|
res.push_back(MyFunction("01010101")); // f = x_3
|
|
} else if ( ARGS_COUNT == 4 ) {
|
|
res.push_back(MyFunction("1111111111111111")); // f = 1
|
|
res.push_back(MyFunction("0000000011111111")); // f = x_1
|
|
res.push_back(MyFunction("0000111100001111")); // f = x_2
|
|
res.push_back(MyFunction("0011001100110011")); // f = x_3
|
|
res.push_back(MyFunction("0101010101010101")); // f = x_4
|
|
} else if ( ARGS_COUNT == 5 ) {
|
|
res.push_back(MyFunction("11111111111111111111111111111111")); // f = 1
|
|
res.push_back(MyFunction("00000000000000001111111111111111")); // f = x_1
|
|
res.push_back(MyFunction("00000000111111110000000011111111")); // f = x_2
|
|
res.push_back(MyFunction("00001111000011110000111100001111")); // f = x_3
|
|
res.push_back(MyFunction("00110011001100110011001100110011")); // f = x_4
|
|
res.push_back(MyFunction("01010101010101010101010101010101")); // f = x_5
|
|
} else {
|
|
assert (("bad args_count", false));
|
|
}
|
|
return res;
|
|
}
|
|
|
|
vector<MyFunction> get_linear_combinations(const vector<MyFunction> &linear_components) {
|
|
set<MyFunction> res(linear_components.begin(), linear_components.end());
|
|
bool is_added = true;
|
|
while ( is_added ) {
|
|
is_added = false;
|
|
for (auto el_first: res)
|
|
for (auto el_second: res) {
|
|
bool is_added_now = res.insert(el_first xor el_second).second;
|
|
is_added = is_added or is_added_now;
|
|
}
|
|
}
|
|
return vector<MyFunction>(res.begin(), res.end());
|
|
}
|
|
|
|
vector<MyFunction> get_all_monomials(const vector<MyFunction> &linear_combinations) {
|
|
set<MyFunction> res(linear_combinations.begin(), linear_combinations.end());
|
|
bool is_added = true;
|
|
while ( is_added ) {
|
|
is_added = false;
|
|
for (auto el_first: res)
|
|
for (auto el_second: res) {
|
|
bool is_added_now = res.insert(el_first and el_second).second;
|
|
is_added = is_added or is_added_now;
|
|
}
|
|
}
|
|
return vector<MyFunction>(res.begin(), res.end());
|
|
}
|
|
|
|
void fill_ranks(vector<MyFunction> monomials) {
|
|
vector<int8_t> used_map(FUNCTIONS_COUNT, 0);
|
|
size_t functions_remains = FUNCTIONS_COUNT;
|
|
|
|
ofstream f_out("out.txt");
|
|
vector< vector<MyFunction> > ranks;
|
|
ranks.push_back(vector<MyFunction>()); // empty set
|
|
ranks.push_back(monomials); // empty set
|
|
|
|
cout << "rank index = " << 1 << endl;
|
|
for (auto el: monomials) {
|
|
--functions_remains;
|
|
used_map.at(el.value()) = 1;
|
|
}
|
|
size_t total_ranks = 1;
|
|
for (total_ranks = 1; functions_remains; ++total_ranks) {
|
|
ranks.push_back(vector<MyFunction>());
|
|
cout << "rank index = " << total_ranks << " remains: " << functions_remains << endl;
|
|
for (auto el_first: ranks.at(total_ranks - 1)) {
|
|
for (auto el_second: ranks.at(1)) {
|
|
MyFunction res_el = el_first xor el_second;
|
|
if ( used_map[res_el.value()] == 0 ) {
|
|
--functions_remains;
|
|
used_map.at(res_el.value()) = total_ranks;
|
|
ranks.at(total_ranks).push_back(res_el);
|
|
}
|
|
}
|
|
}
|
|
if ( total_ranks - 1 > 1 )
|
|
ranks.at(total_ranks - 1).clear(); // больше не нужен
|
|
cout << "size for rank " << total_ranks << " is " << ranks.at(total_ranks).size() << endl;
|
|
}
|
|
|
|
auto possible_tranformations = get_good_matrices();
|
|
cout << "Total " << possible_tranformations.size() << " linear tranformations" << endl;
|
|
//for (auto el: possible_tranformations)
|
|
// cout << el.string(",") <<endl;
|
|
|
|
ranks.clear();
|
|
for (auto i = total_ranks - 1; i != 0; --i)
|
|
ranks.push_back(vector<MyFunction>()); // empty set
|
|
size_t total_functions = 0;
|
|
for (size_t fn_value = 0; fn_value < used_map.size(); ++fn_value) {
|
|
auto cur_rank = used_map[fn_value];
|
|
if ( not cur_rank )
|
|
continue;
|
|
++total_functions;
|
|
MyFunction current_fn(fn_value);
|
|
vector<MyFunction> function_class = get_function_class(
|
|
current_fn, possible_tranformations, f_out
|
|
);
|
|
cout << "size of function class is " << function_class.size() << endl;
|
|
f_out << "Function class for " << current_fn.string() << ": (" << endl;
|
|
for (auto marked_function: function_class) {
|
|
used_map[marked_function.value()] = 0;
|
|
f_out << " " << marked_function.string() << endl;
|
|
}
|
|
f_out << ")" << endl;
|
|
ranks.at(cur_rank - 1).push_back(current_fn);
|
|
}
|
|
cout << "total unique functions: " << total_functions << endl;
|
|
for (size_t rank_ind = 0; rank_ind < ranks.size(); ++rank_ind) {
|
|
f_out << "rank index = " << rank_ind + 1 << endl;
|
|
for (auto f: ranks.at(rank_ind))
|
|
f_out << f.string() << endl;
|
|
}
|
|
f_out.close();
|
|
}
|
|
|
|
int main() {
|
|
test_function();
|
|
cout << "using " << sizeof(Storage) << " bytes for storage" << endl;
|
|
cout << FUNCTIONS_COUNT << " functions with " << ARGS_COUNT
|
|
<< " arguments and " << FUNCTION_LEN << " values" << endl;
|
|
|
|
auto linear_components = get_linear_components();
|
|
cout << "Linear components: " << endl;
|
|
for (auto el: linear_components)
|
|
cout << el.string() << endl;
|
|
|
|
auto linear_combinations = get_linear_combinations(linear_components);
|
|
cout << "Linear combinations: " << linear_combinations.size() << endl;
|
|
|
|
auto monomials = get_all_monomials(linear_combinations);
|
|
cout << "Monomials: " << monomials.size() << endl;
|
|
|
|
fill_ranks(monomials);
|
|
return 0;
|
|
}
|