<commit_before>/*
 * (c) Copyright Ascensio System SIA 2010-2019
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
 * street, Riga, Latvia, EU, LV-1050.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */
#include "FileDownloader_private.h"

#include <iostream>
#include <unistd.h>
#include "../../DesktopEditor/common/Directory.h"

#ifndef USE_EXTERNAL_DOWNLOAD

#include <fcntl.h>
#include <curl/curl.h>
#include <curl/easy.h>
#include <stdio.h>

#else

#include <unistd.h>
#include <sys/wait.h>

std::string wget_url_validate(const std::string& url)
{
    std::string::size_type pos = 0;
    const char* url_ptr = url.c_str();
    while ('-' == *url_ptr++) // '\0' => break
        ++pos;
    if (*url_ptr == '\0')
        return "";

    return url.substr(pos);
}

int download_external(const std::wstring& sUrl, const std::wstring& sOutput)
{
    int nReturnCode = -1;

    std::string sUrlA = U_TO_UTF8(sUrl);
    //sUrlA =("\"" + sUrlA + "\"");
    std::string sOutputA = U_TO_UTF8(sOutput);
    //sOutputA =("\"" + sOutputA + "\"");

    if (0 != nReturnCode && NSFile::CFileBinary::Exists(L"/usr/bin/curl"))
    {
        pid_t pid = fork(); // create child process
        int status;

        switch (pid)
        {
        case -1: // error
            break;

        case 0: // child process
        {
            const char* nargs[8];
            nargs[0] = "/usr/bin/curl";
            nargs[1] = "--url";
            nargs[2] = sUrlA.c_str();
            nargs[3] = "--output";
            nargs[4] = sOutputA.c_str();
            nargs[5] = "--silent";
            nargs[6] = "-L";
            nargs[7] = NULL;

            const char* nenv[3];
            nenv[0] = "LD_PRELOAD=";
            nenv[1] = "LD_LIBRARY_PATH=";
            nenv[2] = NULL;

            execve("/usr/bin/curl", (char * const *)nargs, (char * const *)nenv);
            exit(EXIT_SUCCESS);
            break;
        }
        default: // parent process, pid now contains the child pid
            while (-1 == waitpid(pid, &status, 0)); // wait for child to complete
            if (WIFEXITED(status))
            {
                nReturnCode =  WEXITSTATUS(status);
            }
            break;
        }
    }

    if (0 != nReturnCode && NSFile::CFileBinary::Exists(L"/usr/bin/wget"))
    {
        std::string sUrlValidateA = wget_url_validate(sUrlA);

        pid_t pid = fork(); // create child process
        int status;

        switch (pid)
        {
        case -1: // error
            break;

        case 0: // child process
        {
            const char* nargs[6];
            nargs[0] = "/usr/bin/wget";
            nargs[1] = sUrlValidateA.c_str();
            nargs[2] = "-O";
            nargs[3] = sOutputA.c_str();
            nargs[4] = "-q";
            nargs[5] = NULL;

            const char* nenv[2];
            nenv[0] = "LD_PRELOAD=";
            nenv[1] = NULL;

            execve("/usr/bin/wget", (char * const *)nargs, (char * const *)nenv);
            exit(EXIT_SUCCESS);
            break;
        }
        default: // parent process, pid now contains the child pid
            while (-1 == waitpid(pid, &status, 0)); // wait for child to complete
            if (WIFEXITED(status))
            {
                nReturnCode =  WEXITSTATUS(status);
            }
            break;
        }
    }

    if (0 == nReturnCode)
    {
        if (!NSFile::CFileBinary::Exists(sOutput))
            nReturnCode = -1;
    }

    return nReturnCode;
}

#endif

class CFileDownloaderBaseCURL : public CFileDownloaderBase
{
public :
    CFileDownloaderBaseCURL(std::wstring sFileUrl, bool bDelete = true)
        : CFileDownloaderBase(sFileUrl, bDelete)
    {
    }
    virtual ~CFileDownloaderBaseCURL()
    {
        if (m_bDelete && !m_sFilePath.empty())
        {
            std::string sFilePath = U_TO_UTF8(m_sFilePath);
            unlink(sFilePath.c_str());
        }
    }

#ifndef USE_EXTERNAL_DOWNLOAD
    static size_t write_data(void *ptr, size_t size, size_t nmemb, int fd) {
        size_t written = write(fd, ptr, size * nmemb);
        return written;
    }

    virtual int DownloadFile()
    {
        CURL *curl;
        int fp;
        CURLcode res;
        std::string sUrl = U_TO_UTF8(m_sFileUrl);
        std::string sOut;
        const char *url = sUrl.c_str();
        curl = curl_easy_init();
        if (curl)
        {
           fp = createUniqueTempFile(sOut);
           curl_easy_setopt(curl, CURLOPT_URL, url);
           curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
           curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
#if defined(__linux__)
           //в linux нет встроенных в систему корневых сертификатов, поэтому отключаем проверку
           //http://curl.haxx.se/docs/sslcerts.html
           curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
#endif
           /* tell libcurl to follow redirection(default false) */
           curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
           /* some servers don't like requests that are made without a user-agent field, so we provide one */
           curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0");
           res = curl_easy_perform(curl);
           /* always cleanup */
           curl_easy_cleanup(curl);
           close(fp);
        }

        m_bComplete = (CURLE_OK == res);
        if (m_bComplete)
        {
            if (m_sFilePath.empty())
                m_sFilePath = NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)sOut.c_str(), sOut.length());
            else
                NSFile::CFileBinary::Move(UTF8_TO_U(sOut), m_sFilePath);
        }
        //int nRes = execl("/usr/bin/wget", stringWstingToUtf8String (m_sFileUrl).c_str(), "-P", stringWstingToUtf8String (m_sFilePath).c_str(), (char *)NULL);
        //m_bComplete = nRes >= 0;

        return m_bComplete ? 0 : 1;
    }

protected:
    int createUniqueTempFile (std::string &filename)
    {
        std::string sTempPath = NSFile::CUtf8Converter::GetUtf8StringFromUnicode(NSDirectory::GetTempPath());
        sTempPath += "/fileXXXXXX";
        int fd = mkstemp(const_cast <char *> (sTempPath.c_str()));
        if (-1 != fd)
            filename = sTempPath;
        return fd;
    }
#else
    virtual int DownloadFile()
    {
        if (m_sFilePath.empty())
        {
            m_sFilePath = NSFile::CFileBinary::CreateTempFileWithUniqueName(NSDirectory::GetTempPath(), L"DW");
            if (NSFile::CFileBinary::Exists(m_sFilePath))
                NSFile::CFileBinary::Remove(m_sFilePath);
        }
        return download_external(m_sFileUrl, m_sFilePath);
    }

#endif
};

CFileDownloader_private::CFileDownloader_private(std::wstring sFileUrl, bool bDelete)
{
    m_pInternal = new CFileDownloaderBaseCURL(sFileUrl, bDelete);
}
<commit_msg>Add timeout to curl/wget<commit_after>/*
 * (c) Copyright Ascensio System SIA 2010-2019
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
 * street, Riga, Latvia, EU, LV-1050.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */
#include "FileDownloader_private.h"

#include <iostream>
#include <unistd.h>
#include "../../DesktopEditor/common/Directory.h"

#ifndef USE_EXTERNAL_DOWNLOAD

#include <fcntl.h>
#include <curl/curl.h>
#include <curl/easy.h>
#include <stdio.h>

#else

#include <unistd.h>
#include <sys/wait.h>

std::string wget_url_validate(const std::string& url)
{
    std::string::size_type pos = 0;
    const char* url_ptr = url.c_str();
    while ('-' == *url_ptr++) // '\0' => break
        ++pos;
    if (*url_ptr == '\0')
        return "";

    return url.substr(pos);
}

int download_external(const std::wstring& sUrl, const std::wstring& sOutput)
{
    int nReturnCode = -1;

    std::string sUrlA = U_TO_UTF8(sUrl);
    //sUrlA =("\"" + sUrlA + "\"");
    std::string sOutputA = U_TO_UTF8(sOutput);
    //sOutputA =("\"" + sOutputA + "\"");

    if (0 != nReturnCode && NSFile::CFileBinary::Exists(L"/usr/bin/curl"))
    {
        pid_t pid = fork(); // create child process
        int status;

        switch (pid)
        {
        case -1: // error
            break;

        case 0: // child process
        {
            const char* nargs[10];
            nargs[0] = "/usr/bin/curl";
            nargs[1] = "--url";
            nargs[2] = sUrlA.c_str();
            nargs[3] = "--output";
            nargs[4] = sOutputA.c_str();
            nargs[5] = "--silent";
            nargs[6] = "-L";
            nargs[7] = "--connect-timeout";
            nargs[8] = "10";
            nargs[9] = NULL;

            const char* nenv[3];
            nenv[0] = "LD_PRELOAD=";
            nenv[1] = "LD_LIBRARY_PATH=";
            nenv[2] = NULL;

            execve("/usr/bin/curl", (char * const *)nargs, (char * const *)nenv);
            exit(EXIT_SUCCESS);
            break;
        }
        default: // parent process, pid now contains the child pid
            while (-1 == waitpid(pid, &status, 0)); // wait for child to complete
            if (WIFEXITED(status))
            {
                nReturnCode =  WEXITSTATUS(status);
            }
            break;
        }
    }

    if (0 != nReturnCode && NSFile::CFileBinary::Exists(L"/usr/bin/wget"))
    {
        std::string sUrlValidateA = wget_url_validate(sUrlA);

        pid_t pid = fork(); // create child process
        int status;

        switch (pid)
        {
        case -1: // error
            break;

        case 0: // child process
        {
            const char* nargs[8];
            nargs[0] = "/usr/bin/wget";
            nargs[1] = sUrlValidateA.c_str();
            nargs[2] = "-O";
            nargs[3] = sOutputA.c_str();
            nargs[4] = "-q";
            nargs[5] = "--connect-timeout=10";
            nargs[6] = "--tries=2";
            nargs[7] = NULL;

            const char* nenv[2];
            nenv[0] = "LD_PRELOAD=";
            nenv[1] = NULL;

            execve("/usr/bin/wget", (char * const *)nargs, (char * const *)nenv);
            exit(EXIT_SUCCESS);
            break;
        }
        default: // parent process, pid now contains the child pid
            while (-1 == waitpid(pid, &status, 0)); // wait for child to complete
            if (WIFEXITED(status))
            {
                nReturnCode =  WEXITSTATUS(status);
            }
            break;
        }
    }

    if (0 == nReturnCode)
    {
        if (!NSFile::CFileBinary::Exists(sOutput))
            nReturnCode = -1;
    }

    return nReturnCode;
}

#endif

class CFileDownloaderBaseCURL : public CFileDownloaderBase
{
public :
    CFileDownloaderBaseCURL(std::wstring sFileUrl, bool bDelete = true)
        : CFileDownloaderBase(sFileUrl, bDelete)
    {
    }
    virtual ~CFileDownloaderBaseCURL()
    {
        if (m_bDelete && !m_sFilePath.empty())
        {
            std::string sFilePath = U_TO_UTF8(m_sFilePath);
            unlink(sFilePath.c_str());
        }
    }

#ifndef USE_EXTERNAL_DOWNLOAD
    static size_t write_data(void *ptr, size_t size, size_t nmemb, int fd) {
        size_t written = write(fd, ptr, size * nmemb);
        return written;
    }

    virtual int DownloadFile()
    {
        CURL *curl;
        int fp;
        CURLcode res;
        std::string sUrl = U_TO_UTF8(m_sFileUrl);
        std::string sOut;
        const char *url = sUrl.c_str();
        curl = curl_easy_init();
        if (curl)
        {
           fp = createUniqueTempFile(sOut);
           curl_easy_setopt(curl, CURLOPT_URL, url);
           curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
           curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
#if defined(__linux__)
           //в linux нет встроенных в систему корневых сертификатов, поэтому отключаем проверку
           //http://curl.haxx.se/docs/sslcerts.html
           curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
#endif
           /* tell libcurl to follow redirection(default false) */
           curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
           /* some servers don't like requests that are made without a user-agent field, so we provide one */
           curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0");
           res = curl_easy_perform(curl);
           /* always cleanup */
           curl_easy_cleanup(curl);
           close(fp);
        }

        m_bComplete = (CURLE_OK == res);
        if (m_bComplete)
        {
            if (m_sFilePath.empty())
                m_sFilePath = NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)sOut.c_str(), sOut.length());
            else
                NSFile::CFileBinary::Move(UTF8_TO_U(sOut), m_sFilePath);
        }
        //int nRes = execl("/usr/bin/wget", stringWstingToUtf8String (m_sFileUrl).c_str(), "-P", stringWstingToUtf8String (m_sFilePath).c_str(), (char *)NULL);
        //m_bComplete = nRes >= 0;

        return m_bComplete ? 0 : 1;
    }

protected:
    int createUniqueTempFile (std::string &filename)
    {
        std::string sTempPath = NSFile::CUtf8Converter::GetUtf8StringFromUnicode(NSDirectory::GetTempPath());
        sTempPath += "/fileXXXXXX";
        int fd = mkstemp(const_cast <char *> (sTempPath.c_str()));
        if (-1 != fd)
            filename = sTempPath;
        return fd;
    }
#else
    virtual int DownloadFile()
    {
        if (m_sFilePath.empty())
        {
            m_sFilePath = NSFile::CFileBinary::CreateTempFileWithUniqueName(NSDirectory::GetTempPath(), L"DW");
            if (NSFile::CFileBinary::Exists(m_sFilePath))
                NSFile::CFileBinary::Remove(m_sFilePath);
        }
        return download_external(m_sFileUrl, m_sFilePath);
    }

#endif
};

CFileDownloader_private::CFileDownloader_private(std::wstring sFileUrl, bool bDelete)
{
    m_pInternal = new CFileDownloaderBaseCURL(sFileUrl, bDelete);
}
<|endoftext|>


<commit_before>#include <tiramisu/auto_scheduler/search_method.h>
#include <random>

namespace tiramisu::auto_scheduler
{

void beam_search::search(syntax_tree& ast)
{
    if (ast.nb_explored_optims % NB_OPTIMIZATIONS == 0)
        ast.clear_new_optimizations();

    std::vector<syntax_tree*> children;

    // Look for an optimization that can be applied
    int nb_optims_tried = 0;
    int nb_explored_optims = ast.nb_explored_optims;

    while (children.size() == 0 && nb_optims_tried < NB_OPTIMIZATIONS && nb_explored_optims < max_depth)
    {
        optimization_type optim_type = DEFAULT_OPTIMIZATIONS_ORDER[nb_explored_optims % NB_OPTIMIZATIONS];
        children = scheds_gen->generate_schedules(ast, optim_type);

        nb_explored_optims++;
        nb_optims_tried++;
    }

    // Stop if no more optimizations can be applied
    if (children.size() == 0)
        return ;

    // Evaluate children and sort them from smallest to highest evaluation
    for (syntax_tree *child : children)
    {
        child->nb_explored_optims = nb_explored_optims;
        child->transform_ast();

        child->evaluation = eval_func->evaluate(*child);

        child->print_previous_optims();
        std::cout << "-----------" << std::endl;
        child->print_new_optims();
        child->print_ast();
        std::cout << "Evaluation : " << child->evaluation << std::endl << std::endl;

        if (child->evaluation < best_evaluation)
        {
            best_evaluation = child->evaluation;
            best_ast = child;
        }

        nb_explored_schedules++;
    }

    // Stop if we reached the maximum depth
    if (nb_explored_optims >= max_depth)
        return ;

    // Add the current AST to the list of children
    syntax_tree *ast_copy = ast.copy_ast();
    ast_copy->nb_explored_optims = nb_explored_optims;
    children.push_back(ast_copy);

    // Sort children from smallest evaluation to largest
    std::sort(children.begin(), children.end(), [](syntax_tree *a, syntax_tree *b) {
        return a->evaluation < b->evaluation;
    });

    // keep the top 'beam_size' children and delete the rest
    for (int i = beam_size; i < children.size(); ++i)
        delete children[i];

    children.resize(std::min(beam_size, (int)children.size()));

    // Search recursively on the best children
    for (syntax_tree *child : children)
    {
        child->search_depth = ast.search_depth + 1;
        search(*child);
    }
}

void beam_search::search_save(syntax_tree& ast, std::vector<std::string> *schedules_annotations)
{
    if (ast.nb_explored_optims % NB_OPTIMIZATIONS == 0)
        ast.clear_new_optimizations();

    std::vector<syntax_tree*> children;

    // Look for an optimization that can be applied
    int nb_optims_tried = 0;
    int nb_explored_optims = ast.nb_explored_optims;

    while (children.size() == 0 && nb_optims_tried < NB_OPTIMIZATIONS && nb_explored_optims < max_depth)
    {
        optimization_type optim_type = DEFAULT_OPTIMIZATIONS_ORDER[nb_explored_optims % NB_OPTIMIZATIONS];
        children = scheds_gen->generate_schedules(ast, optim_type);

        nb_explored_optims++;
        nb_optims_tried++;
    }

    // Stop if no more optimizations can be applied
    if (children.size() == 0)
        return ;

    // Evaluate children and sort them from smallest to highest evaluation
    for (syntax_tree *child : children)
    {
        child->nb_explored_optims = nb_explored_optims;
        child->transform_ast();

        child->evaluation =  eval_func->evaluate(*child);

        std::string schedule_annot = evaluate_by_learning_model::get_schedule_json(*child);

        //remove the last two characters }\n
        schedule_annot.pop_back();
        schedule_annot.pop_back();

        if (std::isfinite(child->evaluation)) // the evaluation is not finite mean that the schedule didn't run
            schedule_annot += ", \n\"execution_time\" : " + std::to_string(child->evaluation) + "\n}\n";
        else
            schedule_annot += ", \n\"execution_time\" : null\n}\n";

        schedules_annotations->push_back(schedule_annot);

        if (child->evaluation < best_evaluation)
        {
            best_evaluation = child->evaluation;
            best_ast = child;
        }

        nb_explored_schedules++;
    }

    // Stop if we reached the maximum depth
    if (nb_explored_optims >= max_depth)
        return ;

    // Add the current AST to the list of children
    syntax_tree *ast_copy = ast.copy_ast();
    ast_copy->nb_explored_optims = nb_explored_optims;
    children.push_back(ast_copy);

    // Sort children from smallest evaluation to largest
    std::sort(children.begin(), children.end(), [](syntax_tree *a, syntax_tree *b) {
        return a->evaluation < b->evaluation;
    });

    // keep the top 'beam_size' children and delete the rest
    for (int i = beam_size; i < children.size(); ++i)
        delete children[i];

    children.resize(std::min(beam_size, (int)children.size()));

    // Search recursively on the best children
    for (syntax_tree *child : children)
    {
        child->search_depth = ast.search_depth + 1;
        search_save(*child, schedules_annotations);
    }
}

void mcts::search(syntax_tree& ast)
{
    std::default_random_engine rand_generator;

    std::vector<syntax_tree*> samples;
    std::vector<syntax_tree*> children;
    std::vector<double> children_evals;

    for (int epoch = 0; epoch < nb_samples; ++epoch)
    {
        // Starting from the initial ast, generate optimizations until reaching max_depth
        syntax_tree *ast_sample = *
        for (int depth = 0; depth < max_depth; ++depth)
        {
            optimization_type optim_type = DEFAULT_OPTIMIZATIONS_ORDER[depth % NB_OPTIMIZATIONS];
            children = scheds_gen->generate_schedules(*ast_sample, optim_type);

            if (children.empty())
                continue;

            children_evals.clear();

            for (syntax_tree *child : children)
            {
                child->transform_ast();

                child->evaluation = eval_func->evaluate(*child);
                children_evals.push_back(child->evaluation);

                nb_explored_schedules++;
            }

            // Add the current AST to the list of children
            children.push_back(ast_sample->copy_ast());
            children_evals.push_back(ast_sample->evaluation);

            // Sample an AST
            std::discrete_distribution<int> dist(children_evals.begin(), children_evals.end());
            ast_sample = children[dist(rand_generator)];

            samples.push_back(ast_sample);
        }
    }

    if (samples.empty())
        return ;

    // Sort schedules with respect to evaluations
    std::sort(samples.begin(), samples.end(), [](syntax_tree *a, syntax_tree *b) {
        return a->evaluation < b->evaluation;
    });

    // Execute top-k schedules and return the best
    for (int i = 0; i < topk; ++i)
    {
        float exec_time = exec_eval->evaluate(*samples[i]);
        if (exec_time < best_evaluation)
        {
            best_evaluation = exec_time;
            best_ast = samples[i];
        }
    }
}

void mcts::search_save(syntax_tree& ast, std::vector<std::string> *schedules_annotations)
{
    std::cerr<< "mcts::search_save not yet implemented" << std::endl;
    exit(1);
}

// -------------------------------------------------------------------------- //

void beam_search_topk::search(syntax_tree& ast)
{
    // Do a beam search
    beam_search_subroutine(ast);

    // Sort schedules found
    std::sort(schedules.begin(), schedules.end(), [](syntax_tree *a, syntax_tree *b) {
        return a->evaluation < b->evaluation;
    });

    // Execute top-k schedules to find the best
    for (int i = 0; i < topk; ++i)
    {
        float exec_time = exec_eval->evaluate(*schedules[i]);
        if (exec_time < best_evaluation)
        {
            best_evaluation = exec_time;
            best_ast = schedules[i];
        }
    }
}

void beam_search_topk::search_save(syntax_tree& ast, std::vector<std::string> *schedules_annotations)
{
    std::cerr<< "beam_search_topk::search_save not yet implemented" << std::endl;
    exit(1);
}

void beam_search_topk::beam_search_subroutine(syntax_tree& ast)
{
    if (ast.nb_explored_optims % NB_OPTIMIZATIONS == 0)
        ast.clear_new_optimizations();

    std::vector<syntax_tree*> children;

    // Look for an optimization that can be applied
    int nb_optims_tried = 0;
    int nb_explored_optims = ast.nb_explored_optims;

    while (children.size() == 0 && nb_optims_tried < NB_OPTIMIZATIONS && nb_explored_optims < max_depth)
    {
        optimization_type optim_type = DEFAULT_OPTIMIZATIONS_ORDER[nb_explored_optims % NB_OPTIMIZATIONS];
        children = scheds_gen->generate_schedules(ast, optim_type);

        nb_explored_optims++;
        nb_optims_tried++;
    }

    // Stop if no more optimizations can be applied
    if (children.size() == 0)
        return ;

    // Evaluate children and sort them from smallest to highest evaluation
    for (syntax_tree *child : children)
    {
        child->nb_explored_optims = nb_explored_optims;
        child->transform_ast();

        child->evaluation = eval_func->evaluate(*child);

        nb_explored_schedules++;
    }

    // Add the current AST to the list of children
    syntax_tree *ast_copy = ast.copy_ast();
    ast_copy->nb_explored_optims = nb_explored_optims;
    children.push_back(ast_copy);

    // Sort children from smallest evaluation to largest
    std::sort(children.begin(), children.end(), [](syntax_tree *a, syntax_tree *b) {
        return a->evaluation < b->evaluation;
    });

    for (int i = 0; i < beam_size; ++i)
        schedules.push_back(children[i]);

    // Stop if we reached the maximum depth
    if (nb_explored_optims >= max_depth)
        return ;

    // Search recursively on the best children
    for (int i = beam_size; i < children.size(); ++i)
        delete children[i];

    children.resize(std::min(beam_size, (int)children.size()));

    for (syntax_tree *child : children)
    {
        child->search_depth = ast.search_depth + 1;
        search(*child);
    }
}

void beam_search_accuracy_evaluator::search(syntax_tree& ast)
{
    if (ast.nb_explored_optims % NB_OPTIMIZATIONS == 0)
        ast.clear_new_optimizations();

    std::vector<syntax_tree*> children;

    // Look for an optimization that can be applied
    int nb_optims_tried = 0;
    int nb_explored_optims = ast.nb_explored_optims;

    while (children.size() == 0 && nb_optims_tried < NB_OPTIMIZATIONS && nb_explored_optims < max_depth)
    {
        optimization_type optim_type = DEFAULT_OPTIMIZATIONS_ORDER[nb_explored_optims % NB_OPTIMIZATIONS];
        children = scheds_gen->generate_schedules(ast, optim_type);

        nb_explored_optims++;
        nb_optims_tried++;
    }

    // Stop if no more optimizations can be applied
    if (children.size() == 0)
        return ;

    // Evaluate children and sort them from smallest to highest evaluation
    for (syntax_tree *child : children)
    {
        child->nb_explored_optims = nb_explored_optims;
        child->transform_ast();

        child->evaluation = eval_func->evaluate(*child);

        // We evaluate both by the model and by execution
        model_evals_list.push_back(child->evaluation);
        exec_evals_list.push_back(exec_eval->evaluate(*child));

        if (child->evaluation < best_evaluation)
        {
            best_evaluation = child->evaluation;
            best_ast = child;
        }

        nb_explored_schedules++;
    }

    // Stop if we reached the maximum depth
    if (nb_explored_optims >= max_depth)
        return ;

    // Add the current AST to the list of children
    syntax_tree *ast_copy = ast.copy_ast();
    ast_copy->nb_explored_optims = nb_explored_optims;
    children.push_back(ast_copy);

    // Sort children from smallest evaluation to largest
    std::sort(children.begin(), children.end(), [](syntax_tree *a, syntax_tree *b) {
        return a->evaluation < b->evaluation;
    });

    // Search recursively on the best children
    for (int i = beam_size; i < children.size(); ++i)
        delete children[i];

    children.resize(std::min(beam_size, (int)children.size()));

    for (syntax_tree *child : children)
    {
        child->search_depth = ast.search_depth + 1;
        search(*child);
    }
}

}
<commit_msg>Added a verbose option for search space sampling<commit_after>#include <tiramisu/auto_scheduler/search_method.h>
#include <random>

namespace tiramisu::auto_scheduler
{

void beam_search::search(syntax_tree& ast)
{
    if (ast.nb_explored_optims % NB_OPTIMIZATIONS == 0)
        ast.clear_new_optimizations();

    std::vector<syntax_tree*> children;

    // Look for an optimization that can be applied
    int nb_optims_tried = 0;
    int nb_explored_optims = ast.nb_explored_optims;

    while (children.size() == 0 && nb_optims_tried < NB_OPTIMIZATIONS && nb_explored_optims < max_depth)
    {
        optimization_type optim_type = DEFAULT_OPTIMIZATIONS_ORDER[nb_explored_optims % NB_OPTIMIZATIONS];
        children = scheds_gen->generate_schedules(ast, optim_type);

        nb_explored_optims++;
        nb_optims_tried++;
    }

    // Stop if no more optimizations can be applied
    if (children.size() == 0)
        return ;

    // Evaluate children and sort them from smallest to highest evaluation
    for (syntax_tree *child : children)
    {
        child->nb_explored_optims = nb_explored_optims;
        child->transform_ast();

        child->evaluation = eval_func->evaluate(*child);

        child->print_previous_optims();
        std::cout << "-----------" << std::endl;
        child->print_new_optims();
        child->print_ast();
        std::cout << "Evaluation : " << child->evaluation << std::endl << std::endl;

        if (child->evaluation < best_evaluation)
        {
            best_evaluation = child->evaluation;
            best_ast = child;
        }

        nb_explored_schedules++;
    }

    // Stop if we reached the maximum depth
    if (nb_explored_optims >= max_depth)
        return ;

    // Add the current AST to the list of children
    syntax_tree *ast_copy = ast.copy_ast();
    ast_copy->nb_explored_optims = nb_explored_optims;
    children.push_back(ast_copy);

    // Sort children from smallest evaluation to largest
    std::sort(children.begin(), children.end(), [](syntax_tree *a, syntax_tree *b) {
        return a->evaluation < b->evaluation;
    });

    // keep the top 'beam_size' children and delete the rest
    for (int i = beam_size; i < children.size(); ++i)
        delete children[i];

    children.resize(std::min(beam_size, (int)children.size()));

    // Search recursively on the best children
    for (syntax_tree *child : children)
    {
        child->search_depth = ast.search_depth + 1;
        search(*child);
    }
}

void beam_search::search_save(syntax_tree& ast, std::vector<std::string> *schedules_annotations)
{
    if (ast.nb_explored_optims % NB_OPTIMIZATIONS == 0)
        ast.clear_new_optimizations();

    std::vector<syntax_tree*> children;

    // Look for an optimization that can be applied
    int nb_optims_tried = 0;
    int nb_explored_optims = ast.nb_explored_optims;

    while (children.size() == 0 && nb_optims_tried < NB_OPTIMIZATIONS && nb_explored_optims < max_depth)
    {
        optimization_type optim_type = DEFAULT_OPTIMIZATIONS_ORDER[nb_explored_optims % NB_OPTIMIZATIONS];
        children = scheds_gen->generate_schedules(ast, optim_type);

        nb_explored_optims++;
        nb_optims_tried++;
    }

    // Stop if no more optimizations can be applied
    if (children.size() == 0)
        return ;

    // Evaluate children and sort them from smallest to highest evaluation
    for (syntax_tree *child : children)
    {
        child->nb_explored_optims = nb_explored_optims;
        child->transform_ast();

        if (std::getenv("AS_VERBOSE")!=NULL)
            if (std::stoi(std::getenv("AS_VERBOSE"))==1){
                child->print_previous_optims();
                std::cout << "-----------" << std::endl;
                child->print_new_optims();
                child->print_ast();
            }

        child->evaluation =  eval_func->evaluate(*child);

        std::string schedule_annot = evaluate_by_learning_model::get_schedule_json(*child);

        //remove the last two characters }\n
        schedule_annot.pop_back();
        schedule_annot.pop_back();

        if (std::isfinite(child->evaluation)) // the evaluation is not finite mean that the schedule didn't run
            schedule_annot += ", \n\"execution_time\" : " + std::to_string(child->evaluation) + "\n}\n";
        else
            schedule_annot += ", \n\"execution_time\" : null\n}\n";

        schedules_annotations->push_back(schedule_annot);

        if (std::getenv("AS_VERBOSE")!=NULL)
            if (std::stoi(std::getenv("AS_VERBOSE"))==1){
                std::cout << "Schedule number "<< schedules_annotations->size() << std::endl;
                std::cout << "Evaluation : " << child->evaluation << std::endl << std::endl;
            }

        if (std::isinf(child->evaluation))
            std::cerr<< "Evaluation of schedule "<< schedules_annotations->size() <<" failed "<< std::endl;

        if (child->evaluation < best_evaluation)
        {
            best_evaluation = child->evaluation;
            best_ast = child;
        }

        nb_explored_schedules++;
    }

    // Stop if we reached the maximum depth
    if (nb_explored_optims >= max_depth)
        return ;

    // Add the current AST to the list of children
    syntax_tree *ast_copy = ast.copy_ast();
    ast_copy->nb_explored_optims = nb_explored_optims;
    children.push_back(ast_copy);

    // Sort children from smallest evaluation to largest
    std::sort(children.begin(), children.end(), [](syntax_tree *a, syntax_tree *b) {
        return a->evaluation < b->evaluation;
    });

    // keep the top 'beam_size' children and delete the rest
    for (int i = beam_size; i < children.size(); ++i)
        delete children[i];

    children.resize(std::min(beam_size, (int)children.size()));

    // Search recursively on the best children
    for (syntax_tree *child : children)
    {
        child->search_depth = ast.search_depth + 1;
        search_save(*child, schedules_annotations);
    }
}

void mcts::search(syntax_tree& ast)
{
    std::default_random_engine rand_generator;

    std::vector<syntax_tree*> samples;
    std::vector<syntax_tree*> children;
    std::vector<double> children_evals;

    for (int epoch = 0; epoch < nb_samples; ++epoch)
    {
        // Starting from the initial ast, generate optimizations until reaching max_depth
        syntax_tree *ast_sample = *
        for (int depth = 0; depth < max_depth; ++depth)
        {
            optimization_type optim_type = DEFAULT_OPTIMIZATIONS_ORDER[depth % NB_OPTIMIZATIONS];
            children = scheds_gen->generate_schedules(*ast_sample, optim_type);

            if (children.empty())
                continue;

            children_evals.clear();

            for (syntax_tree *child : children)
            {
                child->transform_ast();

                child->evaluation = eval_func->evaluate(*child);
                children_evals.push_back(child->evaluation);

                nb_explored_schedules++;
            }

            // Add the current AST to the list of children
            children.push_back(ast_sample->copy_ast());
            children_evals.push_back(ast_sample->evaluation);

            // Sample an AST
            std::discrete_distribution<int> dist(children_evals.begin(), children_evals.end());
            ast_sample = children[dist(rand_generator)];

            samples.push_back(ast_sample);
        }
    }

    if (samples.empty())
        return ;

    // Sort schedules with respect to evaluations
    std::sort(samples.begin(), samples.end(), [](syntax_tree *a, syntax_tree *b) {
        return a->evaluation < b->evaluation;
    });

    // Execute top-k schedules and return the best
    for (int i = 0; i < topk; ++i)
    {
        float exec_time = exec_eval->evaluate(*samples[i]);
        if (exec_time < best_evaluation)
        {
            best_evaluation = exec_time;
            best_ast = samples[i];
        }
    }
}

void mcts::search_save(syntax_tree& ast, std::vector<std::string> *schedules_annotations)
{
    std::cerr<< "mcts::search_save not yet implemented" << std::endl;
    exit(1);
}

// -------------------------------------------------------------------------- //

void beam_search_topk::search(syntax_tree& ast)
{
    // Do a beam search
    beam_search_subroutine(ast);

    // Sort schedules found
    std::sort(schedules.begin(), schedules.end(), [](syntax_tree *a, syntax_tree *b) {
        return a->evaluation < b->evaluation;
    });

    // Execute top-k schedules to find the best
    for (int i = 0; i < topk; ++i)
    {
        float exec_time = exec_eval->evaluate(*schedules[i]);
        if (exec_time < best_evaluation)
        {
            best_evaluation = exec_time;
            best_ast = schedules[i];
        }
    }
}

void beam_search_topk::search_save(syntax_tree& ast, std::vector<std::string> *schedules_annotations)
{
    std::cerr<< "beam_search_topk::search_save not yet implemented" << std::endl;
    exit(1);
}

void beam_search_topk::beam_search_subroutine(syntax_tree& ast)
{
    if (ast.nb_explored_optims % NB_OPTIMIZATIONS == 0)
        ast.clear_new_optimizations();

    std::vector<syntax_tree*> children;

    // Look for an optimization that can be applied
    int nb_optims_tried = 0;
    int nb_explored_optims = ast.nb_explored_optims;

    while (children.size() == 0 && nb_optims_tried < NB_OPTIMIZATIONS && nb_explored_optims < max_depth)
    {
        optimization_type optim_type = DEFAULT_OPTIMIZATIONS_ORDER[nb_explored_optims % NB_OPTIMIZATIONS];
        children = scheds_gen->generate_schedules(ast, optim_type);

        nb_explored_optims++;
        nb_optims_tried++;
    }

    // Stop if no more optimizations can be applied
    if (children.size() == 0)
        return ;

    // Evaluate children and sort them from smallest to highest evaluation
    for (syntax_tree *child : children)
    {
        child->nb_explored_optims = nb_explored_optims;
        child->transform_ast();

        child->evaluation = eval_func->evaluate(*child);

        nb_explored_schedules++;
    }

    // Add the current AST to the list of children
    syntax_tree *ast_copy = ast.copy_ast();
    ast_copy->nb_explored_optims = nb_explored_optims;
    children.push_back(ast_copy);

    // Sort children from smallest evaluation to largest
    std::sort(children.begin(), children.end(), [](syntax_tree *a, syntax_tree *b) {
        return a->evaluation < b->evaluation;
    });

    for (int i = 0; i < beam_size; ++i)
        schedules.push_back(children[i]);

    // Stop if we reached the maximum depth
    if (nb_explored_optims >= max_depth)
        return ;

    // Search recursively on the best children
    for (int i = beam_size; i < children.size(); ++i)
        delete children[i];

    children.resize(std::min(beam_size, (int)children.size()));

    for (syntax_tree *child : children)
    {
        child->search_depth = ast.search_depth + 1;
        search(*child);
    }
}

void beam_search_accuracy_evaluator::search(syntax_tree& ast)
{
    if (ast.nb_explored_optims % NB_OPTIMIZATIONS == 0)
        ast.clear_new_optimizations();

    std::vector<syntax_tree*> children;

    // Look for an optimization that can be applied
    int nb_optims_tried = 0;
    int nb_explored_optims = ast.nb_explored_optims;

    while (children.size() == 0 && nb_optims_tried < NB_OPTIMIZATIONS && nb_explored_optims < max_depth)
    {
        optimization_type optim_type = DEFAULT_OPTIMIZATIONS_ORDER[nb_explored_optims % NB_OPTIMIZATIONS];
        children = scheds_gen->generate_schedules(ast, optim_type);

        nb_explored_optims++;
        nb_optims_tried++;
    }

    // Stop if no more optimizations can be applied
    if (children.size() == 0)
        return ;

    // Evaluate children and sort them from smallest to highest evaluation
    for (syntax_tree *child : children)
    {
        child->nb_explored_optims = nb_explored_optims;
        child->transform_ast();

        child->evaluation = eval_func->evaluate(*child);

        // We evaluate both by the model and by execution
        model_evals_list.push_back(child->evaluation);
        exec_evals_list.push_back(exec_eval->evaluate(*child));

        if (child->evaluation < best_evaluation)
        {
            best_evaluation = child->evaluation;
            best_ast = child;
        }

        nb_explored_schedules++;
    }

    // Stop if we reached the maximum depth
    if (nb_explored_optims >= max_depth)
        return ;

    // Add the current AST to the list of children
    syntax_tree *ast_copy = ast.copy_ast();
    ast_copy->nb_explored_optims = nb_explored_optims;
    children.push_back(ast_copy);

    // Sort children from smallest evaluation to largest
    std::sort(children.begin(), children.end(), [](syntax_tree *a, syntax_tree *b) {
        return a->evaluation < b->evaluation;
    });

    // Search recursively on the best children
    for (int i = beam_size; i < children.size(); ++i)
        delete children[i];

    children.resize(std::min(beam_size, (int)children.size()));

    for (syntax_tree *child : children)
    {
        child->search_depth = ast.search_depth + 1;
        search(*child);
    }
}

}
<|endoftext|>


<commit_before>/***
DEVSIM
Copyright 2021 Devsim LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
***/
#include "GaussFermi.hh"
#include "BoostConstants.hh"
#include "MiscMathFunc.hh"
#ifdef DEVSIM_EXTENDED_PRECISION
#include "Float128.hh"
#endif
#include <utility>
#include <cmath>
using std::abs;

#ifdef DEVSIM_UNIT_TEST
#include <iostream>
#include <iomanip>
#endif

/*
Implementation of:
https://doi.org/10.1063/1.3374475
@article{doi:10.1063/1.3374475,
author = {Paasch,Gernot  and Scheinert,Susanne },
title = {Charge carrier density of organics with Gaussian density of states: Analytical approximation for the Gauss–Fermi integral},
journal = {Journal of Applied Physics},
volume = {107},
number = {10},
pages = {104501},
year = {2010},
doi = {10.1063/1.3374475},
URL = { https://doi.org/10.1063/1.3374475 },
eprint = { https://doi.org/10.1063/1.3374475 }
}
*/

namespace {
template <typename T>
struct MC {
    static constexpr T sqrt2 = boost::math::constants::root_two<T>();
    static constexpr T sqrt2_pi = boost::math::constants::root_two<T>() * boost::math::constants::one_div_root_pi<T>();
    static constexpr T one_div_root_two_pi = boost::math::constants::one_div_root_two_pi<T>();
};

template <typename T>
inline T calcH_Impl(const T &s, const T &S)
{
    const T &sqrt2 = MC<T>::sqrt2;

    T H = sqrt2 / s * erfc_inv(exp(-0.5 * S));
    return H;
}

template <typename T>
inline T calcH(const T &s, const T &S)
{
    thread_local auto p = std::make_pair(s, calcH_Impl(s, S));

    // Assume that s is constant across the same call in the same region
    if (p.first != s)
    {
      p = std::make_pair(s, calcH_Impl(s, S));
    }

    return p.second;
}

template <typename T>
inline T calcK(const T &s, const T &S, const T &H)
{
  const T &sqrt2_pi = MC<T>::sqrt2_pi;

  T K = 2 * (1. - H / s * sqrt2_pi * exp(0.5 * S * (1. - H * H)));
  return K;
}

}

template <typename T>
T gfi(T zeta, T s)
{
    const T &sqrt2 = MC<T>::sqrt2;
    const T S = s * s;

    T H = calcH(s, S);

    T value;
    if (zeta < -S)
    {
        const T K = calcK(s, S, H);
        value = exp(0.5 * S + zeta) / (exp(K*(zeta+S)) + 1);
    }
    else
    {
        value = 0.5 * erfc(-zeta / (s*sqrt2) * H);
    }

    return value;
}

template <typename T>
T dgfidx(T zeta, T s)
{
    const T &sqrt2 = MC<T>::sqrt2;
    const T &sqrt2_pi = MC<T>::sqrt2_pi;

    const T S = s * s;

    T H = calcH(s, S);

    T dvalue;
    if (zeta < -S)
    {
        const T K = calcK(s, S, H);
        const T den_inv = 1. / (exp(K * (S + zeta)) + 1.);
        dvalue = exp(0.5 * S + zeta) * den_inv * (1. - K*exp(K * (S+zeta)) * den_inv);
    }
    else
    {
        const T &one_div_root_two_pi = MC<T>::one_div_root_two_pi;
        dvalue = one_div_root_two_pi * H / s * exp(-0.5 * pow(H*zeta,2)/S);
    }

    return dvalue;
}

//### inverse function for Gaussian Fermi Integral

namespace {
template <typename T>
T good_relerror();

template <>
double good_relerror()
{
  return 1e-12;
}

#ifdef DEVSIM_EXTENDED_PRECISION
template <>
float128 good_relerror()
{
  return 1e-31;
}
#endif
}

template <typename T>
T igfi(T g, T s)
{
    // using the Newton method
    // The initial guess
    // perhaps the degenerate approximation
    // or provided from the last call
    // improves speed
    T x = 0.0;
    //printf("%d %1.15e %1.15e\n", -1, x, rerr);
#ifdef DEVSIM_UNIT_TEST
    std::cout << std::setprecision(std::numeric_limits<T>::max_digits10);
#endif
    T arg = 1. - 2. * g;

    static constexpr T bound = 1.0 - std::numeric_limits<T>::epsilon();

    // prevent infinite results
    if (arg <= -1.0)
    {
      arg = -bound;
    }
    else if (arg >= 1.0)
    {
      arg = bound;
    }

    const T &sqrt2 = MC<T>::sqrt2;
    // using the degenerate approximation
    const T S = s*s;
    const T H = calcH(s, S);
    x = -s * sqrt2 * erf_inv(arg) / H;

#if 0
    // slightly less accuracy, best to use iteration
    if ((x >= -S) && (abs(arg) != bound))
    {
        return x;
    }
#endif

    T rerr = 0.0;
    size_t i = 0;
    T f;
    T fp;
    T upd;

    do
    {
        f = gfi(x, s) - g;
        fp = dgfidx(x, s);
        upd = -f / fp;
        x += upd;
        rerr = abs(upd)/(abs(x) + good_relerror<T>());
#ifdef DEVSIM_UNIT_TEST
    std::cout << i << " " << x << " " << rerr << "\n";
#endif
        ++i;
    } while ((rerr > good_relerror<T>()) && (i < 200));
    return x;
}

template <typename T>
T digfidx(T g, T s)
{
    return 1.0 / dgfidx(igfi(g,s), s);
}

template double gfi<double>(double, double);
template double dgfidx<double>(double, double);
template double igfi<double>(double, double);
template double digfidx<double>(double, double);

#ifdef DEVSIM_EXTENDED_PRECISION
template float128 gfi<float128>(float128, float128);
template float128 dgfidx<float128>(float128, float128);
template float128 igfi<float128>(float128, float128);
template float128 digfidx<float128>(float128, float128);
#endif

#ifdef DEVSIM_UNIT_TEST
template <typename DoubleType>
void unit()
{
  DoubleType k_B = 1.380649e-23;
  DoubleType e = 1.602176634e-19;
  DoubleType T = 300;
  DoubleType sigma = 0.10;
  DoubleType s = (sigma*e)/(k_B*T);
  DoubleType S = s*s;
  DoubleType V_0 = 0;
  DoubleType V_f = V_0-S*k_B*T/e;// # (-0.65372119-1.2) ;
  DoubleType zeta = (V_f*e-V_0*e)/(k_B*T);
  // zeta =-0.5
  DoubleType zeta_1 = (V_f*e-V_0*e-pow(sigma*e, 2)/k_B*T)/(k_B*T);

  DoubleType g= gfi(zeta,s);
  DoubleType dg= dgfidx(zeta,s);
  DoubleType ginv= igfi(g,s);
  DoubleType dginv= digfidx(g,s);
// print(g,dg,ginv)
  std::cout << std::setprecision(std::numeric_limits<DoubleType>::max_digits10);
  std::cout
            << " zeta\t" << zeta << "\n"
            << " gfi\t" << g << "\n"
            << " dgfidx\t" << dg << "\n"
            << " igfi\t" << ginv << "\n"
            << " digfidx\t" << dginv << " " << 1.0/dginv << "\n";

}

int main()
{
  unit<double>();
#ifdef DEVSIM_EXTENDED_PRECISION
  unit<float128>();
#endif
}
#endif
<commit_msg>update test<commit_after>/***
DEVSIM
Copyright 2021 Devsim LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
***/
#include "GaussFermi.hh"
#include "BoostConstants.hh"
#include "MiscMathFunc.hh"
#ifdef DEVSIM_EXTENDED_PRECISION
#include "Float128.hh"
#endif
#include <utility>
#include <cmath>
using std::abs;

#ifdef DEVSIM_UNIT_TEST
#include <iostream>
#include <iomanip>
#endif

/*
Implementation of:
https://doi.org/10.1063/1.3374475
@article{doi:10.1063/1.3374475,
author = {Paasch,Gernot  and Scheinert,Susanne },
title = {Charge carrier density of organics with Gaussian density of states: Analytical approximation for the Gauss–Fermi integral},
journal = {Journal of Applied Physics},
volume = {107},
number = {10},
pages = {104501},
year = {2010},
doi = {10.1063/1.3374475},
URL = { https://doi.org/10.1063/1.3374475 },
eprint = { https://doi.org/10.1063/1.3374475 }
}
*/

namespace {
template <typename T>
struct MC {
    static constexpr T sqrt2 = boost::math::constants::root_two<T>();
    static constexpr T sqrt2_pi = boost::math::constants::root_two<T>() * boost::math::constants::one_div_root_pi<T>();
    static constexpr T one_div_root_two_pi = boost::math::constants::one_div_root_two_pi<T>();
};

template <typename T>
inline T calcH_Impl(const T &s, const T &S)
{
    const T &sqrt2 = MC<T>::sqrt2;

    T H = sqrt2 / s * erfc_inv(exp(-0.5 * S));
#ifdef DEVSIM_UNIT_TEST
    std::cout << std::setprecision(std::numeric_limits<T>::max_digits10);
    std::cout << "DEBUG NEW H " << s << " " << H << "\n";
#endif
    return H;
}

template <typename T>
inline T calcH(const T &s, const T &S)
{
    thread_local auto p = std::make_pair(s, calcH_Impl(s, S));

    // Assume that s is constant across the same call in the same region
    if (p.first != s)
    {
      p = std::make_pair(s, calcH_Impl(s, S));
    }
#if 0
    else
    {
      std::cout << "DEBUG REUSE H\n";
    }
#endif

    return p.second;
}

template <typename T>
inline T calcK(const T &s, const T &S, const T &H)
{
  const T &sqrt2_pi = MC<T>::sqrt2_pi;

  T K = 2 * (1. - H / s * sqrt2_pi * exp(0.5 * S * (1. - H * H)));
  return K;
}

}

template <typename T>
T gfi(T zeta, T s)
{
    const T &sqrt2 = MC<T>::sqrt2;
    const T S = s * s;

    T H = calcH(s, S);

    T value;
    if (zeta < -S)
    {
        const T K = calcK(s, S, H);
        value = exp(0.5 * S + zeta) / (exp(K*(zeta+S)) + 1);
    }
    else
    {
        value = 0.5 * erfc(-zeta / (s*sqrt2) * H);
    }

    return value;
}

template <typename T>
T dgfidx(T zeta, T s)
{
    const T &sqrt2 = MC<T>::sqrt2;
    const T &sqrt2_pi = MC<T>::sqrt2_pi;

    const T S = s * s;

    T H = calcH(s, S);

    T dvalue;
    if (zeta < -S)
    {
        const T K = calcK(s, S, H);
        const T den_inv = 1. / (exp(K * (S + zeta)) + 1.);
        dvalue = exp(0.5 * S + zeta) * den_inv * (1. - K*exp(K * (S+zeta)) * den_inv);
    }
    else
    {
        const T &one_div_root_two_pi = MC<T>::one_div_root_two_pi;
        dvalue = one_div_root_two_pi * H / s * exp(-0.5 * pow(H*zeta,2)/S);
    }

    return dvalue;
}

//### inverse function for Gaussian Fermi Integral

namespace {
template <typename T>
T good_relerror();

template <>
double good_relerror()
{
  return 1e-12;
}

#ifdef DEVSIM_EXTENDED_PRECISION
template <>
float128 good_relerror()
{
  return 1e-31;
}
#endif
}

template <typename T>
T igfi(T g, T s)
{
    // using the Newton method
    // The initial guess
    // perhaps the degenerate approximation
    // or provided from the last call
    // improves speed
    T x = 0.0;
    //printf("%d %1.15e %1.15e\n", -1, x, rerr);
#ifdef DEVSIM_UNIT_TEST
    std::cout << std::setprecision(std::numeric_limits<T>::max_digits10);
#endif
    T arg = 1. - 2. * g;

    static constexpr T bound = 1.0 - std::numeric_limits<T>::epsilon();

    // prevent infinite results
    if (arg <= -1.0)
    {
      arg = -bound;
    }
    else if (arg >= 1.0)
    {
      arg = bound;
    }

    const T &sqrt2 = MC<T>::sqrt2;
    // using the degenerate approximation
    const T S = s*s;
    const T H = calcH(s, S);
    x = -s * sqrt2 * erf_inv(arg) / H;

#if 0
    // slightly less accuracy, best to use iteration
    if ((x >= -S) && (abs(arg) != bound))
    {
        return x;
    }
#endif

    T rerr = 0.0;
    size_t i = 0;
    T f;
    T fp;
    T upd;

    do
    {
        f = gfi(x, s) - g;
        fp = dgfidx(x, s);
        upd = -f / fp;
        x += upd;
        rerr = abs(upd)/(abs(x) + good_relerror<T>());
#ifdef DEVSIM_UNIT_TEST
    std::cout << i << " " << x << " " << rerr << "\n";
#endif
        ++i;
    } while ((rerr > good_relerror<T>()) && (i < 200));
    return x;
}

template <typename T>
T digfidx(T g, T s)
{
    return 1.0 / dgfidx(igfi(g,s), s);
}

template double gfi<double>(double, double);
template double dgfidx<double>(double, double);
template double igfi<double>(double, double);
template double digfidx<double>(double, double);

#ifdef DEVSIM_EXTENDED_PRECISION
template float128 gfi<float128>(float128, float128);
template float128 dgfidx<float128>(float128, float128);
template float128 igfi<float128>(float128, float128);
template float128 digfidx<float128>(float128, float128);
#endif

#ifdef DEVSIM_UNIT_TEST
template <typename DoubleType>
void unit()
{
  for (size_t j = 2; j <= 8; j += 2)
  {
    DoubleType s = static_cast<DoubleType>(j);
    for (size_t i = 0; i <= 10; ++i)
    {
      DoubleType zeta = 7 * i - 70.;
      DoubleType g= gfi(zeta,s);
      DoubleType dg= dgfidx(zeta,s);
      DoubleType ginv= igfi(g,s);
      DoubleType dginv= digfidx(g,s);
      std::cout
                << zeta << " "
                << g << " "
                << dg << " "
                << ginv << " "
                << dginv << " " << 1.0/dginv << "\n";
    }
  }
#if 0
  DoubleType k_B = 1.380649e-23;
  DoubleType e = 1.602176634e-19;
  DoubleType T = 300;
  DoubleType sigma = 0.10;
  DoubleType s = (sigma*e)/(k_B*T);
  DoubleType S = s*s;
  DoubleType V_0 = 0;
  DoubleType V_f = V_0-S*k_B*T/e;// # (-0.65372119-1.2) ;
  DoubleType zeta = (V_f*e-V_0*e)/(k_B*T);
  // zeta =-0.5
  DoubleType zeta_1 = (V_f*e-V_0*e-pow(sigma*e, 2)/k_B*T)/(k_B*T);

  DoubleType g= gfi(zeta,s);
  DoubleType dg= dgfidx(zeta,s);
  DoubleType ginv= igfi(g,s);
  DoubleType dginv= digfidx(g,s);
// print(g,dg,ginv)
  std::cout << std::setprecision(std::numeric_limits<DoubleType>::max_digits10);
  std::cout
            << " zeta\t" << zeta << "\n"
            << " gfi\t" << g << "\n"
            << " dgfidx\t" << dg << "\n"
            << " igfi\t" << ginv << "\n"
            << " digfidx\t" << dginv << " " << 1.0/dginv << "\n";
#endif
}

int main()
{
  unit<double>();
#ifdef DEVSIM_EXTENDED_PRECISION
  unit<float128>();
#endif
}
#endif
<|endoftext|>


<commit_before>#include <MemoryManager.hh>

#include <Memory.hh>
#include <Debug.hh>

#include <cstdio>

MemoryManager* MemoryManager::self = 0;

MemoryManager::MemoryManager()
   : freeList()
{
   // empty!
}

void*
MemoryManager::operator new(std::size_t /*size*/, void *placement)
{
   return placement;
}

MemoryManager::Segment*
MemoryManager::headerOf(void* data)
{
   return reinterpret_cast<Segment*>(uintptr_t(data) - sizeof(Segment));
}

void
MemoryManager::init()
{
   printf("Intializing Memory Manager\n");
   void* object = allocateBackend(sizeof(MemoryManager));

   MemoryManager::self = new (object) MemoryManager();

   printf("Memory Manager at %p\n", (void* )MemoryManager::self);
}

MemoryManager&
MemoryManager::get()
{
   return *self;
}

void*
MemoryManager::allocateBackend(std::size_t size)
{
   std::size_t rsize = roundTo(size, PageSize);
   void* data = reinterpret_cast<void*>(Memory::sbrk(rsize));

   KASSERT(data != 0);

   return data;
}

void*
MemoryManager::allocate(std::size_t size)
{
   for (auto& s : freeList)
   {
      if (s.getSize() >= size)
      {
	 freeList.remove(&s);
	 s.markAllocated();
#ifdef DEBUG
	 printf("Debug: allocating from freelist\n");
#endif
	 return reinterpret_cast<void*>(s.getAddress());
      }
   }

#ifdef DEBUG
   printf("Debug: allocating from heap\n");
#endif

   std::size_t rsize = roundTo(size + sizeof(Segment), PageSize);
//   Segment* segment = reinterpret_cast<Segment*>(allocateBackend(rsize));
   Segment* segment = new (reinterpret_cast<void*>(allocateBackend(rsize))) Segment;

   segment->setSize(rsize - sizeof(Segment));
   segment->setAddress(reinterpret_cast<uintptr_t>(segment + 1));
   segment->markAllocated();

   return reinterpret_cast<void*>(segment->getAddress());
}

void
MemoryManager::deallocate(void *data)
{
   Segment* segment = headerOf(data);

   KASSERT(segment->isAllocated());
   segment->markAllocated();

#ifdef DEBUG
   printf("Putting to freelist\n");
#endif

   freeList.insertLast(segment);
}

void
MemoryManager::printStatistics()
{
   printf("Allocator statistics:\n");
   printf("Free segments: %zu\n", freeList.getCount());

   for (auto& s : freeList)
   {
      printf("Segment %p: size: %zu, address: %p\n", &s, s.getSize(), (void* )s.getAddress());
   }
}

<commit_msg>use memory mapped backend<commit_after>#include <MemoryManager.hh>

#include <Memory.hh>
#include <Debug.hh>

#include <cstdio>

MemoryManager* MemoryManager::self = 0;

MemoryManager::MemoryManager()
   : freeList()
{
   // empty!
}

void*
MemoryManager::operator new(std::size_t /*size*/, void *placement)
{
   return placement;
}

MemoryManager::Segment*
MemoryManager::headerOf(void* data)
{
   return reinterpret_cast<Segment*>(uintptr_t(data) - sizeof(Segment));
}

void
MemoryManager::init()
{
   printf("Intializing Memory Manager\n");
   void* object = allocateBackend(sizeof(MemoryManager));

   MemoryManager::self = new (object) MemoryManager();

   printf("Memory Manager at %p\n", (void* )MemoryManager::self);
}

MemoryManager&
MemoryManager::get()
{
   return *self;
}

void*
MemoryManager::allocateBackend(std::size_t size)
{
   std::size_t rsize = roundTo(size, PageSize);

   void* data = reinterpret_cast<void*>(Memory::mapAnonymousRegion(rsize));

   KASSERT(data != 0);

   return data;
}

void*
MemoryManager::allocate(std::size_t size)
{
   for (auto& s : freeList)
   {
      if (s.getSize() >= size)
      {
	 freeList.remove(&s);
	 s.markAllocated();
#ifdef DEBUG
	 printf("Debug: allocating from freelist\n");
#endif
	 return reinterpret_cast<void*>(s.getAddress());
      }
   }

#ifdef DEBUG
   printf("Debug: allocating from heap\n");
#endif

   std::size_t rsize = roundTo(size + sizeof(Segment), PageSize);
//   Segment* segment = reinterpret_cast<Segment*>(allocateBackend(rsize));
   Segment* segment = new (reinterpret_cast<void*>(allocateBackend(rsize))) Segment;

   segment->setSize(rsize - sizeof(Segment));
   segment->setAddress(reinterpret_cast<uintptr_t>(segment + 1));
   segment->markAllocated();

   return reinterpret_cast<void*>(segment->getAddress());
}

void
MemoryManager::deallocate(void *data)
{
   Segment* segment = headerOf(data);

   KASSERT(segment->isAllocated());
   segment->markAllocated();

#ifdef DEBUG
   printf("Putting to freelist\n");
#endif

   freeList.insertLast(segment);
}

void
MemoryManager::printStatistics()
{
   printf("Allocator statistics:\n");
   printf("Free segments: %zu\n", freeList.getCount());

   for (auto& s : freeList)
   {
      printf("Segment %p: size: %zu, address: %p\n", &s, s.getSize(), (void* )s.getAddress());
   }
}

<|endoftext|>


<commit_before>// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include <autowiring/CoreThread.h>
#include CHRONO_HEADER
#include THREAD_HEADER

class AutoPacketFactoryTest:
  public testing::Test
{};

TEST_F(AutoPacketFactoryTest, VerifyNoIssueWhileNotStarted) {
  AutoRequired<AutoPacketFactory> factory;
  ASSERT_THROW(factory->NewPacket(), autowiring_error) << "Issuing a packet in a context that has not yet been started should throw an exception";
}

TEST_F(AutoPacketFactoryTest, StopReallyStops) {
  AutoCurrentContext()->SignalShutdown();

  AutoRequired<AutoPacketFactory> factory;
  ASSERT_TRUE(factory->ShouldStop()) << "Expected that an attempt to insert a packet factory to an already-stopped context would stop the packet factory";
}

TEST_F(AutoPacketFactoryTest, VerifyNoIssueWhileStopped) {
  AutoCurrentContext()->SignalShutdown();

  AutoRequired<AutoPacketFactory> factory;
  ASSERT_THROW(factory->NewPacket(), autowiring_error) << "Issuing a packet in a context that has already been stopped should throw an exception";
}

class IssuesPacketWaitsThenQuits:
  public CoreThread
{
public:
  IssuesPacketWaitsThenQuits(void) :
    m_hasQuit(false)
  {
    // Note:  Don't do this in practice.  This only works because we only inject this type
    // into a context that's already running; normally, creating a packet from our ctor can
    // cause an exception if we are being injected before Initiate is called.
    AutoRequired<AutoPacketFactory> factory;
    m_packet = factory->NewPacket();
  }

  bool m_hasQuit;
  std::shared_ptr<AutoPacket> m_packet;

  void Run(void) override {
    // Move shared pointer locally:
    std::shared_ptr<AutoPacket> packet;
    std::swap(packet, m_packet);

    // Just wait a bit, then return, just like we said we would
    this->ThreadSleep(std::chrono::milliseconds(50));

    // Update our variable and then return out:
    m_hasQuit = true;
  }
};

TEST_F(AutoPacketFactoryTest, WaitRunsDownAllPackets) {
  AutoCurrentContext()->Initiate();

  // Create a factory in our context, factory had better be started:
  AutoRequired<AutoPacketFactory> factory;
  ASSERT_TRUE(factory->IsRunning()) << "Factory was not started even though it was a member of an initiated context";

  // Make the thread create and hold a packet, and then return
  AutoRequired<IssuesPacketWaitsThenQuits> ipwtq;

  // Shutdown context
  AutoCurrentContext()->SignalShutdown();

  // Now we're going to try to run down the factory:
  factory->Wait();

  // Verify that the thread has quit:
  ASSERT_TRUE(ipwtq->m_hasQuit) << "AutoPacketFactory::Wait returned prematurely";
}

class HoldsAutoPacketFactoryReference {
public:
  HoldsAutoPacketFactoryReference(void):
    m_value(0)
  {}

  AutoRequired<AutoPacketFactory> m_factory;
  int m_value;

  // Just a dummy AutoFilter method so that this class is recognized as an AutoFilter
  void AutoFilter(int value) {
    m_value = value;
  }
};

TEST_F(AutoPacketFactoryTest, AutoPacketFactoryCycle) {
  std::weak_ptr<CoreContext> ctxtWeak;
  std::weak_ptr<HoldsAutoPacketFactoryReference> hapfrWeak;
  std::shared_ptr<AutoPacket> packet;

  {
    // Create a context, fill it up, kick it off:
    AutoCreateContext ctxt;
    CurrentContextPusher pshr(ctxt);
    AutoRequired<HoldsAutoPacketFactoryReference> hapfr(ctxt);
    ctxt->Initiate();

    // A weak pointer is used to detect object destruction
    ctxtWeak = ctxt;
    hapfrWeak = hapfr;

    // Trivial validation-of-reciept:
    AutoRequired<AutoPacketFactory> factory;
    {
      auto trivial = factory->NewPacket();
      trivial->Decorate((int) 54);
      ASSERT_EQ(54, hapfr->m_value) << "A simple packet was not received as expected by an AutoFilter";
    }

    // Create a packet which will force in a back-reference:
    packet = factory->NewPacket();

    // Terminate the context:
    ctxt->SignalShutdown();

    // Verify that we can still decorate the packet and also that the packet is delivered to the factory:
    packet->Decorate((int) 55);

    // Relock, verify the value was received by the hapfr:
    ASSERT_EQ(55, hapfr->m_value) << "AutoFilter did not receive a packet as expected";
  }

  // The context cannot go out of socpe until all packets in the context are out of scope
  ASSERT_FALSE(ctxtWeak.expired()) << "Context went out of scope before all packets were finished being processed";

  // Now we can release the packet and verify that everything gets cleaned up:
  packet.reset();
  ASSERT_TRUE(ctxtWeak.expired()) << "AutoPacketFactory incorrectly held a cyclic reference even after the context was shut down";
  ASSERT_TRUE(hapfrWeak.expired()) << "The last packet from a factory was released; this should have resulted in teardown, but it did not";
}

class DelaysAutoPacketsOneMS {
public:
  DelaysAutoPacketsOneMS(void) {}

  void AutoFilter(int value) {
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  }
};

TEST_F(AutoPacketFactoryTest, AutoPacketStatistics) {
  // Create a context, fill it up, kick it off:
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);
  AutoRequired<DelaysAutoPacketsOneMS> dapoms(ctxt);
  AutoRequired<AutoPacketFactory> factory(ctxt);
  ctxt->Initiate();

  int numPackets = 20;

  // Send 20 packets which should all be delayed 1ms
  for (int i = 0; i < numPackets; ++i) {
    auto packet = factory->NewPacket();
    packet->Decorate(i);
  }

  // Shutdown our context, and rundown our factory
  ctxt->SignalShutdown();
  factory->Wait();

  // Ensure that the statistics are not too wrong
  // We delayed each packet by one ms, and our statistics are given in nanoseconds
  double packetDelay = (double) std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(1)).count();
  ASSERT_EQ(numPackets, factory->GetTotalPacketCount()) << "The factory did not get enough packets";

  ASSERT_LE(packetDelay, factory->GetMeanPacketLifetime()) << "The mean packet lifetime was less than the delay on each packet";
}

TEST_F(AutoPacketFactoryTest, AddSubscriberTest) {
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);
  AutoRequired<AutoPacketFactory> factory(ctxt);
  ctxt->Initiate();

  bool first_called = false;
  bool second_called = false;

  factory->AddSubscriber(AutoFilterDescriptor([&first_called] (int) {first_called = true;}));
  *factory += [&second_called] (int) {second_called = true;};

  auto packet = factory->NewPacket();

  ASSERT_FALSE(first_called) << "Normal subscriber called too early";
  ASSERT_FALSE(second_called) << "Subscriber added with operator+= called too early";

  packet->DecorateImmediate(int(0));

  ASSERT_TRUE(first_called) << "Normal subscriber never called";
  ASSERT_TRUE(second_called) << "Subscriber added with operator+= never called";
}

TEST_F(AutoPacketFactoryTest, MultiDecorateTest) {
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);
  AutoRequired<AutoPacketFactory> factory(ctxt);
  ctxt->Initiate();

  int called = 0;

  *factory += [&called] (int& out) { out = called++; };
  *factory += [&called] (int& out) { out = called++; };
  *factory += [&called] (const int* vals[]) {
    ASSERT_NE(nullptr, vals);
    called++;
    int i;
    for (i = 0; vals[i] != nullptr; i++) {
      EXPECT_EQ(i, *(vals[i])) << "Incorrect values were added to the packet";
    }
    EXPECT_EQ(2, i) << "The wrong number of values were added to the packet";
  };
  ASSERT_EQ(0, called);

  auto packet = factory->NewPacket();

  ASSERT_EQ(3, called);
}
<commit_msg>Adding a small test to verify extraction on a multi-in type<commit_after>// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include <autowiring/CoreThread.h>
#include CHRONO_HEADER
#include THREAD_HEADER

class AutoPacketFactoryTest:
  public testing::Test
{};

TEST_F(AutoPacketFactoryTest, VerifyNoIssueWhileNotStarted) {
  AutoRequired<AutoPacketFactory> factory;
  ASSERT_THROW(factory->NewPacket(), autowiring_error) << "Issuing a packet in a context that has not yet been started should throw an exception";
}

TEST_F(AutoPacketFactoryTest, StopReallyStops) {
  AutoCurrentContext()->SignalShutdown();

  AutoRequired<AutoPacketFactory> factory;
  ASSERT_TRUE(factory->ShouldStop()) << "Expected that an attempt to insert a packet factory to an already-stopped context would stop the packet factory";
}

TEST_F(AutoPacketFactoryTest, VerifyNoIssueWhileStopped) {
  AutoCurrentContext()->SignalShutdown();

  AutoRequired<AutoPacketFactory> factory;
  ASSERT_THROW(factory->NewPacket(), autowiring_error) << "Issuing a packet in a context that has already been stopped should throw an exception";
}

class IssuesPacketWaitsThenQuits:
  public CoreThread
{
public:
  IssuesPacketWaitsThenQuits(void) :
    m_hasQuit(false)
  {
    // Note:  Don't do this in practice.  This only works because we only inject this type
    // into a context that's already running; normally, creating a packet from our ctor can
    // cause an exception if we are being injected before Initiate is called.
    AutoRequired<AutoPacketFactory> factory;
    m_packet = factory->NewPacket();
  }

  bool m_hasQuit;
  std::shared_ptr<AutoPacket> m_packet;

  void Run(void) override {
    // Move shared pointer locally:
    std::shared_ptr<AutoPacket> packet;
    std::swap(packet, m_packet);

    // Just wait a bit, then return, just like we said we would
    this->ThreadSleep(std::chrono::milliseconds(50));

    // Update our variable and then return out:
    m_hasQuit = true;
  }
};

TEST_F(AutoPacketFactoryTest, WaitRunsDownAllPackets) {
  AutoCurrentContext()->Initiate();

  // Create a factory in our context, factory had better be started:
  AutoRequired<AutoPacketFactory> factory;
  ASSERT_TRUE(factory->IsRunning()) << "Factory was not started even though it was a member of an initiated context";

  // Make the thread create and hold a packet, and then return
  AutoRequired<IssuesPacketWaitsThenQuits> ipwtq;

  // Shutdown context
  AutoCurrentContext()->SignalShutdown();

  // Now we're going to try to run down the factory:
  factory->Wait();

  // Verify that the thread has quit:
  ASSERT_TRUE(ipwtq->m_hasQuit) << "AutoPacketFactory::Wait returned prematurely";
}

class HoldsAutoPacketFactoryReference {
public:
  HoldsAutoPacketFactoryReference(void):
    m_value(0)
  {}

  AutoRequired<AutoPacketFactory> m_factory;
  int m_value;

  // Just a dummy AutoFilter method so that this class is recognized as an AutoFilter
  void AutoFilter(int value) {
    m_value = value;
  }
};

TEST_F(AutoPacketFactoryTest, AutoPacketFactoryCycle) {
  std::weak_ptr<CoreContext> ctxtWeak;
  std::weak_ptr<HoldsAutoPacketFactoryReference> hapfrWeak;
  std::shared_ptr<AutoPacket> packet;

  {
    // Create a context, fill it up, kick it off:
    AutoCreateContext ctxt;
    CurrentContextPusher pshr(ctxt);
    AutoRequired<HoldsAutoPacketFactoryReference> hapfr(ctxt);
    ctxt->Initiate();

    // A weak pointer is used to detect object destruction
    ctxtWeak = ctxt;
    hapfrWeak = hapfr;

    // Trivial validation-of-reciept:
    AutoRequired<AutoPacketFactory> factory;
    {
      auto trivial = factory->NewPacket();
      trivial->Decorate((int) 54);
      ASSERT_EQ(54, hapfr->m_value) << "A simple packet was not received as expected by an AutoFilter";
    }

    // Create a packet which will force in a back-reference:
    packet = factory->NewPacket();

    // Terminate the context:
    ctxt->SignalShutdown();

    // Verify that we can still decorate the packet and also that the packet is delivered to the factory:
    packet->Decorate((int) 55);

    // Relock, verify the value was received by the hapfr:
    ASSERT_EQ(55, hapfr->m_value) << "AutoFilter did not receive a packet as expected";
  }

  // The context cannot go out of socpe until all packets in the context are out of scope
  ASSERT_FALSE(ctxtWeak.expired()) << "Context went out of scope before all packets were finished being processed";

  // Now we can release the packet and verify that everything gets cleaned up:
  packet.reset();
  ASSERT_TRUE(ctxtWeak.expired()) << "AutoPacketFactory incorrectly held a cyclic reference even after the context was shut down";
  ASSERT_TRUE(hapfrWeak.expired()) << "The last packet from a factory was released; this should have resulted in teardown, but it did not";
}

class DelaysAutoPacketsOneMS {
public:
  DelaysAutoPacketsOneMS(void) {}

  void AutoFilter(int value) {
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  }
};

TEST_F(AutoPacketFactoryTest, AutoPacketStatistics) {
  // Create a context, fill it up, kick it off:
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);
  AutoRequired<DelaysAutoPacketsOneMS> dapoms(ctxt);
  AutoRequired<AutoPacketFactory> factory(ctxt);
  ctxt->Initiate();

  int numPackets = 20;

  // Send 20 packets which should all be delayed 1ms
  for (int i = 0; i < numPackets; ++i) {
    auto packet = factory->NewPacket();
    packet->Decorate(i);
  }

  // Shutdown our context, and rundown our factory
  ctxt->SignalShutdown();
  factory->Wait();

  // Ensure that the statistics are not too wrong
  // We delayed each packet by one ms, and our statistics are given in nanoseconds
  double packetDelay = (double) std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(1)).count();
  ASSERT_EQ(numPackets, factory->GetTotalPacketCount()) << "The factory did not get enough packets";

  ASSERT_LE(packetDelay, factory->GetMeanPacketLifetime()) << "The mean packet lifetime was less than the delay on each packet";
}

TEST_F(AutoPacketFactoryTest, AddSubscriberTest) {
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);
  AutoRequired<AutoPacketFactory> factory(ctxt);
  ctxt->Initiate();

  bool first_called = false;
  bool second_called = false;

  factory->AddSubscriber(AutoFilterDescriptor([&first_called] (int) {first_called = true;}));
  *factory += [&second_called] (int) {second_called = true;};

  auto packet = factory->NewPacket();

  ASSERT_FALSE(first_called) << "Normal subscriber called too early";
  ASSERT_FALSE(second_called) << "Subscriber added with operator+= called too early";

  packet->DecorateImmediate(int(0));

  ASSERT_TRUE(first_called) << "Normal subscriber never called";
  ASSERT_TRUE(second_called) << "Subscriber added with operator+= never called";
}

TEST_F(AutoPacketFactoryTest, EnumerateDecorationsTest) {
  auto sample = [](const int* vals []) {};
  AutoFilterDescriptor desc(sample);

  size_t i = 0;
  for (auto* pCur = desc.GetAutoFilterInput(); *pCur; pCur++)
    i++;

  ASSERT_EQ(1, i) << "AutoFilterDescriptor parsed an incorrect number of arguments from a lambda";
}

TEST_F(AutoPacketFactoryTest, MultiDecorateTest) {
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);
  AutoRequired<AutoPacketFactory> factory(ctxt);
  ctxt->Initiate();

  int called = 0;

  *factory += [&called] (int& out) { out = called++; };
  *factory += [&called] (int& out) { out = called++; };
  *factory += [&called] (const int* vals[]) {
    ASSERT_NE(nullptr, vals);
    called++;
    int i;
    for (i = 0; vals[i] != nullptr; i++) {
      EXPECT_EQ(i, *(vals[i])) << "Incorrect values were added to the packet";
    }
    EXPECT_EQ(2, i) << "The wrong number of values were added to the packet";
  };
  ASSERT_EQ(0, called);

  auto packet = factory->NewPacket();

  ASSERT_EQ(3, called);
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file quintic_spiral_path.cpp
 **/

#include "modules/planning/math/curve1d/quintic_spiral_path.h"

#include "glog/logging.h"

namespace apollo {
namespace planning {

QuinticSpiralPath::QuinticSpiralPath(
    const double x0, const double dx0, const double ddx0, const double x1,
    const double dx1, const double ddx1, const double p)
    : QuinticPolynomialCurve1d(x0, dx0, ddx0, x1, dx1, ddx1, p) {
  CHECK(p > 0.0);

  double p2 = p * p;
  double p3 = p2 * p;
  double p4 = p3 * p;
  double p5 = p2 * p3;
  double p6 = p3 * p3;

  // derive a
  // double a = -6.0 * x0 / p5 - 3.0 * dx0 / p4 - 0.5 * ddx0 / p3 + 6.0 * x1 /
  // p5 - 3.0 * dx1 / p4 + 0.5 * ddx1 / p3;
  coef_deriv_[0][0] = -6.0 / p5;

  coef_deriv_[0][1] = -3.0 / p4;

  coef_deriv_[0][2] = -0.5 / p3;

  coef_deriv_[0][3] = 6.0 / p5;

  coef_deriv_[0][4] = -3.0 / p4;

  coef_deriv_[0][5] = 0.5 / p3;

  coef_deriv_[0][6] = 30.0 * x0 / p6 + 12.0 * dx0 / p5 + 1.5 * ddx0 / p4 -
                      30.0 * x1 / p6 + 12.0 * dx1 / p5 - 1.5 * ddx1 / p4;

  // derive b
  // double b = 15.0 * x0 / p4 + 8.0 * dx0 / p3 + 1.5 * ddx0 / p2 - 15.0 * x1 /
  // p4 + 7.0 * dx1 / p3 - ddx1 / p2;
  coef_deriv_[1][0] = 15.0 / p4;

  coef_deriv_[1][1] = 8.0 / p3;

  coef_deriv_[1][2] = 1.5 / p2;

  coef_deriv_[1][3] = -15.0 / p4;

  coef_deriv_[1][4] = 7.0 / p3;

  coef_deriv_[1][5] = -1.0 / p2;

  coef_deriv_[1][6] = -60.0 * x0 / p5 - 24.0 * dx0 / p4 - 3.0 * ddx0 / p3 +
                      60.0 * x1 / p5 - 21.0 * dx1 / p4 + 2.0 * ddx1 / p3;

  // derive c
  // double c = -10.0 * x0 / p3 - 6.0 * dx0 / p2 - 1.5 * ddx0 / p + 10.0 * x1 /
  // p3 - 4.0 * dx1 / p2 + 0.5 * ddx1 / p;
  coef_deriv_[2][0] = -10.0 / p3;

  coef_deriv_[2][1] = -6.0 / p2;

  coef_deriv_[2][2] = -1.5 / p;

  coef_deriv_[2][3] = 10.0 / p3;

  coef_deriv_[2][4] = -4.0 / p2;

  coef_deriv_[2][5] = 0.5 / p;

  coef_deriv_[2][6] = 30.0 * x0 / p4 + 12.0 * dx0 / p3 + 1.5 * ddx0 / p2 -
                      30.0 * x1 / p4 + 8.0 * dx1 / p3 - 0.5 * ddx1 / p2;

  // derive d
  // double d = 0.5 * ddx0;
  coef_deriv_[3][0] = 0.0;

  coef_deriv_[3][1] = 0.0;

  coef_deriv_[3][2] = 0.5;

  coef_deriv_[3][3] = 0.0;

  coef_deriv_[3][4] = 0.0;

  coef_deriv_[3][5] = 0.0;

  coef_deriv_[3][6] = 0.0;

  // derive e
  // double e = dx0;
  coef_deriv_[4][0] = 0.0;

  coef_deriv_[4][1] = 1.0;

  coef_deriv_[4][2] = 0.0;

  coef_deriv_[4][3] = 0.0;

  coef_deriv_[4][4] = 0.0;

  coef_deriv_[4][5] = 0.0;

  coef_deriv_[4][6] = 0.0;

  // derive f
  // double f = x0;
  coef_deriv_[5][0] = 1.0;

  coef_deriv_[5][1] = 0.0;

  coef_deriv_[5][2] = 0.0;

  coef_deriv_[5][3] = 0.0;

  coef_deriv_[5][4] = 0.0;

  coef_deriv_[5][5] = 0.0;

  coef_deriv_[5][6] = 0.0;
}

QuinticSpiralPath::QuinticSpiralPath(
    const std::array<double, 3>& start, const std::array<double, 3>& end,
    const double delta_s)
    : QuinticSpiralPath(start[0], start[1], start[2], end[0], end[1],
                                  end[2], delta_s) {}

double QuinticSpiralPath::DeriveTheta(const std::size_t param_index,
                                                const double r) const {
  double s = param_ * r;
  double s2 = s * s;
  double s3 = s2 * s;
  double s4 = s2 * s2;
  double s5 = s3 * s2;

  double derivative =
      coef_deriv_[0][param_index] * s5 + coef_deriv_[1][param_index] * s4 +
      coef_deriv_[2][param_index] * s3 + coef_deriv_[3][param_index] * s2 +
      coef_deriv_[4][param_index] * s + coef_deriv_[5][param_index];

  if (param_index == DELTA_S) {
    derivative += coef_[0] * 5.0 * s4 * r + coef_[1] * 4.0 * s3 * r +
                  coef_[2] * 3.0 * s2 * r + coef_[3] * 2.0 * s * r +
                  coef_[4] * r;
  }
  return derivative;
}

double QuinticSpiralPath::DeriveKappaDerivative(
    const std::size_t param_index, const double r) const {
  double s = param_ * r;
  double s2 = s * s;
  double s3 = s2 * s;

  double derivative = 20.0 * coef_deriv_[0][param_index] * s3 +
                      12.0 * coef_deriv_[1][param_index] * s2 +
                      6.0 * coef_deriv_[2][param_index] * s +
                      2.0 * coef_deriv_[3][param_index];

  if (param_index == DELTA_S) {
    derivative += 20.0 * coef_[0] * 3.0 * s2 * r +
                  12.0 * coef_[1] * 2.0 * s * r + 6.0 * coef_[2] * r;
  }
  return derivative;
}

}  // namespace planning
}  // namespace apollo
<commit_msg>planning: fixed unmatched indices in quintic spiral path<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file quintic_spiral_path.cpp
 **/

#include "modules/planning/math/curve1d/quintic_spiral_path.h"

#include "glog/logging.h"

namespace apollo {
namespace planning {

QuinticSpiralPath::QuinticSpiralPath(
    const double x0, const double dx0, const double ddx0, const double x1,
    const double dx1, const double ddx1, const double p)
    : QuinticPolynomialCurve1d(x0, dx0, ddx0, x1, dx1, ddx1, p) {
  CHECK(p > 0.0);

  double p2 = p * p;
  double p3 = p2 * p;
  double p4 = p3 * p;
  double p5 = p2 * p3;
  double p6 = p3 * p3;

  // derive a
  // double a = -6.0 * x0 / p5 - 3.0 * dx0 / p4 - 0.5 * ddx0 / p3 + 6.0 * x1 /
  // p5 - 3.0 * dx1 / p4 + 0.5 * ddx1 / p3;
  coef_deriv_[5][0] = -6.0 / p5;

  coef_deriv_[5][1] = -3.0 / p4;

  coef_deriv_[5][2] = -0.5 / p3;

  coef_deriv_[5][3] = 6.0 / p5;

  coef_deriv_[5][4] = -3.0 / p4;

  coef_deriv_[5][5] = 0.5 / p3;

  coef_deriv_[5][6] = 30.0 * x0 / p6 + 12.0 * dx0 / p5 + 1.5 * ddx0 / p4 -
                      30.0 * x1 / p6 + 12.0 * dx1 / p5 - 1.5 * ddx1 / p4;

  // derive b
  // double b = 15.0 * x0 / p4 + 8.0 * dx0 / p3 + 1.5 * ddx0 / p2 - 15.0 * x1 /
  // p4 + 7.0 * dx1 / p3 - ddx1 / p2;
  coef_deriv_[4][0] = 15.0 / p4;

  coef_deriv_[4][1] = 8.0 / p3;

  coef_deriv_[4][2] = 1.5 / p2;

  coef_deriv_[4][3] = -15.0 / p4;

  coef_deriv_[4][4] = 7.0 / p3;

  coef_deriv_[4][5] = -1.0 / p2;

  coef_deriv_[4][6] = -60.0 * x0 / p5 - 24.0 * dx0 / p4 - 3.0 * ddx0 / p3 +
                      60.0 * x1 / p5 - 21.0 * dx1 / p4 + 2.0 * ddx1 / p3;

  // derive c
  // double c = -10.0 * x0 / p3 - 6.0 * dx0 / p2 - 1.5 * ddx0 / p + 10.0 * x1 /
  // p3 - 4.0 * dx1 / p2 + 0.5 * ddx1 / p;
  coef_deriv_[3][0] = -10.0 / p3;

  coef_deriv_[3][1] = -6.0 / p2;

  coef_deriv_[3][2] = -1.5 / p;

  coef_deriv_[3][3] = 10.0 / p3;

  coef_deriv_[3][4] = -4.0 / p2;

  coef_deriv_[3][5] = 0.5 / p;

  coef_deriv_[3][6] = 30.0 * x0 / p4 + 12.0 * dx0 / p3 + 1.5 * ddx0 / p2 -
                      30.0 * x1 / p4 + 8.0 * dx1 / p3 - 0.5 * ddx1 / p2;

  // derive d
  // double d = 0.5 * ddx0;
  coef_deriv_[2][0] = 0.0;

  coef_deriv_[2][1] = 0.0;

  coef_deriv_[2][2] = 0.5;

  coef_deriv_[2][3] = 0.0;

  coef_deriv_[2][4] = 0.0;

  coef_deriv_[2][5] = 0.0;

  coef_deriv_[2][6] = 0.0;

  // derive e
  // double e = dx0;
  coef_deriv_[1][0] = 0.0;

  coef_deriv_[1][1] = 1.0;

  coef_deriv_[1][2] = 0.0;

  coef_deriv_[1][3] = 0.0;

  coef_deriv_[1][4] = 0.0;

  coef_deriv_[1][5] = 0.0;

  coef_deriv_[1][6] = 0.0;

  // derive f
  // double f = x0;
  coef_deriv_[0][0] = 1.0;

  coef_deriv_[0][1] = 0.0;

  coef_deriv_[0][2] = 0.0;

  coef_deriv_[0][3] = 0.0;

  coef_deriv_[0][4] = 0.0;

  coef_deriv_[0][5] = 0.0;

  coef_deriv_[0][6] = 0.0;
}

QuinticSpiralPath::QuinticSpiralPath(
    const std::array<double, 3>& start, const std::array<double, 3>& end,
    const double delta_s)
    : QuinticSpiralPath(start[0], start[1], start[2], end[0], end[1],
                                  end[2], delta_s) {}

double QuinticSpiralPath::DeriveTheta(const std::size_t param_index,
                                                const double r) const {
  double s = param_ * r;
  double s2 = s * s;
  double s3 = s2 * s;
  double s4 = s2 * s2;
  double s5 = s3 * s2;

  double derivative =
      coef_deriv_[5][param_index] * s5 + coef_deriv_[4][param_index] * s4 +
      coef_deriv_[3][param_index] * s3 + coef_deriv_[2][param_index] * s2 +
      coef_deriv_[1][param_index] * s + coef_deriv_[0][param_index];

  if (param_index == DELTA_S) {
    derivative += coef_[5] * 5.0 * s4 * r + coef_[4] * 4.0 * s3 * r +
                  coef_[3] * 3.0 * s2 * r + coef_[2] * 2.0 * s * r +
                  coef_[1] * r;
  }
  return derivative;
}

double QuinticSpiralPath::DeriveKappaDerivative(
    const std::size_t param_index, const double r) const {
  double s = param_ * r;
  double s2 = s * s;
  double s3 = s2 * s;

  double derivative = 20.0 * coef_deriv_[5][param_index] * s3 +
                      12.0 * coef_deriv_[4][param_index] * s2 +
                      6.0 * coef_deriv_[3][param_index] * s +
                      2.0 * coef_deriv_[2][param_index];

  if (param_index == DELTA_S) {
    derivative += 20.0 * coef_[5] * 3.0 * s2 * r +
                  12.0 * coef_[4] * 2.0 * s * r + 6.0 * coef_[3] * r;
  }
  return derivative;
}

}  // namespace planning
}  // namespace apollo
<|endoftext|>


<commit_before>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "SurgSim/Framework/Assert.h"
#include "SurgSim/Framework/Timer.h"

namespace SurgSim {
namespace Framework {

Timer::Timer() :
	m_stopped(true), m_maxNumberOfFrames(100), m_clockFails(0)
{
	start();
}

void Timer::start()
{
	m_frameDurations.clear();
	m_clockFails = 0;
	beginFrame();
}

void Timer::beginFrame()
{
	m_lastTime = now();
}

void Timer::endFrame()
{
	TimerTimePoint currentTime = now();
	m_frameDurations.push_back(currentTime - m_lastTime);
	if (m_frameDurations.size() > m_maxNumberOfFrames)
	{
		m_frameDurations.pop_front();
	}
	m_lastTime = currentTime;
}

double Timer::getAverageFramePeriod() const
{
	SURGSIM_ASSERT(m_frameDurations.size() > 0) <<
		"Attempted to access the last frame period for a Timer with no frames.\n";
	TimerDuration cumulativeTime;
	for (auto it = m_frameDurations.begin(); it != m_frameDurations.end(); ++it)
	{
		cumulativeTime += *it;
	}
	return cumulativeTime.count() / m_frameDurations.size();
}

double Timer::getAverageFrameRate() const
{
	return 1.0 / getAverageFramePeriod();
}

double Timer::getLastFramePeriod() const
{
	SURGSIM_ASSERT(m_frameDurations.size() > 0) <<
		"Attempted to access the last frame period for a Timer with no frames.\n";
	return m_frameDurations.back().count();
}

double Timer::getLastFrameRate() const
{
	return 1.0 / getLastFramePeriod();
}

void Timer::setNumberOfFrames(size_t maxNumberOfFrames)
{
	m_maxNumberOfFrames = (maxNumberOfFrames > 0) ? maxNumberOfFrames : 1;
	while (m_frameDurations.size() > m_maxNumberOfFrames)
	{
		m_frameDurations.pop_front();
	}
}

size_t Timer::getCurrentNumberOfFrames() const
{
	return m_frameDurations.size();
}

size_t Timer::getNumberOfClockFails() const
{
	return m_clockFails;
}

Timer::TimerTimePoint Timer::now()
{
	boost::system::error_code ec;
	TimerTimePoint currentTime = m_clock.now(ec);
	if (ec.value() != 0)
	{
		++ m_clockFails;
	}
	return currentTime;
}

}; // namespace Framework
}; // namespace SurgSim
<commit_msg>Fix copy/paste error in assert message about Timer not having frames.<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "SurgSim/Framework/Assert.h"
#include "SurgSim/Framework/Timer.h"

namespace SurgSim {
namespace Framework {

Timer::Timer() :
	m_stopped(true), m_maxNumberOfFrames(100), m_clockFails(0)
{
	start();
}

void Timer::start()
{
	m_frameDurations.clear();
	m_clockFails = 0;
	beginFrame();
}

void Timer::beginFrame()
{
	m_lastTime = now();
}

void Timer::endFrame()
{
	TimerTimePoint currentTime = now();
	m_frameDurations.push_back(currentTime - m_lastTime);
	if (m_frameDurations.size() > m_maxNumberOfFrames)
	{
		m_frameDurations.pop_front();
	}
	m_lastTime = currentTime;
}

double Timer::getAverageFramePeriod() const
{
	SURGSIM_ASSERT(m_frameDurations.size() > 0) <<
		"Attempted to access the frames for a Timer with no frames.\n";
	TimerDuration cumulativeTime;
	for (auto it = m_frameDurations.begin(); it != m_frameDurations.end(); ++it)
	{
		cumulativeTime += *it;
	}
	return cumulativeTime.count() / m_frameDurations.size();
}

double Timer::getAverageFrameRate() const
{
	return 1.0 / getAverageFramePeriod();
}

double Timer::getLastFramePeriod() const
{
	SURGSIM_ASSERT(m_frameDurations.size() > 0) <<
		"Attempted to access the last frame period for a Timer with no frames.\n";
	return m_frameDurations.back().count();
}

double Timer::getLastFrameRate() const
{
	return 1.0 / getLastFramePeriod();
}

void Timer::setNumberOfFrames(size_t maxNumberOfFrames)
{
	m_maxNumberOfFrames = (maxNumberOfFrames > 0) ? maxNumberOfFrames : 1;
	while (m_frameDurations.size() > m_maxNumberOfFrames)
	{
		m_frameDurations.pop_front();
	}
}

size_t Timer::getCurrentNumberOfFrames() const
{
	return m_frameDurations.size();
}

size_t Timer::getNumberOfClockFails() const
{
	return m_clockFails;
}

Timer::TimerTimePoint Timer::now()
{
	boost::system::error_code ec;
	TimerTimePoint currentTime = m_clock.now(ec);
	if (ec.value() != 0)
	{
		++ m_clockFails;
	}
	return currentTime;
}

}; // namespace Framework
}; // namespace SurgSim
<|endoftext|>


<commit_before>// Copyright (c) 2005-2009 Jay Berkenbilt
//
// This file is part of qpdf.  This software may be distributed under
// the terms of version 2 of the Artistic License which may be found
// in the source distribution.  It is provided "as is" without express
// or implied warranty.

#ifndef __QPDFEXC_HH__
#define __QPDFEXC_HH__

#include <qpdf/DLL.h>
#include <qpdf/Constants.h>
#include <stdexcept>
#include <fcntl.h>

class DLL_EXPORT QPDFExc: public std::runtime_error
{
  public:
    QPDFExc(qpdf_error_code_e error_code,
	    std::string const& filename,
	    std::string const& object,
	    off_t offset,
	    std::string const& message);
    virtual ~QPDFExc() throw ();

    // To get a complete error string, call what(), provided by
    // std::exception.  The accessors below return the original values
    // used to create the exception.  Only the error code and message
    // are guaranteed to have non-zero/empty values.

    // There is no lookup code that maps numeric error codes into
    // strings.  The numeric error code is just another way to get at
    // the underlying issue, but it is more programmer-friendly than
    // trying to parse a string that is subject to change.

    qpdf_error_code_e getErrorCode() const;
    std::string const& getFilename() const;
    std::string const& getObject() const;
    off_t getFilePosition() const;
    std::string const& getMessageDetail() const;

  private:
    static std::string createWhat(std::string const& filename,
				  std::string const& object,
				  off_t offset,
				  std::string const& message);

    qpdf_error_code_e error_code;
    std::string filename;
    std::string object;
    off_t offset;
    std::string message;
};

#endif // __QPDFEXC_HH__
<commit_msg>try stdlib.h<commit_after>// Copyright (c) 2005-2009 Jay Berkenbilt
//
// This file is part of qpdf.  This software may be distributed under
// the terms of version 2 of the Artistic License which may be found
// in the source distribution.  It is provided "as is" without express
// or implied warranty.

#ifndef __QPDFEXC_HH__
#define __QPDFEXC_HH__

#include <qpdf/DLL.h>
#include <qpdf/Constants.h>
#include <stdexcept>
#include <fcntl.h>
#include <stdlib.h>

class DLL_EXPORT QPDFExc: public std::runtime_error
{
  public:
    QPDFExc(qpdf_error_code_e error_code,
	    std::string const& filename,
	    std::string const& object,
	    off_t offset,
	    std::string const& message);
    virtual ~QPDFExc() throw ();

    // To get a complete error string, call what(), provided by
    // std::exception.  The accessors below return the original values
    // used to create the exception.  Only the error code and message
    // are guaranteed to have non-zero/empty values.

    // There is no lookup code that maps numeric error codes into
    // strings.  The numeric error code is just another way to get at
    // the underlying issue, but it is more programmer-friendly than
    // trying to parse a string that is subject to change.

    qpdf_error_code_e getErrorCode() const;
    std::string const& getFilename() const;
    std::string const& getObject() const;
    off_t getFilePosition() const;
    std::string const& getMessageDetail() const;

  private:
    static std::string createWhat(std::string const& filename,
				  std::string const& object,
				  off_t offset,
				  std::string const& message);

    qpdf_error_code_e error_code;
    std::string filename;
    std::string object;
    off_t offset;
    std::string message;
};

#endif // __QPDFEXC_HH__
<|endoftext|>


<commit_before><commit_msg>Planning: support simple pull over in dp_road_graph.<commit_after><|endoftext|>