#include <vector>
#include <list>
#include <unordered_map>
#include <set>
#include <stack>
#include <memory>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <chrono>
#include <bitset>
#include <bit>

#include "matrice.h"
#include "linearExtension.h"
#include "functionLinearExtension.h"
#include "poset.h"
#include "linearExtensionGenerator.h"
#include "tranformExtension.h"
#include "score.h"

//#if __cplusplus > 201703L
auto contabituno = [](std::uint_fast64_t valore) {
    return std::popcount(valore);
};
//#else
//auto contabituno = [](std::uint_fast64_t valore) {
//    std::bitset<64> b(valore);
//    return b.count();
//};
//#endif

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<BinaryVariablePOSet> BinaryVariablePOSet::Build(const std::vector<std::string>& variables) {
    std::shared_ptr<BinaryVariablePOSet> r(new BinaryVariablePOSet());
    r->variables.insert(r->variables.end(), variables.begin(), variables.end());
    r->numero_profili = ((std::uint_fast64_t) 1) << r->variables.size();
    return r;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::string BinaryVariablePOSet::to_string(char DELIMETER) const {
    std::string err_str = "Function not yet implemented";
    throw_line(err_str);
}

// ***********************************************
// ***********************************************
// ***********************************************

std::uint_fast64_t BinaryVariablePOSet::size() const {
    return numero_profili;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::uint_fast64_t BinaryVariablePOSet::NumberOfVariables() const {
    return variables.size();
}

// ***********************************************
// ***********************************************
// ***********************************************


std::shared_ptr<POSet::DATASTORE> BinaryVariablePOSet::DownSets() const {
    auto result = std::make_shared<POSet::DATASTORE>(numero_profili);
    result->at(0) = std::make_shared<std::set<std::uint_fast64_t>>();
    for (std::uint_fast64_t v1 = 1; v1 < numero_profili; ++v1) {
        result->at(v1) = std::make_shared<std::set<std::uint_fast64_t>>();
        for (std::uint_fast64_t v2 = 0; v2 < v1; ++v2) {
            std::uint_fast64_t bit_or = (v1 | v2);
            if (bit_or == v1) {
                result->at(v1)->insert(v2);
            }
        }
    }
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<std::set<std::uint_fast64_t>> BinaryVariablePOSet::DownSet(std::set<std::uint_fast64_t>& els) const {
    auto maximals = Maximals(els);
    
    // costruisco il risultato analizzando solo i massimali
    auto result = std::make_shared<std::set<std::uint_fast64_t>>();
    for (std::uint_fast64_t v1 : *maximals) {
        result->insert(v1);
        for (std::uint_fast64_t v2 = 0; v2 < v1; ++v2) {
            std::uint_fast64_t bit_or = (v1 | v2);
            if (bit_or == v1) {
                result->insert(v2);
            }
        }
    }
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************

bool BinaryVariablePOSet::IsDownSet(std::set<std::uint_fast64_t>& elements) const {
    auto ProssimaSequenza = [](std::vector<std::uint_fast64_t>& sequenza, std::uint_fast64_t totale_elementi) {
        if (sequenza.back() != totale_elementi - 1) {
            sequenza.end() += 1;
        } else {
            if (sequenza.size() < 2)
                return false;
            std::uint_fast64_t k = sequenza.size() - 2;
            while (k >= 0 and sequenza[k] + (sequenza.size() - k - 1) >= (totale_elementi - 1)) {
                if (k == 0)
                    return false;
                --k;
            }
            sequenza[k] += 1;
            for (std::uint_fast64_t p = k + 1; p < sequenza.size(); ++p) {
                sequenza[p] = sequenza[p - 1] + 1;
            }
        }
        return true;
    };

    auto CardinalitaIntersezione = [](std::vector<std::uint_fast64_t>& valori, std::vector<std::uint_fast64_t>&indici) {
        std::uint_fast64_t r = ~0;
        for (auto& p : indici) {
            r = r & valori[p];
        }
        std::uint_fast64_t uno_bit = contabituno(~r);
        return 1 << uno_bit;
    };
        
    auto CardinalitaTutti = [](std::vector<std::uint_fast64_t>& valori) {
        std::uint_fast64_t r = 0;
        for (auto& v  : valori) {
            std::uint_fast64_t uno_bit = contabituno(~v);
            r += 1 << uno_bit;
        }
        return r;
    };
    
    auto CardinalitaIntersezioneDiOrdine = [&CardinalitaIntersezione, &ProssimaSequenza](std::vector<std::uint_fast64_t>& valori, std::uint_fast64_t ordine) {
        std::vector<std::uint_fast64_t> posizioni(ordine);
        std::iota (std::begin(posizioni), std::end(posizioni), 0);
        
        std::uint_fast64_t tot = CardinalitaIntersezione(valori, posizioni);
        while (true) {
            bool trovata = ProssimaSequenza(posizioni, valori.size());
            if (!trovata) {
                break;
            }
            tot += CardinalitaIntersezione(valori, posizioni);
        }
        return tot;
    };
    
    auto maximals = Maximals(elements);
    std::vector<std::uint_fast64_t> valori(maximals->size());
    std::copy(maximals->begin(), maximals->end(), valori.begin());
    
    std::uint_fast64_t totale = CardinalitaTutti(valori);
    int include_exclude = -1;
    for (std::uint_fast64_t ordine = 2; ordine <= maximals->size(); ++ordine) {
        std::uint_fast64_t r = CardinalitaIntersezioneDiOrdine(valori, ordine);
        totale += (include_exclude * r);
        include_exclude *= -1;
    }
    return totale;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<POSet::DATASTORE> BinaryVariablePOSet::UpSets() {
    auto result = std::make_shared<POSet::DATASTORE>(numero_profili);
    for (std::uint_fast64_t v1 = 0; v1 < numero_profili; ++v1) {
        result->at(v1) = std::make_shared<std::set<std::uint_fast64_t>>();
        for (std::uint_fast64_t v2 = v1 + 1; v2 < numero_profili; ++v2) {
            std::uint_fast64_t bit_and = (v1 & v2);
            if (bit_and == v1) {
                result->at(v1)->insert(v2);
            }
        }
    }
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<std::set<std::uint_fast64_t>> BinaryVariablePOSet::UpSet(std::set<std::uint_fast64_t>& els) const {
    auto minimals = Minimals(els);
    
    // costruisco il risultato analizzando solo i minimalio
    auto result = std::make_shared<std::set<std::uint_fast64_t>>();
    for (std::uint_fast64_t v1 : *minimals) {
        result->insert(v1);
        for (std::uint_fast64_t v2 = v1 + 1; v2 < numero_profili; ++v2) {
            std::uint_fast64_t bit_and = (v1 & v2);
            if (bit_and == v1) {
                result->insert(v2);
            }
        }
    }
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************


bool BinaryVariablePOSet::IsUpSet(std::set<std::uint_fast64_t>& elements) const {
    auto ProssimaSequenza = [](std::vector<std::uint_fast64_t>& sequenza, std::uint_fast64_t totale_elementi) {
        if (sequenza.back() != totale_elementi - 1) {
            sequenza.end() += 1;
        } else {
            if (sequenza.size() < 2)
                return false;
            std::uint_fast64_t k = sequenza.size() - 2;
            while (k >= 0 and sequenza[k] + (sequenza.size() - k - 1) >= (totale_elementi - 1)) {
                if (k == 0)
                    return false;
                --k;
            }
            sequenza[k] += 1;
            for (std::uint_fast64_t p = k + 1; p < sequenza.size(); ++p) {
                sequenza[p] = sequenza[p - 1] + 1;
            }
        }
        return true;
    };

    auto CardinalitaIntersezione = [](std::vector<std::uint_fast64_t>& valori, std::vector<std::uint_fast64_t>&indici) {
        std::uint_fast64_t r = ~0;
        for (auto& p : indici) {
            r = r & valori[p];
        }
        std::uint_fast64_t uno_bit = contabituno(r);
        return 1 << uno_bit;
    };
        
    auto CardinalitaTutti = [](std::vector<std::uint_fast64_t>& valori) {
        std::uint_fast64_t r = 0;
        for (auto& v  : valori) {
            std::uint_fast64_t uno_bit = contabituno(v);
            r += 1 << uno_bit;
        }
        return r;
    };
    
    auto CardinalitaIntersezioneDiOrdine = [&CardinalitaIntersezione, &ProssimaSequenza](std::vector<std::uint_fast64_t>& valori, std::uint_fast64_t ordine) {
        std::vector<std::uint_fast64_t> posizioni(ordine);
        std::iota (std::begin(posizioni), std::end(posizioni), 0);
        
        std::uint_fast64_t tot = CardinalitaIntersezione(valori, posizioni);
        while (true) {
            bool trovata = ProssimaSequenza(posizioni, valori.size());
            if (!trovata) {
                break;
            }
            tot += CardinalitaIntersezione(valori, posizioni);
        }
        return tot;
    };
    auto minimals = Minimals(elements);

    std::vector<std::uint_fast64_t> valori(minimals->size());
    std::copy(minimals->begin(), minimals->end(), valori.begin());
    
    std::uint_fast64_t totale = CardinalitaTutti(valori);
    int include_exclude = -1;
    for (std::uint_fast64_t ordine = 2; ordine <= minimals->size(); ++ordine) {
        std::uint_fast64_t r = CardinalitaIntersezioneDiOrdine(valori, ordine);
        totale += (include_exclude * r);
        include_exclude *= -1;
    }
    return totale;
}

// ***********************************************
// ***********************************************
// ***********************************************


std::shared_ptr<std::vector<std::vector<bool>>> BinaryVariablePOSet::IncidenceMatrix() const {
    auto result = std::make_shared<std::vector<std::vector<bool>>>(numero_profili, std::vector<bool>(numero_profili, false));
    for (std::uint_fast64_t row = 0; row < numero_profili; ++row) {
        result->at(row).at(row) =  true;
        for (std::uint_fast64_t col = row + 1; col < numero_profili; ++col) {
            std::uint_fast64_t bit_or = row | col;
            if (bit_or == col) {
                result->at(row).at(col) = true;
            }
        }
    }
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************


std::shared_ptr<std::list<std::pair<std::string, std::string>>> BinaryVariablePOSet::OrderRelation() const {
    auto result = std::make_shared<std::list<std::pair<std::string, std::string>>>();
    for (std::uint_fast64_t row = 0; row < elementi->size(); ++row) {
        auto row_e = GetEName(row);
        result->push_back(std::make_pair(row_e, row_e));
        for (std::uint_fast64_t col = row + 1; col < numero_profili; ++col) {
            std::uint_fast64_t bit_or = row | col;
            if (bit_or == col) {
                auto col_e = GetEName(col);
                result->push_back(std::make_pair(row_e, col_e));
            }
        }
    }
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************


std::shared_ptr<std::vector<std::vector<bool>>> BinaryVariablePOSet::CoverMatrix() const {
    auto result = std::make_shared<std::vector<std::vector<bool>>>(numero_profili, std::vector<bool>(numero_profili, false));
    for (std::uint_fast64_t row = 0; row < numero_profili; ++row) {
        //result->at(row).at(row) =  true;
        for (std::uint_fast64_t col = row + 1; col < numero_profili; ++col) {
            std::uint_fast64_t bit_xor = row ^ col;
            if (contabituno(bit_xor) == 1) {
                result->at(row).at(col) = true;
            }
        }
    }
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************


std::shared_ptr<std::list<std::pair<std::uint_fast64_t, std::uint_fast64_t>>> BinaryVariablePOSet::CoverRelation() const {
    auto result = std::make_shared<std::list<std::pair<std::uint_fast64_t, std::uint_fast64_t>>>();
    for (std::uint_fast64_t row = 0; row < elementi->size(); ++row) {
        result->push_back(std::make_pair(row, row));
        for (std::uint_fast64_t col = row + 1; col < numero_profili; ++col) {
            std::uint_fast64_t bit_xor = row ^ col;
            if (contabituno(bit_xor) == 1) {
                result->push_back(std::make_pair(row, col));
            }
        }
    }
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<std::set<std::uint_fast64_t>> BinaryVariablePOSet::ComparabilitySetOf(std::uint_fast64_t e) const {
    std::set<std::uint_fast64_t> eset;
    eset.insert(e);
    auto r1 = UpSet(eset);
    auto r2 = DownSet(eset);
    
    r1->insert(r2->begin(), r2->end());
    return r1;
}

// ***********************************************
// ***********************************************
// ***********************************************


std::shared_ptr<std::set<std::uint_fast64_t>> BinaryVariablePOSet::IncomparabilitySetOf(std::uint_fast64_t e) const {
    auto result = std::make_shared<std::set<std::uint_fast64_t>>();

    for (std::uint_fast64_t val = 0; val < numero_profili; ++val) {
        if (val == e) continue;
        std::uint_fast64_t bit_and = val & e;
        if (bit_and == e) {
            result->insert(val);
        }
    }
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<std::set<std::uint_fast64_t>> BinaryVariablePOSet::Maximals() const {
    auto maximals = std::make_shared<std::set<std::uint_fast64_t>>();
    maximals->insert(~0);
    return maximals;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<std::list<std::uint_fast64_t>> BinaryVariablePOSet::Maximals(std::set<std::uint_fast64_t>& els) const {
    auto maximals = std::make_shared<std::list<std::uint_fast64_t>>(els.begin(), els.end());
    auto v1_iter = maximals->begin();
    while (v1_iter != maximals->end()) {
        std::uint_fast64_t v1 = *v1_iter;
        bool not_maximan = false;
        auto v2_iter = std::next(v1_iter, 1);
        while (v2_iter != maximals->end()) {
            std::uint_fast64_t v2 = *v2_iter;
            std::uint_fast64_t bit_or = (v1 | v2);
            if (bit_or == v1) {
                v2_iter = maximals->erase(v2_iter);
            } else if (bit_or == v2) {
                not_maximan = true;
                break;
            } else {
                ++v2_iter;
            }
        }
        if (not_maximan) {
            v1_iter = maximals->erase(v1_iter);
        }
        else {
            ++v1_iter;
        }
    }
    return maximals;
}

// ***********************************************
// ***********************************************
// ***********************************************


std::shared_ptr<std::set<std::uint_fast64_t>> BinaryVariablePOSet::Minimals() const {
    auto maximals = std::make_shared<std::set<std::uint_fast64_t>>();
    maximals->insert(0);
    return maximals;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<std::list<std::uint_fast64_t>> BinaryVariablePOSet::Minimals(std::set<std::uint_fast64_t>& els) const {
    auto minimals = std::make_shared<std::list<std::uint_fast64_t>>(els.begin(), els.end());
    auto v1_iter = minimals->begin();
    while (v1_iter != minimals->end()) {
        std::uint_fast64_t v1 = *v1_iter;
        bool not_minimal = false;
        auto v2_iter = std::next(v1_iter, 1);
        while (v2_iter != minimals->end()) {
            std::uint_fast64_t v2 = *v2_iter;
            std::uint_fast64_t bit_and = (v1 & v2);
            if (bit_and == v1) {
                v2_iter = minimals->erase(v2_iter);
            } else if (bit_and == v1) {
                not_minimal = true;
                break;
            } else {
                ++v2_iter;
            }
        }
        if (not_minimal) {
            v1_iter = minimals->erase(v1_iter);
        }
        else {
            ++v1_iter;
        }
    }
    return minimals;
}


// ***********************************************
// ***********************************************
// ***********************************************


bool BinaryVariablePOSet::IsMaximal(std::uint_fast64_t v) const {
    return v == numero_profili - 1;
}

// ***********************************************
// ***********************************************
// ***********************************************


bool BinaryVariablePOSet::IsMinimal(std::uint_fast64_t v) const {
    return v == 0;

}

// ***********************************************
// ***********************************************
// ***********************************************


std::shared_ptr<std::list<std::pair<std::uint_fast64_t, std::uint_fast64_t>>> BinaryVariablePOSet::Incomparabilities() const {
    auto result = std::make_shared<std::list<std::pair<std::uint_fast64_t, std::uint_fast64_t>>>();
    for (std::uint_fast64_t v1 = 0; v1 < numero_profili; ++v1) {
        for (std::uint_fast64_t v2 = v1 + 1; v2 < numero_profili; ++v2) {
            std::uint_fast64_t bit_or = (v1 | v2);
            std::uint_fast64_t bit_and = (v1 & v2);

            if (bit_or != v2 && bit_and != v1) {
                result->push_back(std::make_pair(v1, v2));
            }
        }
    }
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************

bool BinaryVariablePOSet::IsExtensionOf(std::shared_ptr<POSet> p) const {
    if (!instanceof<BinaryVariablePOSet>(&(*p)) && dynamic_cast<const BinaryVariablePOSet*>(&(*p))->numero_profili == numero_profili) {
        return true;
    }
    return false;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::uint_fast64_t BinaryVariablePOSet::getEID(std::string s) const {
    return std::stoi(s, nullptr, 2);
}

// ***********************************************
// ***********************************************
// ***********************************************

std::string BinaryVariablePOSet::GetEName(std::uint_fast64_t v) const {
    std::string s = std::bitset<64>(v).to_string().substr(64 - variables.size());
    return s;
}

// ***********************************************
// ***********************************************
// ***********************************************


void BinaryVariablePOSet::FirstLE(LinearExtension& le) const {
    for (std::uint_fast64_t k = 0; k < le.size(); ++k) {
        le.set(k, k);
    }
}

// ***********************************************
// ***********************************************
// ***********************************************


bool BinaryVariablePOSet::IsTotalOrder() const {
    return numero_profili == 1;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<BucketPOSet> BinaryVariablePOSet::BucketPOSetFromMinimal() const {
    std::string err_str = "Function not yet implemented";
    throw_line(err_str);
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<BucketPOSet> BinaryVariablePOSet::BucketPOSetFromMaximal() const {
    std::string err_str = "Function not yet implemented";
    throw_line(err_str);
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<POSet> BinaryVariablePOSet::clone() const {
    auto result = BinaryVariablePOSet::Build(variables);
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************


std::shared_ptr<Matrice<double>> BinaryVariablePOSet::BruggemannLercheSorensenDominance() const {
    auto matrice = std::make_shared<Matrice<double>>(numero_profili);
    for (std::uint_fast64_t k = 0; k < matrice->Rows(); ++k) {
        (*matrice)(k, k) = 1.0;
    }
    for (std::uint_fast64_t v1 = 0; v1 < matrice->Rows(); ++v1) {
        for (std::uint_fast64_t v2 = v1 + 1; v2 < matrice->Rows(); ++v2) {
            std::uint_fast64_t bit_or_v1_v2 = (v1 | v2);
            if (bit_or_v1_v2 == v2) {
                (*matrice)(v1, v2) = 1.0;
                (*matrice)(v2, v1) = 0.0;
            } else {
                std::uint_fast64_t upij = contabituno(~v1) - contabituno(~v1 & ~v2);
                std::uint_fast64_t upji = contabituno(~v2) - contabituno(~v1 & ~v2);;
                std::uint_fast64_t downij = contabituno(v1) - contabituno(v1 & v2);
                std::uint_fast64_t downji = contabituno(v2) - contabituno(v1 & v2);
                auto aij = (upij + 1.0) / (downij + 1.0);
                auto aji = (upji + 1.0) / (downji + 1.0);
                (*matrice)(v2, v1) = aij / (aij + aji);
                (*matrice)(v1, v2) = aji / (aji + aij);
            }
        }
    }
    return matrice;
}

// ***********************************************
// ***********************************************
// ***********************************************


bool BinaryVariablePOSet::GreaterThan(std::uint_fast64_t v1, std::uint_fast64_t v2) const {
    // e2 < e1 true
    // otherwise false
    std::uint_fast64_t bit_or = (v1 | v2);
    if (bit_or == v1) {
        return true;
    }
    return false;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<std::list<std::pair<std::uint_fast64_t, std::uint_fast64_t>>> BinaryVariablePOSet::Comparabilities() {
    auto result = std::make_shared<std::list<std::pair<std::uint_fast64_t, std::uint_fast64_t>>>();
    for (std::uint_fast64_t v1 = 0; v1 < numero_profili; ++v1) {
        for (std::uint_fast64_t v2 = v1 + 1; v2 < numero_profili; ++v2) {
            std::uint_fast64_t bit_or = (v1 | v2);
            std::uint_fast64_t bit_and = (v1 & v2);

            if (bit_or == v2 || bit_and == v1) {
                result->push_back(std::make_pair(v1, v2));
            }
        }
    }
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<LatticeOfIdeals> BinaryVariablePOSet::latticeOfIdeals() {
    std::string err_str = "Function not yet implemented";
    throw_line(err_str);
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<TreeOfIdeals> BinaryVariablePOSet::treeOfIdeals() {
    std::string err_str = "Function not yet implemented";
    throw_line(err_str);
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<Matrice<double>> BinaryVariablePOSet::ComputeMRP() {
    auto poss = std::make_shared<std::vector<std::shared_ptr<POSet>>>();
    std::shared_ptr<BinaryVariablePOSet>poset(this);
    poss->push_back(poset);
    auto legenerator = std::make_shared<LEGBinaryVariable>(poss);
    legenerator->start(0);
    
    std::vector<std::shared_ptr<Matrice<double>>> eval_results(1);
    std::uint_fast64_t nrow = size();
    std::uint_fast64_t ncol = size();
    auto mrp = std::make_shared<Matrice<double>>(nrow, ncol);
    eval_results.at(0) = mrp;

    std::vector<std::shared_ptr<FunctionLinearExtension>> fles(1);
    fles.at(0) = std::make_shared<FLEMutualRankingProbability>(poset);
    TEItentity tle(poset->Elements());
    
    std::uint_fast64_t le_count = 0;
    bool end_process = false;
    
    std::shared_ptr<DisplayMessage> displayMessage = std::make_shared<DisplayMessageNull>();
    poset->evaluation(fles, *legenerator, tle, eval_results, le_count, end_process, displayMessage);
    return mrp;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<std::vector<std::string>> BinaryVariablePOSet::Elements() {
    auto result = std::make_shared<std::vector<std::string>>(numero_profili);
    
    for (std::uint_fast64_t v = 0; v < numero_profili; ++v) {
        result->at(v) = GetEName(v);
    }
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<std::map<std::string, std::uint_fast64_t>> BinaryVariablePOSet::NamesToID() {
    auto result = std::make_shared<std::map<std::string, std::uint_fast64_t>>();
    
    for (std::uint_fast64_t v = 0; v < numero_profili; ++v) {
        auto e = GetEName(v);
        (*result)[e] = v;
    }
    return result;
}

// ***********************************************
// ***********************************************
// ***********************************************

std::shared_ptr<POSet> BinaryVariablePOSet::Dual() {
    std::vector<std::string> variables_names(variables.begin(), variables.end());
    std::reverse(variables_names.begin(), variables_names.end());

    auto poset = BinaryVariablePOSet::Build(variables_names);
    return poset;
}
