#include <iostream>
#include <cstdlib>
#include <gmp.h>
#include <cstdarg>
#include <vector>
#include <bitset>
using namespace std;

bitset<40> xor40(bitset<40> bs1, bitset<40> bs2) {
    return bs1 ^ bs2;
}

bitset<40> reduce_2(bitset<40> (*f)(bitset<40>, bitset<40>), vector< bitset<40> > bsv) {
    bitset<40> result = bsv[0];
    for (int i = 1; i < bsv.size(); i++)
        result = f(result, bsv[i]);
    return result;
}

vector< bitset<40> > map_1(bitset<40> (*f)(vector<bitset<8> >), vector< vector< bitset<8> > > b) {
    vector< bitset<40> > result;
    result.resize(b.size());
    for (int i = 0; i < b.size(); i++) {
        result[i] = f(b[i]);
    }
    return result;
}

bitset<40> merge_1(vector< bitset<8> > vb) {
    string s = "";
    for (int i = 0; i < vb.size(); i++) {
        s = s + vb[i].to_string();
    }
    return bitset <40>(s);
}

int main(int argc, char *argv[]){
    vector< vector< bitset<8> > > block;
    block.resize(5);
    cout << "block:\n";
    for (int i = 0; i < 5; i++)
        block[i].resize(5);
    for (int i = 0; i < 5; i++)
        for (int j = 0; j < 5; j++)
            block[i][j] = 5*i+j;
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++)
            cout << block[i][j] << ", ";
        cout << "\n";
    }

    cout << "\nAfter map the merge function to block:\n";

    vector< bitset<40> > out = map_1(&merge_1, block);
    for (int i = 0; i < out.size(); i++)
        cout << out[i] << endl;

    bitset<40> out2 = reduce_2(&xor40, out);

    cout << "\nAfter reduce them by ^:\n";
    cout << out2 << endl;

    return 0;
}
