#ifndef poset_hpp
#define poset_hpp

#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <tuple>
#include <list>
#include <map>
#include <memory>
#include <thread>
#include <condition_variable>
#include <mutex>

#include "types.h"
//#include "bitSet.h"
#include "displayMessage.h"
#include "utilita.h"
#include "matrice.h"
#include "random.h"
#include "paramType.h"
#include "linearExtension.h"
#include "treeOfIdeals.h"
#include "latticeOfIdeals.h"
#include "lossFunctionMRP.h"
#include "score.h"

class FunctionLinearExtension;
class BucketPOSet;
class ProductPOSet;
class LexicographicProductPOSet;
class FromPOSets;
class ProductLinearPOSet;
class LinearPOSet;
class BinaryVariablePOSet;


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

class POSet {
public:
    using DATASTORE = std::vector<std::shared_ptr<std::set<std::uint_fast64_t>>>;
    using BEC = std::tuple<std::shared_ptr<std::vector<std::vector<std::uint_fast64_t>>>, std::shared_ptr<std::vector<std::string>>, std::shared_ptr<std::list<std::pair<std::string, std::string>>>>;
protected:
    std::shared_ptr<DATASTORE> elementi;
    std::shared_ptr<std::vector<std::string>> eid_vs_ename;
    std::shared_ptr<std::map<std::string, std::uint_fast64_t>> ename_vs_eid;
    std::shared_ptr<TreeOfIdeals> __tree_of_ideals;
    std::shared_ptr<LatticeOfIdeals> __lattice_of_ideals;

public:
    POSet() {
        elementi = nullptr;
        eid_vs_ename = nullptr;
        ename_vs_eid = nullptr;
        __tree_of_ideals = nullptr;
        __lattice_of_ideals = nullptr;
    }
    // costruttori
    static std::shared_ptr<POSet> Build(BEC, bool=true);
    static std::shared_ptr<POSet> Build(std::shared_ptr<std::vector<std::string>>, std::list<std::pair<std::string, std::string>>&, bool=true);

    virtual ~POSet();
public:
    // non modificano
    virtual std::string to_string(char DELIMETER = ';') const;
    virtual std::uint_fast64_t size() const;
    virtual std::shared_ptr<DATASTORE> DownSets() const;
    virtual std::shared_ptr<std::vector<std::vector<bool>>> IncidenceMatrix() const;
    virtual std::shared_ptr<std::list<std::pair<std::string, std::string>>> OrderRelation() const;
    virtual std::shared_ptr<std::vector<std::vector<bool>>> CoverMatrix() const;
    virtual std::shared_ptr<std::list<std::pair<std::uint_fast64_t, std::uint_fast64_t>>> CoverRelation() const;
    virtual std::shared_ptr<std::set<std::uint_fast64_t>> DownSet(std::set<std::uint_fast64_t>&) const;
    virtual bool IsDownSet(std::set<std::uint_fast64_t>&) const;
    virtual std::shared_ptr<std::set<std::uint_fast64_t>> UpSet(std::set<std::uint_fast64_t>&) const;
    virtual bool IsUpSet(std::set<std::uint_fast64_t>&) const;
    virtual std::shared_ptr<std::set<std::uint_fast64_t>> ComparabilitySetOf(std::uint_fast64_t) const;
    virtual std::shared_ptr<std::set<std::uint_fast64_t>> IncomparabilitySetOf(std::uint_fast64_t) const;
    virtual std::shared_ptr<std::set<std::uint_fast64_t>> Maximals() const;
    virtual std::shared_ptr<std::set<std::uint_fast64_t>> Minimals() const;
    virtual bool IsMaximal(std::uint_fast64_t) const;
    virtual bool IsMinimal(std::uint_fast64_t) const;
    virtual std::shared_ptr<std::list<std::pair<std::uint_fast64_t, std::uint_fast64_t>>> Incomparabilities() const;
    virtual bool IsExtensionOf(std::shared_ptr<POSet>) const;
    virtual std::shared_ptr<std::uint_fast64_t> Meet(std::vector<std::uint_fast64_t>&);
    virtual std::shared_ptr<std::uint_fast64_t> Join(std::vector<std::uint_fast64_t>&);

    virtual std::uint_fast64_t getEID(std::string) const;
    virtual std::string GetEName(std::uint_fast64_t) const;
    
    virtual void FirstLE(LinearExtension&) const;
    virtual bool IsTotalOrder() const;
    virtual std::shared_ptr<BucketPOSet> BucketPOSetFromMinimal() const;
    virtual std::shared_ptr<BucketPOSet> BucketPOSetFromMaximal() const;
    virtual std::shared_ptr<POSet> clone() const;
    virtual std::shared_ptr<Matrice<double>> BruggemannLercheSorensenDominance() const;
    virtual bool GreaterThan(std::uint_fast64_t, std::uint_fast64_t) const;
public:
    // non costanti
    virtual std::shared_ptr<DATASTORE> UpSets()  {
        return elementi;
    }
    virtual void evaluation(std::vector<std::shared_ptr<FunctionLinearExtension>>&, LinearExtensionGenerator&, TranformExtension&, std::vector<std::shared_ptr<Matrice<double>>>&, std::uint_fast64_t&, bool&, std::shared_ptr<DisplayMessage>);
    virtual std::shared_ptr<std::list<std::pair<std::uint_fast64_t, std::uint_fast64_t>>> Comparabilities();
    virtual std::shared_ptr<LatticeOfIdeals> latticeOfIdeals();
    virtual std::shared_ptr<TreeOfIdeals> treeOfIdeals();
    virtual std::shared_ptr<Matrice<double>> ComputeMRP();
    
    virtual std::shared_ptr<std::vector<std::string>> Elements() {
        return eid_vs_ename;
    }
    
    virtual std::shared_ptr<std::map<std::string, std::uint_fast64_t>> NamesToID () {
        return ename_vs_eid;
    }
    
    void FillBaseAttribute(std::vector<std::string>&, std::list<std::pair<std::string, std::string>>&, Score*, bool);
    void FillBaseAttribute(std::shared_ptr<std::vector<std::string>>, std::list<std::pair<std::string, std::string>>&, bool);
    virtual std::shared_ptr<POSet> Lifting(std::string);
    virtual std::shared_ptr<POSet> Dual();
private:
    bool AddToDatastore(std::uint_fast64_t);
    bool CheckAntisymmetric(std::uint_fast64_t, std::uint_fast64_t);
    void AverageUpdate(std::shared_ptr<Matrice<double>>, std::shared_ptr<FunctionLinearExtension>, std::uint_fast64_t);
    void SumUpdate(std::shared_ptr<Matrice<double>>, std::shared_ptr<FunctionLinearExtension>, std::uint_fast64_t);
    void RecursiveComputeMRP(std::uint_fast64_t, std::vector<bool>&, std::vector<bool>&, std::uint_fast64_t, std::shared_ptr<Matrice<double>>&);
    
    std::shared_ptr<DATASTORE> imPred() const;
    std::shared_ptr<DATASTORE> imPred(std::shared_ptr<std::vector<std::uint_fast64_t>>) const;
    std::shared_ptr<std::set<std::uint_fast64_t>> imPred(std::uint_fast64_t) const;
    
public:
    // static
    static void UpdateForFirst(std::shared_ptr<POSet::DATASTORE> downSets, std::set<std::uint_fast64_t>& setOne, std::uint_fast64_t min_el);
    static void TransitiveClosure(POSet&, std::uint_fast64_t, std::uint_fast64_t);
    static std::shared_ptr<POSet> Intersection(POSet& p1, POSet& p2) {
        auto p1_elements = p1.Elements();
        auto p2_elements = p2.Elements();
        
        if (p1_elements->size() != p2_elements->size()) {
            std::string err_str = "POSet must have the same elements!";
            throw_line(err_str);
        }
        std::list<std::pair<std::string, std::string>> comparabilities;
        auto p1_upsets = p1.UpSets();
        auto p2_upsets = p1.UpSets();
        auto p2_ntoID = p2.NamesToID();

        for (std::uint_fast64_t e1_in_p1 = 0;  e1_in_p1 < p1_upsets->size(); ++e1_in_p1) {
            auto e1_p1_upset = p1_upsets->at(e1_in_p1);
            auto e1_string = p1_elements->at(e1_in_p1);
            if (p2_ntoID->find(e1_string) == p2_ntoID->end()) {
                std::string err_str = "POSet must have the same elements!";
                throw_line(err_str);
            }
            auto e1_in_p2 = p2_ntoID->at(e1_string);
            auto e1_p2_upset = p2_upsets->at(e1_in_p2);
            for (auto e2_in_p1 : *e1_p1_upset) {
                auto e2_string = p1_elements->at(e2_in_p1);
                if (p2_ntoID->find(e2_string) == p2_ntoID->end()) {
                    std::string err_str = "POSet must have the same elements!";
                    throw_line(err_str);
                }
                auto e2_in_p2 = p2_ntoID->at(e2_string);
                if (e1_p2_upset->find(e2_in_p2) != e1_p2_upset->end()) {
                    comparabilities.push_back(std::make_pair(e1_string, e2_string));
                }
            }
        }
        
        auto risultato = POSet::Build(p1_elements, comparabilities, true);
        return risultato;
    }
    
    template<class ... Types>
    static std::shared_ptr<POSet> Intersection(POSet& p_first, Types ... p_next) {
        auto p_second = Intersection(p_next...);
        return Intersection(p_first, p_second);
    }
    
    static std::shared_ptr<POSet> LinearSum(POSet& p1, POSet& p2);
    static std::shared_ptr<POSet> DisjointSum(POSet& p1, POSet& p2);
    
    void KeysValueToFile(std::fstream& result_file) {
        for (std::uint_fast64_t v = 0;  v < eid_vs_ename->size(); ++v) {
            result_file << v << ": " << eid_vs_ename->at(v) << "\n";
        }
        result_file.flush();
    }
};

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

class Bucket {
public:
    //typedef typename std::set<std::uint_fast64_t>::iterator iterator;
    typedef typename BitSet::iterator iterator;
    //typedef typename std::set<std::uint_fast64_t>::const_iterator const_iterator;
    typedef typename BitSet::const_iterator const_iterator;

    //Bucket(std::uint_fast64_t max_size) : max_size(max_size) {}
    Bucket(std::uint_fast64_t max_size) : max_size(max_size), dati(max_size) {}

    /*
    template<typename Iterator>
    Bucket(std::uint_fast64_t max_size, Iterator begin, Iterator end) : max_size(max_size), dati(max_size) {
        dati.insert(begin, end);
    }*/
    template<typename Iterator>
    Bucket(std::uint_fast64_t max_size, Iterator begin, Iterator end) : max_size(max_size), dati(max_size) {
        dati.set(begin, end);
    }
    
    ~Bucket() {}
    
    iterator begin() noexcept { return dati.begin(); }
    const_iterator cbegin() const noexcept { return dati.cbegin(); }
    iterator end() noexcept { return dati.end(); }
    const_iterator cend() const noexcept { return dati.cend(); }
    
    void insert(std::uint_fast64_t e)  {
        //dati.insert(e);
        dati.set(e);
    }
    
    template<typename Iterator>
    void insert(Iterator begin, Iterator end) {
        //dati.insert(begin, end);
        dati.set(begin, end);
    }
    
    void erase(std::uint_fast64_t e)  {
        //dati.erase(e);
        dati.reset(e);
    }
    
    bool find(std::uint_fast64_t e)  {
        //return dati.find(e) != dati.end();
        return dati.check(e);
    }
    
    std::uint_fast64_t size() const {
        //return dati.size();
        return dati.count();
    }
    /*
    std::shared_ptr<Bucket> difference(Bucket& b) {
        std::shared_ptr<Bucket> result = std::make_shared<Bucket>(b.max_size);
        std::set_difference(dati.begin(), dati.end(), b.dati.begin(), b.dati.end(), std::inserter(result->dati, result->dati.end()));
        return result;
    }*/
    
    std::shared_ptr<Bucket> set_difference(Bucket& b) {
        std::shared_ptr<Bucket> result = std::make_shared<Bucket>(b.max_size);
        result->dati.set_difference(this->dati, b.dati);
        return result;
    }

    std::string to_string() const {
        std::string result = "";
        result += "{";
        std::uint_fast64_t conta = 0;
        for (auto v = cbegin(); v != cend(); v++) {
            if ((++conta) < this->size()) {
                result += std::to_string(*v) + " ";
            } else {
                result += std::to_string(*v);
            }
        }
        result += "}";
        return result;
    }
    
    friend class BucketOrder;
private:
    std::uint_fast64_t max_size;
    //std::set<std::uint_fast64_t> dati;
    BitSet dati;
};


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

class BucketOrder {
public:
    typedef typename std::list<std::shared_ptr<Bucket>> bo_type;
    typedef typename bo_type::iterator iterator;
    typedef typename bo_type::const_iterator const_iterator;
    
    // costruttori
    BucketOrder(std::uint_fast64_t e_number) : element_number(e_number) {}
    
    ~BucketOrder() {}
    
    iterator begin() noexcept { return buckets.begin(); }
    const_iterator cbegin() const noexcept { return buckets.cbegin(); }
    iterator end() noexcept { return buckets.end(); }
    const_iterator cend() const noexcept { return buckets.cend(); }
    
    std::uint_fast64_t size() const {
        return buckets.size();
    }
    
    std::uint_fast64_t eSize() const {
        return element_number;
    }
    
    std::uint_fast64_t size(std::uint_fast64_t layer) const {
        if (buckets.size() <= layer) {
            std::string err_str = "size: BucketOrder layer not valid";
            throw_line(err_str);
        }
        auto it = buckets.begin();
        advance(it, layer);
        return (*it)->size();
    }
    
    void push_back(std::shared_ptr<Bucket> e)  {
        return buckets.push_back(e);
    }
    
    std::shared_ptr<Bucket> at(std::uint_fast64_t layer) {
        if (buckets.size() <= layer) {
            std::string err_str = "at: BucketOrder layer not valid";
            throw_line(err_str);
        }
        auto it = buckets.begin();
        advance(it, layer);
        return (*it);
    }
    
    void replace(std::shared_ptr<Bucket> b, std::uint_fast64_t layer) {
        auto it = buckets.begin();
        advance(it, layer);
        buckets.insert(it, b);
        buckets.erase(it);
    }
    
    void insert(std::shared_ptr<Bucket> b, std::uint_fast64_t layer) {
        auto it = buckets.begin();
        advance(it, layer);
        buckets.insert(it, b);
    }
    
    void insertN(Bucket& b, std::uint_fast64_t layer) {
        auto it = buckets.begin();
        advance(it, layer);
        auto n = std::make_shared<Bucket>(b.max_size, b.begin(), b.end());
        buckets.insert(it, n);
    }
    
    void eraseAt(Bucket& b, std::uint_fast64_t layer) {
        if (buckets.size() <= layer) {
            std::string err_str = "add: BucketOrder layer not valid";
            throw_line(err_str);
        }
        auto it = buckets.begin();
        advance(it, layer);
        for (auto e : b) {
            (*it)->erase(e);
        }
    }
    
    void addAt(Bucket& b, std::uint_fast64_t layer) {
        if (buckets.size() <= layer) {
            std::string err_str = "add: BucketOrder layer not valid";
            throw_line(err_str);
        }
        auto it = buckets.begin();
        advance(it, layer);
        (*it)->insert(b.begin(), b.end());
    }
    
    void erase(std::uint_fast64_t layer) {
        auto it = buckets.begin();
        advance(it, layer);
        buckets.erase(it);
    }
    
    void clear() {
        buckets.clear();
    }

    std::shared_ptr<BucketOrder> copy() {
        auto e_number = this->eSize();
        auto result = std::make_shared<BucketOrder>(e_number);
        for (auto it = buckets.begin(); it != buckets.end(); ++it) {
            result->push_back(std::make_shared<Bucket>(e_number, (*it)->begin(), (*it)->end()));
        }
        return result;
    }
    
    std::string to_string() const {
        std::string result = "";
        for (auto b : buckets) {
            result += "{";
            std::uint_fast64_t conta = 0;
            for (auto v : *b) {
                if ((++conta) < b->size()) {
                    result += std::to_string(v) + " ";
                } else {
                    result += std::to_string(v);
                }
            }
            result += "}";
        }
        return result;
    }
    
    BJRES BestJoinAt(POSet&, POSet&, LossFunctionMRP&, std::uint_fast64_t);
    BSRES BestSplitAt(POSet&, POSet&, LossFunctionMRP&, std::uint_fast64_t);
    
    static bool BSplitPreserve(POSet&, Bucket&, Bucket&);
    static bool BJoinPreserve(POSet&, Bucket&, Bucket&, Bucket&);
private:
    bo_type buckets;
    std::uint_fast64_t element_number;
};


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

class BucketPOSet : public POSet {
private:
    BucketOrder buckets;
    BucketPOSet(std::uint_fast64_t esize) : POSet(),  buckets(esize) {}
public:
    static std::shared_ptr<BucketPOSet> Build(std::shared_ptr<std::vector<std::string>>, std::list<std::pair<std::string, std::string>>&);
    void ReplaceBuckets(BucketOrder& new_buckets);
    ~BucketPOSet();
    std::shared_ptr<Matrice<double>> evaluationMRP();
    static std::shared_ptr<Matrice<double>> evaluationMRP(BucketOrder& buckets);

    bool IsTotalOrder() const;
    std::uint_fast64_t LSize(std::uint_fast64_t) const;
    std::uint_fast64_t LSize() const;
    std::shared_ptr<Bucket> BucketAt(std::uint_fast64_t);
    BucketOrder& Buckets() {
        return this->buckets;
    }
    virtual std::shared_ptr<POSet> clone() const;

private:
    void BuildBucketOrder();
};

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

class LinearPOSet : public POSet {
private:
    LinearPOSet() : POSet() {}
public:
    static std::shared_ptr<LinearPOSet> Build(std::shared_ptr<std::vector<std::string>>);
    virtual std::shared_ptr<std::vector<std::vector<bool>>> IncidenceMatrix() const;
private:
    std::shared_ptr<std::list<std::pair<std::string, std::string>>> BuildComparability(std::shared_ptr<std::vector<std::string>>);
};

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

class FromPOSets : public POSet {
private:
    FromPOSets() : POSet() {
        elements_to_original = nullptr;
    }
    friend ProductPOSet;
    friend ProductLinearPOSet;
    friend LexicographicProductPOSet;
public:
    const static char SEP = '_';
    std::vector<std::shared_ptr<POSet>> posets;
    std::shared_ptr<std::vector<std::vector<std::uint_fast64_t>>> elements_to_original;
public:
    static std::shared_ptr<FromPOSets> Build(std::shared_ptr<POSet> p1, std::shared_ptr<POSet> p2) {
        std::shared_ptr<FromPOSets> result(new FromPOSets());
        if (instanceof<FromPOSets>(&(*p1))) {
            auto pp1 = dynamic_cast<const FromPOSets*>(&(*p1));
            result->posets.insert(result->posets.end(), pp1->posets.begin(), pp1->posets.end());
        } else {
            result->posets.push_back(p1);
        }
        if (instanceof<FromPOSets>(&(*p2))) {
            auto pp2 = dynamic_cast<const FromPOSets*>(&(*p2));
            result->posets.insert(result->posets.end(), pp2->posets.begin(), pp2->posets.end());
        } else {
            result->posets.push_back(p2);
        }
        return result;
    }
    virtual ~FromPOSets() {}
    //virtual std::string to_string() = 0;
};

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

// Let $P_1=<V_1, \leq_1>$ and $P_2=<V_2, \leq_2>$ POSet
// then $P_1\times P_2=<V_{\times}, \leq_{\times}>$ where
// $V_{\times}=\{(a, b) \mid a\in P_1 \text{ and } b\in P_2\}$
// and $(x_1, x_2) \leq_{\times} (y_1, y_2)$ if and only if $x_1 \leq_1 y_1$ and  $x_2 \leq_2 y_2$

class ProductPOSet : public FromPOSets {
private:
    ProductPOSet() : FromPOSets() {}
public:
    static std::shared_ptr<ProductPOSet> Build(std::shared_ptr<POSet> p1, std::shared_ptr<POSet> p2);
    std::shared_ptr<POSet> FilterStrong(std::vector<std::uint_fast64_t>&);
    std::shared_ptr<POSet> FilterStrong(std::shared_ptr<POSet>);
    std::shared_ptr<POSet> FilterLight(std::shared_ptr<POSet>);
};

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

// Let $P_1=<V_1, \leq_1>$ and $P_2=<V_2, \leq_2>$ POSet
// then $P_1\times P_2=<V_{\times}, \leq_{\times}>$ where
// $V_{\times}=\{(a, b) \mid a\in P_1 \text{ and } b\in P_2\}$
// and $(x_1, x_2) \leq_{\times} (y_1, y_2)$ if and only if $x_1 < y_1$ or $x_1 = y_1$  $x_2 \leq_2 y_2$

class LexicographicProductPOSet : public FromPOSets {
private:
    LexicographicProductPOSet() : FromPOSets() {}
public:
    static std::shared_ptr<LexicographicProductPOSet> Build(std::shared_ptr<POSet> p1, std::shared_ptr<POSet> p2);
};

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

class ProductLinearPOSet : public FromPOSets {
private:
    ProductLinearPOSet() : FromPOSets() {}
public:
    static std::shared_ptr<ProductLinearPOSet> Build(std::shared_ptr<POSet> p1, std::shared_ptr<POSet> p2);
    std::shared_ptr<Matrice<double>> ComputeMRPLex();

private:
    static POSet::BEC ElementComparability(std::shared_ptr<POSet> p1, std::shared_ptr<POSet> p2);
};


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

class BinaryVariablePOSet : public POSet {
private:
    BinaryVariablePOSet() : POSet() {}
    std::vector<std::string> variables;
    std::uint_fast64_t numero_profili;
public:
    static std::shared_ptr<BinaryVariablePOSet> Build(const std::vector<std::string>& variables);
    
    virtual std::string to_string(char DELIMETER = ';') const;
    virtual std::uint_fast64_t size() const;
    virtual std::uint_fast64_t NumberOfVariables() const;
    virtual std::shared_ptr<DATASTORE> DownSets() const;
    virtual std::shared_ptr<std::vector<std::vector<bool>>> IncidenceMatrix() const;
    virtual std::shared_ptr<std::list<std::pair<std::string, std::string>>> OrderRelation() const;
    virtual std::shared_ptr<std::vector<std::vector<bool>>> CoverMatrix() const;
    virtual std::shared_ptr<std::list<std::pair<std::uint_fast64_t, std::uint_fast64_t>>> CoverRelation() const;
    virtual std::shared_ptr<std::set<std::uint_fast64_t>> DownSet(std::set<std::uint_fast64_t>&) const;
    virtual bool IsDownSet(std::set<std::uint_fast64_t>&) const;
    virtual std::shared_ptr<std::set<std::uint_fast64_t>> UpSet(std::set<std::uint_fast64_t>&) const;
    virtual bool IsUpSet(std::set<std::uint_fast64_t>&) const;
    virtual std::shared_ptr<std::set<std::uint_fast64_t>> ComparabilitySetOf(std::uint_fast64_t) const;
    virtual std::shared_ptr<std::set<std::uint_fast64_t>> IncomparabilitySetOf(std::uint_fast64_t) const;
    virtual std::shared_ptr<std::set<std::uint_fast64_t>> Maximals() const;
    virtual std::shared_ptr<std::set<std::uint_fast64_t>> Minimals() const;
    virtual bool IsMaximal(std::uint_fast64_t) const;
    virtual bool IsMinimal(std::uint_fast64_t) const;
    virtual std::shared_ptr<std::list<std::pair<std::uint_fast64_t, std::uint_fast64_t>>> Incomparabilities() const;
    virtual bool IsExtensionOf(std::shared_ptr<POSet>) const;

    virtual std::uint_fast64_t getEID(std::string) const;
    virtual std::string GetEName(std::uint_fast64_t) const;
    
    virtual void FirstLE(LinearExtension&) const;
    virtual bool IsTotalOrder() const;
    virtual std::shared_ptr<BucketPOSet> BucketPOSetFromMinimal() const;
    virtual std::shared_ptr<BucketPOSet> BucketPOSetFromMaximal() const;
    virtual std::shared_ptr<POSet> clone() const;
    virtual std::shared_ptr<Matrice<double>> BruggemannLercheSorensenDominance() const;
    virtual std::shared_ptr<POSet> Dual();
public:
    // non costanti
    virtual std::shared_ptr<DATASTORE> UpSets();

    virtual bool GreaterThan(std::uint_fast64_t, std::uint_fast64_t) const;
    virtual std::shared_ptr<std::list<std::pair<std::uint_fast64_t, std::uint_fast64_t>>> Comparabilities();
    virtual std::shared_ptr<LatticeOfIdeals> latticeOfIdeals();
    virtual std::shared_ptr<TreeOfIdeals> treeOfIdeals();
    virtual std::shared_ptr<Matrice<double>> ComputeMRP();
    
    virtual std::shared_ptr<std::vector<std::string>> Elements();
    virtual std::shared_ptr<std::map<std::string, std::uint_fast64_t>> NamesToID();
private:
    std::shared_ptr<std::list<std::uint_fast64_t>> Maximals(std::set<std::uint_fast64_t>& els) const;
    std::shared_ptr<std::list<std::uint_fast64_t>> Minimals(std::set<std::uint_fast64_t>& els) const;
};




#endif /* poset_hpp */
