#include <list>
#include <chrono>
#include "myException.h"
#include "random.h"
#include "utilita.h"
#include "tranformExtension.h"
#include "linearExtensionGenerator.h"
#include "functionLinearExtension.h"
#include "posetWrapper.h"
#include "linearGeneratorWrapper.h"

#include "rwrapper.h"
#include "rDisplayUtils.h"
#include "rFunctionLinearExtension.h"
#include "rSeparationUtils.h"

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

LinearGeneratorWrap* LinearGeneratorWrap::BuildBubleyDyerGenerator(POSetWrap* poset, std::map<std::string, std::uint_fast64_t>& args) {
    auto result = new LinearGeneratorWrap();
    result->type = LEGType::BubleyDyer;

    auto poss = std::make_shared<std::vector<std::shared_ptr<POSet>>>();
    poss->push_back(poset->poset);

    std::uint_fast64_t SEED_BD = 0;
    if (args.find("BubleyDyerSeed") != args.end()) {
        SEED_BD = (std::uint_fast64_t) (args["BubleyDyerSeed"]);
    } else {
        SEED_BD = RandomUni::GENERATORE_SEED_RANDOM.RndNextInt(0, std::numeric_limits<std::uint_fast64_t>::max());
    }
    auto rnd = std::make_shared<RandomUni>(SEED_BD);
    result->generator = std::make_shared<LEGBubleyDyer>(poss, rnd);
    result->generator->start(0);
    return result;
}

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

LinearGeneratorWrap* LinearGeneratorWrap::BuildLEGenerator(POSetWrap* poset) {
    auto poss = std::make_shared<std::vector<std::shared_ptr<POSet>>>();
    poss->push_back(poset->poset);
    auto result = new LinearGeneratorWrap();
    if (dynamic_pointer_cast<BinaryVariablePOSet>(poset->poset) == nullptr) {
        result->type = LEGType::TreeOfIdeals;
        result->generator = std::make_shared<LEGTreeOfIdeals>(poss);
    } else {
        result->type = LEGType::BinaryVariable;
        result->generator = std::make_shared<LEGBinaryVariable>(poss);
    }
    result->generator->start(0);
    return result;
}

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

std::shared_ptr<std::list<std::shared_ptr<std::vector<std::string>>>> LinearGeneratorWrap::get(bool from_start, std::uint_fast64_t quante, std::uint_fast64_t output_ogni_in_sec) {
    auto keys = generator->keys();
    if (from_start) {
        generator->start(std::numeric_limits<std::uint_fast64_t>::max());
        finite = false;
    }
    auto result = std::make_shared<std::list<std::shared_ptr<std::vector<std::string>>>>();
    if (finite) return result;

    bool expected_output = false;
    std::uint_fast64_t le_count = 0;

    std::shared_ptr<DisplayMessage> displayMessage = nullptr;
    if (output_ogni_in_sec == std::numeric_limits<std::uint_fast64_t>::max()) {
        displayMessage = std::make_shared<DisplayMessageNull>();
    } else {
        displayMessage = std::make_shared<DisplayMessageLEGetR>(le_count, quante, expected_output, output_ogni_in_sec);
    }
    displayMessage->Start();
    for (le_count = 0; le_count < quante; ++le_count) {
        displayMessage->Display();

        auto le = generator->get();
        auto le_str = std::make_shared<std::vector<std::string>>(le->size());
        for (std::uint_fast64_t r = 0; r < le->size(); ++r) {
            le_str->at(r) = keys->at(le->getVal(r));
        }
        result->push_back(le_str);
        if (!generator->hasNext()) {
            finite = true;
            std::string message = "Reached maximum number of linear extentions: " + std::to_string(le_count + 1) + ".";
            Rprintf("%s\n", message.c_str());
            break;
        }
        generator->next();
    }
    displayMessage->Stop();
    return result;
}

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

std::shared_ptr<std::list<std::shared_ptr<std::vector<std::string>>>> LinearGeneratorWrap::GetFromBubleyDyer(bool from_start,
                                                                                                             std::uint_fast64_t quante,
                                                                                                             std::shared_ptr<double> errore,
                                                                                                             std::uint_fast64_t output_ogni_in_sec) {
    if (errore == nullptr && quante == std::numeric_limits<std::uint_fast64_t>::max()) {
        std::string err_str = "The number of le extensions to generate or the error must be provided.";
        throw_line(err_str);
    }
    if (errore != nullptr && quante != std::numeric_limits<std::uint_fast64_t>::max()) {
        std::string err_str = "The number of le generated will be: " + std::to_string(quante) + ". Parameter error is ignored";
        forward_warning_to_r(err_str);
    } else if (quante == std::numeric_limits<std::uint_fast64_t>::max()) {
        auto q = static_cast<LEGBubleyDyer*>(&(*generator))->evaluateNumberOfIteration(*errore);
        if (from_start) {
            quante = q;
        } else {
            if ((q + 1) < static_cast<LEGBubleyDyer*>(&(*generator))->currentNumberOfLE()) {
                std::string err_str = "GetFromBubleyDyer: Internal error.";
                throw_line(err_str);
            }
            quante = (q + 1) - static_cast<LEGBubleyDyer*>(&(*generator))->currentNumberOfLE();
        }
        std::string message = std::to_string(quante) + " linear extentions will be generated.";
        Rprintf("%s\n", message.c_str());
    }
    auto result = get(from_start, quante, output_ogni_in_sec);
    return result;
}

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

std::shared_ptr<std::list<std::shared_ptr<std::vector<std::string>>>> LinearGeneratorWrap::GetFromLE(bool from_start, std::uint_fast64_t quante, std::uint_fast64_t output_ogni_in_sec) {
    auto result = get(from_start, quante, output_ogni_in_sec);
    return result;
}

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

std::uint_fast64_t LinearGeneratorWrap::LESize() const {
    return generator->LESize();
}

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

SEXP LinearGeneratorWrap::BuildExactEvaluation(POSetWrap* poset,
                                               std::vector<std::string>& internal_functions,
                                               std::vector<SEXP>& external_functions,
                                               std::uint_fast64_t output_ogni_in_sec,
                                               int& conta_proteggi) {
    std::shared_ptr<LEGTreeOfIdeals> le_generator;
    std::vector<std::shared_ptr<Matrice<double>>> eval_results(internal_functions.size(), nullptr);
    std::vector<std::shared_ptr<FunctionLinearExtension>> fles(internal_functions.size(), nullptr);
    std::vector<std::string> functions_name(internal_functions.size(), "");

    for (std::uint_fast64_t k = 0; k < internal_functions.size(); ++k) {
        auto nome_funzione = internal_functions.at(k);
        auto r_funzione = external_functions.at(k);
        if (POSetWrap::functionLinearMapType.find(nome_funzione) == POSetWrap::functionLinearMapType.end()) {
            std::string err_str = "Wrong function name: " + nome_funzione;
            throw_line(err_str);
        }
        std::shared_ptr<FunctionLinearExtension> fle = nullptr;
        std::string function_name = "";

        auto function_type = POSetWrap::functionLinearMapType.at(nome_funzione);
        switch (function_type) {
            case POSetWrap::FunctionLinearType::FLETMutualRankingProbability:
                fle = std::make_shared<FLEMutualRankingProbability>(poset->poset);
                function_name = "MutualRankingProbability";
                break;
            case POSetWrap::FunctionLinearType::FLETAverageHeight:
                fle = std::make_shared<FLEAverageHeight>(poset->poset);
                function_name = "AverageHeight";
                break;
            case POSetWrap::FunctionLinearType::FLETSeparationAsymmetricLower:
                fle = std::make_shared<FLESeparationAsymmetricLower>(poset->poset);
                function_name = "asymmetricLower";
                break;
            case POSetWrap::FunctionLinearType::FLETSeparationAsymmetricUpper:
                fle = std::make_shared<FLESeparationAsymmetricUpper>(poset->poset);
                function_name = "asymmetricUpper";
                break;
            case POSetWrap::FunctionLinearType::FLETSeparationSymmetric:
                fle = std::make_shared<FLESeparationSymmetric>(poset->poset);
                function_name = "symmetric";
                break;
            case POSetWrap::FunctionLinearType::FLETRFunction:
                //std::string message = "FLETRFunction: " + std::to_string(k);
                //Rprintf("%s\n", message.c_str());
                fle = std::make_shared<FLERinterface>(poset->poset, r_funzione);
                function_name = "RFunction";
                break;
        }
        auto shape = fle->shape();
        std::uint_fast64_t nrow = shape.at(0);
        std::uint_fast64_t ncol = shape.at(1);
        eval_results.at(k) = std::make_shared<Matrice<double>>(nrow, ncol);
        fles.at(k) = fle;
        functions_name.at(k) = function_name;
    }

    auto poss = std::make_shared<std::vector<std::shared_ptr<POSet>>>();
    poss->push_back(poset->poset);
    le_generator = std::make_shared<LEGTreeOfIdeals>(poss);
    le_generator->start(0);

    //////////////////////////////

    TEItentity tle(poset->Elements());
    std::uint_fast64_t le_count = 0;
    std::uint_fast64_t total_number_of_extension = std::numeric_limits<std::uint_fast64_t>::max();
    bool end_process = false;

    std::shared_ptr<DisplayMessage> displayMessage = nullptr;
    if (output_ogni_in_sec == std::numeric_limits<std::uint_fast64_t>::max()) {
        displayMessage = std::make_shared<DisplayMessageNull>();
    } else {
        displayMessage = std::make_shared<DisplayMessageEvaluationR>(total_number_of_extension, le_count, output_ogni_in_sec);
    }
    poset->poset->evaluation(fles, *le_generator, tle, eval_results, le_count, end_process, displayMessage);

    auto result_r = Proteggi(Rf_allocVector(VECSXP, (long) (eval_results.size() + 1)), conta_proteggi);
    auto result_r_names = Proteggi(Rf_allocVector(VECSXP, (long) (eval_results.size() + 1)), conta_proteggi);

    for (std::uint_fast64_t k = 0; k < eval_results.size(); ++k) {
        auto r_c = eval_results.at(k);
        std::uint_fast64_t nrow = r_c->Rows();
        std::uint_fast64_t ncol = r_c->Cols();


        auto rows_names_c = fles.at(k)->rowsName();
        auto cols_names_c = fles.at(k)->colsName();

        SEXP r_r = Proteggi(Rf_allocMatrix(REALSXP, (int) nrow, (int) ncol), conta_proteggi);
        SEXP rows_names_r = Proteggi(Rf_allocVector(VECSXP, (int) rows_names_c.size()), conta_proteggi);
        SEXP cols_names_r = Proteggi(Rf_allocVector(VECSXP, (int) cols_names_c.size()), conta_proteggi);
        for (std::uint_fast64_t riga = 0; riga < nrow; ++riga) {
            SET_VECTOR_ELT(rows_names_r, (long) riga, Rf_mkChar(rows_names_c.at(riga).c_str()));
            for (std::uint_fast64_t colonna = 0; colonna < ncol; ++colonna) {
                auto v = (*r_c)(riga, colonna);
                REAL(r_r)[riga + nrow * colonna] = v;
            }
        }
        for (std::uint_fast64_t colonna = 0; colonna < ncol; ++colonna) {
            SET_VECTOR_ELT(cols_names_r, (long) colonna, Rf_mkChar(cols_names_c.at(colonna).c_str()));
        }
        SEXP dimnames = Proteggi(Rf_allocVector(VECSXP, 2), conta_proteggi);
        SET_VECTOR_ELT(dimnames, 0, rows_names_r);
        SET_VECTOR_ELT(dimnames, 1, cols_names_r);
        Rf_setAttrib(r_r, R_DimNamesSymbol, dimnames);

        SET_VECTOR_ELT(result_r, (long) k, r_r);

        SET_VECTOR_ELT(result_r_names, (long) k, Rf_mkChar(functions_name.at(k).c_str()));
    }

    SEXP n_r = Proteggi(Rf_allocVector(INTSXP, 1), conta_proteggi);
    INTEGER(n_r)[0] = (int) le_count;

    SET_VECTOR_ELT(result_r, eval_results.size(), n_r);
    SET_VECTOR_ELT(result_r_names, eval_results.size(), Rf_mkChar("n"));
    Rf_setAttrib(result_r, R_NamesSymbol, result_r_names);

    return result_r;


}


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

BubleyDyerMRPGenerator* BubleyDyerMRPGenerator::BuildBubleyDyerMRPGenerator(POSetWrap* poset, std::shared_ptr<Random> rnd) {
    auto result = new BubleyDyerMRPGenerator();
    result->mrp = std::make_shared<Matrice<double>>(poset->poset->size(), poset->poset->size());
    auto poss = std::make_shared<std::vector<std::shared_ptr<POSet>>>();
    poss->push_back(poset->poset);
    result->le_generator = std::make_shared<LEGBubleyDyer>(poss, rnd);
    result->le_generator->start(0);
    return result;
}

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

SEXP BubleyDyerMRPGenerator::BuildMRP(std::uint_fast64_t quante,
                          std::shared_ptr<double> errore,
                          std::uint_fast64_t output_ogni_in_sec,
                          int& conta_proteggi) {
    if (errore == nullptr && quante == std::numeric_limits<std::uint_fast64_t>::max()) {
        std::string err_str = "The number of le extensions to generate or the error must be provided.";
        throw_line(err_str);
    }

    if (errore != nullptr && quante != std::numeric_limits<std::uint_fast64_t>::max()) {
        std::string err_str = "Parameter error is ignored";
        forward_warning_to_r(err_str);
    }
    std::vector<std::shared_ptr<Matrice<double>>> eval_results(1);
    auto e_stato_aggiornato = true;
    if (!used) {
        if (quante == std::numeric_limits<std::uint_fast64_t>::max()) {
            quante = le_generator->evaluateNumberOfIteration(*errore);
        }
        le_generator->start(quante);
    } else {
        e_stato_aggiornato = le_generator->UpdateCounters(quante, errore);
        if (!e_stato_aggiornato) {
            std::string message = "Desidered distance from uniformity (error) already reached. No additional linear extension generated.";
            Rprintf("%s\n", message.c_str());
        } else {
            le_generator->next();
        }
    }
    eval_results.at(0) = mrp;
    auto poset = le_generator->posets->at(0);
    std::uint_fast64_t nrow = poset->size();
    std::uint_fast64_t ncol = poset->size();

    std::uint_fast64_t total_le = le_generator->currentNumberOfLE() - 1;
    if (e_stato_aggiornato) {
        used = true;
        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;
        std::uint_fast64_t total_number_of_extension = le_generator->numberOfLE() - le_generator->currentNumberOfLE() + 1;
        bool end_process = false;

        std::shared_ptr<DisplayMessage> displayMessage = nullptr;
        if (output_ogni_in_sec == std::numeric_limits<std::uint_fast64_t>::max()) {
            displayMessage = std::make_shared<DisplayMessageNull>();
        } else {
            displayMessage = std::make_shared<DisplayMessageEvaluationR>(total_number_of_extension, le_count, output_ogni_in_sec);
        }
        poset->evaluation(fles, *le_generator, tle, eval_results, le_count, end_process, displayMessage);
        total_le += le_count;
    }


    SEXP matrice = Proteggi(Rf_allocMatrix(REALSXP, (int) nrow, (int) ncol), conta_proteggi);
    auto matrice_names = Proteggi(Rf_allocVector(VECSXP, (int) nrow), conta_proteggi);
    auto poset_elements = poset->Elements();

    for (long riga = 0; riga < ((long) nrow); ++riga) {
        SET_VECTOR_ELT(matrice_names, riga, Rf_mkChar(poset_elements->at((unsigned long) riga).c_str()));
        for (long colonna = 0; colonna < ((long) ncol); ++colonna) {
            auto v = (*mrp)((unsigned long) riga, (unsigned long) colonna);
            REAL(matrice)[riga + ((long) nrow) * colonna] = v;
        }
    }

    SEXP dim_matrice_names = Proteggi(Rf_allocVector(VECSXP, 2), conta_proteggi);
    SET_VECTOR_ELT(dim_matrice_names, 0, matrice_names);
    SET_VECTOR_ELT(dim_matrice_names, 1, matrice_names);
    Rf_setAttrib(matrice, R_DimNamesSymbol, dim_matrice_names);


    SEXP n_r = Proteggi(Rf_allocVector(INTSXP, 1), conta_proteggi);
    INTEGER(n_r)[0] = (int) total_le;

    auto result_r = Proteggi(Rf_allocVector(VECSXP, 2), conta_proteggi);
    auto result_r_names = Proteggi(Rf_allocVector(VECSXP, 2), conta_proteggi);

    SET_VECTOR_ELT(result_r, 0, matrice);
    SET_VECTOR_ELT(result_r_names, 0, Rf_mkChar("mrp"));

    SET_VECTOR_ELT(result_r, 1, n_r);
    SET_VECTOR_ELT(result_r_names, 1, Rf_mkChar("n"));

    Rf_setAttrib(result_r, R_NamesSymbol, result_r_names);

    return result_r;
}

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

BubleyDyerEvaluationGenerator* BubleyDyerEvaluationGenerator::BuildBubleyDyerEvaluationGenerator(POSetWrap* poset,
                                                                                                 std::shared_ptr<Random> rnd,
                                                                                                 std::vector<std::string>& internal_functions,
                                                                                                 std::vector<SEXP>& external_functions) {
    auto result = new BubleyDyerEvaluationGenerator();
    result->eval_results.assign(internal_functions.size(), nullptr);
    result->fles.assign(internal_functions.size(), nullptr);
    result->functions_name.assign(internal_functions.size(), "");

    for (std::uint_fast64_t k = 0; k < internal_functions.size(); ++k) {
        auto nome_funzione = internal_functions.at(k);
        auto r_funzione = external_functions.at(k);
        if (POSetWrap::functionLinearMapType.find(nome_funzione) == POSetWrap::functionLinearMapType.end()) {
            std::string err_str = "Wrong function name: " + nome_funzione;
            throw_line(err_str);
        }
        std::shared_ptr<FunctionLinearExtension> fle = nullptr;
        std::string function_name = "";

        auto function_type = POSetWrap::functionLinearMapType.at(nome_funzione);
        switch (function_type) {
            case POSetWrap::FunctionLinearType::FLETMutualRankingProbability:
                fle = std::make_shared<FLEMutualRankingProbability>(poset->poset);
                function_name = "MutualRankingProbability";
                break;
            case POSetWrap::FunctionLinearType::FLETAverageHeight:
                fle = std::make_shared<FLEAverageHeight>(poset->poset);
                function_name = "AverageHeight";
                break;
            case POSetWrap::FunctionLinearType::FLETSeparationAsymmetricLower:
                fle = std::make_shared<FLESeparationAsymmetricLower>(poset->poset);
                function_name = "asymmetricLower";
                break;
            case POSetWrap::FunctionLinearType::FLETSeparationAsymmetricUpper:
                fle = std::make_shared<FLESeparationAsymmetricUpper>(poset->poset);
                function_name = "asymmetricUpper";
                break;
            case POSetWrap::FunctionLinearType::FLETSeparationSymmetric:
                fle = std::make_shared<FLESeparationSymmetric>(poset->poset);
                function_name = "symmetric";
                break;
            case POSetWrap::FunctionLinearType::FLETRFunction:
                //std::string message = "FLETRFunction: " + std::to_string(k);
                //Rprintf("%s\n", message.c_str());
                fle = std::make_shared<FLERinterface>(poset->poset, r_funzione);
                function_name = "RFunction";
                break;
        }
        auto shape = fle->shape();
        std::uint_fast64_t nrow = shape.at(0);
        std::uint_fast64_t ncol = shape.at(1);
        result->eval_results.at(k) = std::make_shared<Matrice<double>>(nrow, ncol);
        result->fles.at(k) = fle;
        result->functions_name.at(k) = function_name;
    }

    auto poss = std::make_shared<std::vector<std::shared_ptr<POSet>>>();
    poss->push_back(poset->poset);
    result->le_generator = std::make_shared<LEGBubleyDyer>(poss, rnd);
    result->le_generator->start(0);
    return result;
}

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

SEXP BubleyDyerEvaluationGenerator::Evaluation(std::uint_fast64_t quante,
                                               std::shared_ptr<double> errore,
                                               std::uint_fast64_t output_ogni_in_sec,
                                               int& conta_proteggi) {
    if (errore == nullptr && quante == std::numeric_limits<std::uint_fast64_t>::max()) {
        std::string err_str = "The number of le extensions to generate or the error must be provided.";
        throw_line(err_str);
    }

    if (errore != nullptr && quante != std::numeric_limits<std::uint_fast64_t>::max()) {
        std::string err_str = "Parameter error is ignored";
        forward_warning_to_r(err_str);
    }

    auto poset = le_generator->posets->at(0);

    auto e_stato_aggiornato = true;
    if (used == false) {
        if (quante == std::numeric_limits<std::uint_fast64_t>::max()) {
            quante = le_generator->evaluateNumberOfIteration(*errore);
        }
        le_generator->start(quante);
    } else {
        e_stato_aggiornato = le_generator->UpdateCounters(quante, errore);
        if (!e_stato_aggiornato) {
            std::string message = "Desidered distance from uniformity (error) already reached. No additional linear extension generated.";
            Rprintf("%s\n", message.c_str());
        } else {
            le_generator->next();
        }
    }
    std::uint_fast64_t total_le = le_generator->currentNumberOfLE() - 1;
    if (e_stato_aggiornato) {
        used = true;
        TEItentity tle(poset->Elements());
        std::uint_fast64_t le_count = 0;
        std::uint_fast64_t total_number_of_extension = le_generator->numberOfLE() - le_generator->currentNumberOfLE() + 1;
        bool end_process = false;

        std::shared_ptr<DisplayMessage> displayMessage = nullptr;
        if (output_ogni_in_sec == std::numeric_limits<std::uint_fast64_t>::max()) {
            displayMessage = std::make_shared<DisplayMessageNull>();
        } else {
            displayMessage = std::make_shared<DisplayMessageEvaluationR>(total_number_of_extension, le_count, output_ogni_in_sec);
        }
        poset->evaluation(fles, *le_generator, tle, eval_results, le_count, end_process, displayMessage);
        total_le += le_count;
    }

    auto result_r = Proteggi(Rf_allocVector(VECSXP, (long) (eval_results.size() + 1)), conta_proteggi);
    auto result_r_names = Proteggi(Rf_allocVector(VECSXP, (long) (eval_results.size() + 1)), conta_proteggi);

    for (std::uint_fast64_t k = 0; k < eval_results.size(); ++k) {
        auto r_c = eval_results.at(k);
        std::uint_fast64_t nrow = r_c->Rows();
        std::uint_fast64_t ncol = r_c->Cols();


        auto rows_names_c = fles.at(k)->rowsName();
        auto cols_names_c = fles.at(k)->colsName();

        SEXP r_r = Proteggi(Rf_allocMatrix(REALSXP, (int) nrow, (int) ncol), conta_proteggi);
        SEXP rows_names_r = Proteggi(Rf_allocVector(VECSXP, (int) rows_names_c.size()), conta_proteggi);
        SEXP cols_names_r = Proteggi(Rf_allocVector(VECSXP, (int) cols_names_c.size()), conta_proteggi);
        for (std::uint_fast64_t riga = 0; riga < nrow; ++riga) {
            SET_VECTOR_ELT(rows_names_r, (long) riga, Rf_mkChar(rows_names_c.at(riga).c_str()));
            for (std::uint_fast64_t colonna = 0; colonna < ncol; ++colonna) {
                auto v = (*r_c)(riga, colonna);
                REAL(r_r)[riga + nrow * colonna] = v;
            }
        }
        for (std::uint_fast64_t colonna = 0; colonna < ncol; ++colonna) {
            SET_VECTOR_ELT(cols_names_r, (long) colonna, Rf_mkChar(cols_names_c.at(colonna).c_str()));
        }
        SEXP dimnames = Proteggi(Rf_allocVector(VECSXP, 2), conta_proteggi);
        SET_VECTOR_ELT(dimnames, 0, rows_names_r);
        SET_VECTOR_ELT(dimnames, 1, cols_names_r);
        Rf_setAttrib(r_r, R_DimNamesSymbol, dimnames);

        SET_VECTOR_ELT(result_r, (long) k, r_r);

        SET_VECTOR_ELT(result_r_names, (long) k, Rf_mkChar(functions_name.at(k).c_str()));
    }

    SEXP n_r = Proteggi(Rf_allocVector(INTSXP, 1), conta_proteggi);
    INTEGER(n_r)[0] = (int) total_le;

    SET_VECTOR_ELT(result_r, eval_results.size(), n_r);
    SET_VECTOR_ELT(result_r_names, eval_results.size(), Rf_mkChar("n"));
    Rf_setAttrib(result_r, R_NamesSymbol, result_r_names);

    return result_r;
}
