<commit_before>//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef WITHOUT_HSA_BACKEND

#include <string>
#include <sstream>
#include <fstream>
#include <iostream>

#include "os/os.hpp"
#include "rocdevice.hpp"
#include "rocprogram.hpp"
#if defined(WITH_LIGHTNING_COMPILER)
#include "opencl1.2-c.amdgcn.inc"
#include "opencl2.0-c.amdgcn.inc"
#else // !defined(WITH_LIGHTNING_COMPILER)
#include "roccompilerlib.hpp"
#endif // !defined(WITH_LIGHTNING_COMPILER)
#include "utils/options.hpp"
#include <cstdio>

#if defined(ATI_OS_LINUX)
#include <dlfcn.h>
#include <libgen.h>
#endif // defined(ATI_OS_LINUX)

#if defined(WITH_LIGHTNING_COMPILER)
static std::string llvmBin_(amd::Os::getEnvironment("LLVM_BIN"));
#endif // defined(WITH_LIGHTNING_COMPILER)

//CLC_IN_PROCESS_CHANGE
extern int openclFrontEnd(const char* cmdline, std::string*, std::string* typeInfo = NULL);

namespace roc {

/* Temporary log function for the compiler library */
static void
logFunction(const char* msg, size_t size)
{
    std::cout<< "Compiler Log: " << msg << std::endl;
}

static int programsCount = 0;

#if defined(WITH_LIGHTNING_COMPILER)
bool
HSAILProgram::compileImpl_LC(
    const std::string& sourceCode,
    const std::vector<const std::string*>& headers,
    const char** headerIncludeNames,
    amd::option::Options* options)
{
    using namespace amd::opencl_driver;
    std::auto_ptr<Compiler> C(newCompilerInstance());
    std::vector<Data*> inputs;

    if (options->isDumpFlagSet(amd::option::DUMP_CL)) {
        std::ofstream f(options->getDumpFileName(".cl").c_str(), std::ios::trunc);
        if(f.is_open()) {
            f << "/* Compiler options:\n" << options->origOptionStr
                << "\n*/\n\n" << sourceCode;
        } else {
            buildLog_ +=
                "Warning: opening the file to dump the OpenCL source failed.\n";
        }
    }

    Data* input = C->NewBufferReference(DT_CL,
        sourceCode.c_str(), sourceCode.length());
    if (input == NULL) {
        buildLog_ += "Error while creating data from source code";
        return false;
    }

    inputs.push_back(input);

    //Find the temp folder for the OS
    std::string tempFolder = amd::Os::getEnvironment("TEMP");
    if (tempFolder.empty()) {
        tempFolder = amd::Os::getEnvironment("TMP");
        if (tempFolder.empty()) {
            tempFolder = WINDOWS_SWITCH(".","/tmp");;
        }
    }
    //Iterate through each source code and dump it into tmp
    std::fstream f;
    std::vector<std::string> headerFileNames(headers.size());
    std::vector<std::string> newDirs;
    for (size_t i = 0; i < headers.size(); ++i) {
        std::string headerPath = tempFolder;
        std::string headerIncludeName(headerIncludeNames[i]);
        // replace / in path with current os's file separator
        if ( amd::Os::fileSeparator() != '/') {
            for (std::string::iterator it = headerIncludeName.begin(),
                end = headerIncludeName.end();
                it != end;
                ++it) {
                if (*it == '/') *it = amd::Os::fileSeparator();
            }
        }
        size_t pos = headerIncludeName.rfind(amd::Os::fileSeparator());
        if (pos != std::string::npos) {
            headerPath += amd::Os::fileSeparator();
            headerPath += headerIncludeName.substr(0, pos);
            headerIncludeName = headerIncludeName.substr(pos+1);
        }
        if (!amd::Os::pathExists(headerPath)) {
            bool ret = amd::Os::createPath(headerPath);
            assert(ret && "failed creating path!");
            newDirs.push_back(headerPath);
        }
        std::string headerFullName
        = headerPath + amd::Os::fileSeparator() + headerIncludeName;
        headerFileNames[i] = headerFullName;
        f.open(headerFullName.c_str(), std::fstream::out);
        //Should we allow asserts
        assert(!f.fail() && "failed creating header file!");
        f.write(headers[i]->c_str(), headers[i]->length());
        f.close();

        Data* inc = C->NewFileReference(DT_CL_HEADER, headerFileNames[i]);
        if (inc == NULL) {
            buildLog_ += "Error while creating data from headers";
            return false;
        }
        inputs.push_back(inc);
    }

    //Set the options for the compiler
    std::ostringstream ostrstr;
    std::copy(options->clangOptions.begin(), options->clangOptions.end(),
        std::ostream_iterator<std::string>(ostrstr, " "));
    std::string driverOptions(ostrstr.str());

    //Set the include path for the temp folder that contains the includes
    if(!headers.empty()) {
        driverOptions.append(" -I");
        driverOptions.append(tempFolder);
    }

    const char* xLang = options->oVariables->XLang;
    if (xLang != NULL && strcmp(xLang, "cl")) {
        buildLog_ += "Unsupported OpenCL language.\n";
    }

    //FIXME_Nikolay: the program manager should be setting the language
    //driverOptions.append(" -x cl");
    //FIXME_Nikolay: the program manager shouls be setting the cl-std. -Xclang
    //is not necessary, we add it to overridde the flag set in the comp driver.
    driverOptions.append(" -Xclang -cl-std=").append(options->oVariables->CLStd);

    std::ostringstream optLevel;
    optLevel << " -O" << options->oVariables->OptLevel;
    driverOptions.append(optLevel.str());

    //FIXME_lmoriche: has the CL option been validated?
    uint clVer = (options->oVariables->CLStd[2] - '0') * 100
        + (options->oVariables->CLStd[4] - '0') * 10;

    std::pair<const void*, size_t> hdr;
    switch(clVer) {
    case 120:
        hdr = std::make_pair(opencl1_2_c_amdgcn, opencl1_2_c_amdgcn_size);
        break;
    case 200:
        hdr = std::make_pair(opencl2_0_c_amdgcn, opencl2_0_c_amdgcn_size);
        break;
    default:
        buildLog_ += "Unsupported requested OpenCL C version (-cl-std).\n";
        return false;
    }

    File* pch = C->NewTempFile(DT_CL_HEADER);
    if (pch == NULL || !pch->WriteData((const char*) hdr.first, hdr.second)) {
        buildLog_ += "Error while opening the opencl-c header ";
        return false;
    }

    driverOptions.append(" -include-pch " + pch->Name());
    driverOptions.append(" -Xclang -fno-validate-pch");
    driverOptions.append(" -isysroot " + llvmBin_ + "/../../include");

    driverOptions.append(hsailOptions(options));
    if (clVer >= 200) {
        std::stringstream opts;
        //Add only for CL2.0 and later
        opts << " -D" << "CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE="
            << device().info().maxGlobalVariableSize_;
        driverOptions.append(opts.str());
    }

    Buffer* output = C->NewBuffer(DT_LLVM_BC);
    if (output == NULL) {
        buildLog_ += "Error while creating buffer for the LLVM bitcode";
        return false;
    }

    // Tokenize the options string into a vector of strings
    std::istringstream istrstr(driverOptions);
    std::istream_iterator<std::string> sit(istrstr), end;
    std::vector<std::string> params(sit, end);

    // Compile source to IR
    bool ret = C->CompileToLLVMBitcode(inputs, output, params);
    buildLog_ += C->Output();
    if (!ret) {
        buildLog_ += "Error while compiling opencl source: Compiling CL to IR";
        return false;
    }

    llvmBinary_.assign(output->Buf().data(), output->Size());
    elfSectionType_ = amd::OclElf::LLVMIR;

    if (options->isDumpFlagSet(amd::option::DUMP_BC_ORIGINAL)) {
        std::ofstream f(options->getDumpFileName("_original.bc").c_str(), std::ios::trunc);
        if(f.is_open()) {
            f.write(llvmBinary_.data(), llvmBinary_.size());
        } else {
            buildLog_ +=
                "Warning: opening the file to dump the compiled IR failed.\n";
        }
    }

    if (clBinary()->saveSOURCE()) {
        clBinary()->elfOut()->addSection(
            amd::OclElf::SOURCE, sourceCode.data(), sourceCode.size());
    }
    if (clBinary()->saveLLVMIR()) {
        clBinary()->elfOut()->addSection(
            amd::OclElf::LLVMIR, llvmBinary_.data(), llvmBinary_.size(), false);
        // store the original compile options
        clBinary()->storeCompileOptions(compileOptions_);
    }
    return true;
}
#endif // defined(WITH_LIGHTNING_COMPILER)

bool
HSAILProgram::compileImpl(
    const std::string& sourceCode,
    const std::vector<const std::string*>& headers,
    const char** headerIncludeNames,
    amd::option::Options* options)
{
#if defined(WITH_LIGHTNING_COMPILER)
    return compileImpl_LC(sourceCode, headers, headerIncludeNames, options);
#else // !defined(WITH_LIGHTNING_COMPILER)
    acl_error errorCode;
    aclTargetInfo target;

    //Defaulting to bonaire
    //Todo (sramalin) : Query the device for asic type-
    //Defaulting to Bonair for now.
    target = g_complibApi._aclGetTargetInfo(LP64_SWITCH("hsail","hsail64"), "Bonaire",
        &errorCode);

    //end if asic info is ready
    // We dump the source code for each program (param: headers)
    // into their filenames (headerIncludeNames) into the TEMP
    // folder specific to the OS and add the include path while
    // compiling

    //Find the temp folder for the OS
    std::string tempFolder = amd::Os::getEnvironment("TEMP");
    if (tempFolder.empty()) {
        tempFolder = amd::Os::getEnvironment("TMP");
        if (tempFolder.empty()) {
            tempFolder = WINDOWS_SWITCH(".","/tmp");;
        }
    }
    //Iterate through each source code and dump it into tmp
    std::fstream f;
    std::vector<std::string> headerFileNames(headers.size());
    std::vector<std::string> newDirs;
    for (size_t i = 0; i < headers.size(); ++i) {
        std::string headerPath = tempFolder;
        std::string headerIncludeName(headerIncludeNames[i]);
        // replace / in path with current os's file separator
        if ( amd::Os::fileSeparator() != '/') {
            for (std::string::iterator it = headerIncludeName.begin(),
                end = headerIncludeName.end();
                it != end;
                ++it) {
                if (*it == '/') *it = amd::Os::fileSeparator();
            }
        }
        size_t pos = headerIncludeName.rfind(amd::Os::fileSeparator());
        if (pos != std::string::npos) {
            headerPath += amd::Os::fileSeparator();
            headerPath += headerIncludeName.substr(0, pos);
            headerIncludeName = headerIncludeName.substr(pos+1);
        }
        if (!amd::Os::pathExists(headerPath)) {
            bool ret = amd::Os::createPath(headerPath);
            assert(ret && "failed creating path!");
            newDirs.push_back(headerPath);
        }
        std::string headerFullName
        = headerPath + amd::Os::fileSeparator() + headerIncludeName;
        headerFileNames[i] = headerFullName;
        f.open(headerFullName.c_str(), std::fstream::out);
        //Should we allow asserts
        assert(!f.fail() && "failed creating header file!");
        f.write(headers[i]->c_str(), headers[i]->length());
        f.close();
    }

    //Create Binary
    binaryElf_ = g_complibApi._aclBinaryInit(sizeof(aclBinary),
        &target,
        &binOpts_,
        &errorCode);

    if( errorCode!=ACL_SUCCESS ) {
        buildLog_ += "Error while compiling opencl source:\
                     aclBinary init failure \n";
        LogWarning("aclBinaryInit failed");
        return false;
    }

    //Insert opencl into binary
    errorCode = g_complibApi._aclInsertSection(device().compiler(),
        binaryElf_,
        sourceCode.c_str(),
        strlen(sourceCode.c_str()),
        aclSOURCE);

    if ( errorCode != ACL_SUCCESS )    {
        buildLog_ += "Error while converting to BRIG: \
                     Inserting openCl Source \n";
    }

    //Set the options for the compiler
    //Set the include path for the temp folder that contains the includes
    if(!headers.empty()) {
        this->compileOptions_.append(" -I");
        this->compileOptions_.append(tempFolder);
    }

    //Add only for CL2.0 and later
    if (options->oVariables->CLStd[2] >= '2') {
        std::stringstream opts;
        opts << " -D" << "CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE="
            << device().info().maxGlobalVariableSize_;
        compileOptions_.append(opts.str());
    }

    //Compile source to IR
    this->compileOptions_.append(hsailOptions(options));

    errorCode = g_complibApi._aclCompile(device().compiler(),
        binaryElf_,
        //"-Wf,--support_all_extensions",
        this->compileOptions_.c_str(),
        ACL_TYPE_OPENCL,
        ACL_TYPE_LLVMIR_BINARY,
        logFunction);
    buildLog_ += g_complibApi._aclGetCompilerLog(device().compiler());
    if( errorCode!=ACL_SUCCESS ) {
        LogWarning("aclCompile failed");
        buildLog_ += "Error while compiling \
                     opencl source: Compiling CL to IR";
        return false;
    }
    // Save the binary in the interface class
    saveBinaryAndSetType(TYPE_COMPILED);
    return true;
#endif // !defined(WITH_LIGHTNING_COMPILER)
}

#if defined(WITH_LIGHTNING_COMPILER)
#if defined(ATI_OS_LINUX)
static pthread_once_t once = PTHREAD_ONCE_INIT;

static void
checkLLVM_BIN()
{
    if (llvmBin_.empty()) {
        Dl_info info;
        if (dladdr((const void*)&amd::Device::init, &info)) {
            llvmBin_ = dirname(strdup(info.dli_fname));
            size_t pos = llvmBin_.rfind("lib");
            if (pos != std::string::npos) {
                llvmBin_.replace(pos, 3, "bin");
            }
        }
    }
#if defined(DEBUG)
    std::string clangExe(llvmBin_ + "/clang");
    struct stat buf;
    if (stat(clangExe.c_str(), &buf)) {
        std::string msg("Could not find the Clang binary in " + llvmBin_);
        LogWarning(msg.c_str());
    }
#endif // defined(DEBUG)
}
#endif // defined(ATI_OS_LINUX)

std::auto_ptr<amd::opencl_driver::Compiler>
HSAILProgram::newCompilerInstance()
{
#if defined(ATI_OS_LINUX)
    pthread_once(&once, checkLLVM_BIN);
#endif // defined(ATI_OS_LINUX)
    return std::auto_ptr<amd::opencl_driver::Compiler>(
        amd::opencl_driver::CompilerFactory().CreateAMDGPUCompiler(llvmBin_));
}
#endif // defined(WITH_LIGHTNING_COMPILER)

} // namespace roc
#endif // WITHOUT_GPU_BACKEND
<commit_msg>P4 to Git Change 1310397 by lmoriche@lmoriche_opencl_dev on 2016/09/02 13:55:00<commit_after>//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef WITHOUT_HSA_BACKEND

#include <string>
#include <sstream>
#include <fstream>
#include <iostream>

#include "os/os.hpp"
#include "rocdevice.hpp"
#include "rocprogram.hpp"
#if defined(WITH_LIGHTNING_COMPILER)
#include "opencl1.2-c.amdgcn.inc"
#include "opencl2.0-c.amdgcn.inc"
#else // !defined(WITH_LIGHTNING_COMPILER)
#include "roccompilerlib.hpp"
#endif // !defined(WITH_LIGHTNING_COMPILER)
#include "utils/options.hpp"
#include <cstdio>

#if defined(ATI_OS_LINUX)
#include <dlfcn.h>
#include <libgen.h>
#endif // defined(ATI_OS_LINUX)

#if defined(WITH_LIGHTNING_COMPILER)
static std::string llvmBin_(amd::Os::getEnvironment("LLVM_BIN"));
#endif // defined(WITH_LIGHTNING_COMPILER)

//CLC_IN_PROCESS_CHANGE
extern int openclFrontEnd(const char* cmdline, std::string*, std::string* typeInfo = NULL);

namespace roc {

/* Temporary log function for the compiler library */
static void
logFunction(const char* msg, size_t size)
{
    std::cout<< "Compiler Log: " << msg << std::endl;
}

static int programsCount = 0;

#if defined(WITH_LIGHTNING_COMPILER)
bool
HSAILProgram::compileImpl_LC(
    const std::string& sourceCode,
    const std::vector<const std::string*>& headers,
    const char** headerIncludeNames,
    amd::option::Options* options)
{
    using namespace amd::opencl_driver;
    std::auto_ptr<Compiler> C(newCompilerInstance());
    std::vector<Data*> inputs;

    if (options->isDumpFlagSet(amd::option::DUMP_CL)) {
        std::ofstream f(options->getDumpFileName(".cl").c_str(), std::ios::trunc);
        if(f.is_open()) {
            f << "/* Compiler options:\n" << options->origOptionStr
                << "\n*/\n\n" << sourceCode;
        } else {
            buildLog_ +=
                "Warning: opening the file to dump the OpenCL source failed.\n";
        }
    }

    Data* input = C->NewBufferReference(DT_CL,
        sourceCode.c_str(), sourceCode.length());
    if (input == NULL) {
        buildLog_ += "Error while creating data from source code";
        return false;
    }

    inputs.push_back(input);

    //Find the temp folder for the OS
    std::string tempFolder = amd::Os::getEnvironment("TEMP");
    if (tempFolder.empty()) {
        tempFolder = amd::Os::getEnvironment("TMP");
        if (tempFolder.empty()) {
            tempFolder = WINDOWS_SWITCH(".","/tmp");;
        }
    }
    //Iterate through each source code and dump it into tmp
    std::fstream f;
    std::vector<std::string> headerFileNames(headers.size());
    std::vector<std::string> newDirs;
    for (size_t i = 0; i < headers.size(); ++i) {
        std::string headerPath = tempFolder;
        std::string headerIncludeName(headerIncludeNames[i]);
        // replace / in path with current os's file separator
        if ( amd::Os::fileSeparator() != '/') {
            for (std::string::iterator it = headerIncludeName.begin(),
                end = headerIncludeName.end();
                it != end;
                ++it) {
                if (*it == '/') *it = amd::Os::fileSeparator();
            }
        }
        size_t pos = headerIncludeName.rfind(amd::Os::fileSeparator());
        if (pos != std::string::npos) {
            headerPath += amd::Os::fileSeparator();
            headerPath += headerIncludeName.substr(0, pos);
            headerIncludeName = headerIncludeName.substr(pos+1);
        }
        if (!amd::Os::pathExists(headerPath)) {
            bool ret = amd::Os::createPath(headerPath);
            assert(ret && "failed creating path!");
            newDirs.push_back(headerPath);
        }
        std::string headerFullName
        = headerPath + amd::Os::fileSeparator() + headerIncludeName;
        headerFileNames[i] = headerFullName;
        f.open(headerFullName.c_str(), std::fstream::out);
        //Should we allow asserts
        assert(!f.fail() && "failed creating header file!");
        f.write(headers[i]->c_str(), headers[i]->length());
        f.close();

        Data* inc = C->NewFileReference(DT_CL_HEADER, headerFileNames[i]);
        if (inc == NULL) {
            buildLog_ += "Error while creating data from headers";
            return false;
        }
        inputs.push_back(inc);
    }

    //Set the options for the compiler
    std::ostringstream ostrstr;
    std::copy(options->clangOptions.begin(), options->clangOptions.end(),
        std::ostream_iterator<std::string>(ostrstr, " "));
    std::string driverOptions(ostrstr.str());

    //Set the include path for the temp folder that contains the includes
    if(!headers.empty()) {
        driverOptions.append(" -I");
        driverOptions.append(tempFolder);
    }

    const char* xLang = options->oVariables->XLang;
    if (xLang != NULL && strcmp(xLang, "cl")) {
        buildLog_ += "Unsupported OpenCL language.\n";
    }

    //FIXME_Nikolay: the program manager should be setting the language
    //driverOptions.append(" -x cl");
    //FIXME_Nikolay: the program manager shouls be setting the cl-std. -Xclang
    //is not necessary, we add it to overridde the flag set in the comp driver.
    driverOptions.append(" -Xclang -cl-std=").append(options->oVariables->CLStd);

    std::ostringstream optLevel;
    optLevel << " -O" << options->oVariables->OptLevel;
    driverOptions.append(optLevel.str());

    //FIXME_lmoriche: has the CL option been validated?
    uint clVer = (options->oVariables->CLStd[2] - '0') * 100
        + (options->oVariables->CLStd[4] - '0') * 10;

    std::pair<const void*, size_t> hdr;
    switch(clVer) {
    case 120:
        hdr = std::make_pair(opencl1_2_c_amdgcn, opencl1_2_c_amdgcn_size);
        break;
    case 200:
        hdr = std::make_pair(opencl2_0_c_amdgcn, opencl2_0_c_amdgcn_size);
        break;
    default:
        buildLog_ += "Unsupported requested OpenCL C version (-cl-std).\n";
        return false;
    }

    File* pch = C->NewTempFile(DT_CL_HEADER);
    if (pch == NULL || !pch->WriteData((const char*) hdr.first, hdr.second)) {
        buildLog_ += "Error while opening the opencl-c header ";
        return false;
    }

    driverOptions.append(" -include-pch " + pch->Name());
    driverOptions.append(" -Xclang -fno-validate-pch");

    driverOptions.append(hsailOptions(options));
    if (clVer >= 200) {
        std::stringstream opts;
        //Add only for CL2.0 and later
        opts << " -D" << "CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE="
            << device().info().maxGlobalVariableSize_;
        driverOptions.append(opts.str());
    }

    Buffer* output = C->NewBuffer(DT_LLVM_BC);
    if (output == NULL) {
        buildLog_ += "Error while creating buffer for the LLVM bitcode";
        return false;
    }

    // Tokenize the options string into a vector of strings
    std::istringstream istrstr(driverOptions);
    std::istream_iterator<std::string> sit(istrstr), end;
    std::vector<std::string> params(sit, end);

    // Compile source to IR
    bool ret = C->CompileToLLVMBitcode(inputs, output, params);
    buildLog_ += C->Output();
    if (!ret) {
        buildLog_ += "Error while compiling opencl source: Compiling CL to IR";
        return false;
    }

    llvmBinary_.assign(output->Buf().data(), output->Size());
    elfSectionType_ = amd::OclElf::LLVMIR;

    if (options->isDumpFlagSet(amd::option::DUMP_BC_ORIGINAL)) {
        std::ofstream f(options->getDumpFileName("_original.bc").c_str(), std::ios::trunc);
        if(f.is_open()) {
            f.write(llvmBinary_.data(), llvmBinary_.size());
        } else {
            buildLog_ +=
                "Warning: opening the file to dump the compiled IR failed.\n";
        }
    }

    if (clBinary()->saveSOURCE()) {
        clBinary()->elfOut()->addSection(
            amd::OclElf::SOURCE, sourceCode.data(), sourceCode.size());
    }
    if (clBinary()->saveLLVMIR()) {
        clBinary()->elfOut()->addSection(
            amd::OclElf::LLVMIR, llvmBinary_.data(), llvmBinary_.size(), false);
        // store the original compile options
        clBinary()->storeCompileOptions(compileOptions_);
    }
    return true;
}
#endif // defined(WITH_LIGHTNING_COMPILER)

bool
HSAILProgram::compileImpl(
    const std::string& sourceCode,
    const std::vector<const std::string*>& headers,
    const char** headerIncludeNames,
    amd::option::Options* options)
{
#if defined(WITH_LIGHTNING_COMPILER)
    return compileImpl_LC(sourceCode, headers, headerIncludeNames, options);
#else // !defined(WITH_LIGHTNING_COMPILER)
    acl_error errorCode;
    aclTargetInfo target;

    //Defaulting to bonaire
    //Todo (sramalin) : Query the device for asic type-
    //Defaulting to Bonair for now.
    target = g_complibApi._aclGetTargetInfo(LP64_SWITCH("hsail","hsail64"), "Bonaire",
        &errorCode);

    //end if asic info is ready
    // We dump the source code for each program (param: headers)
    // into their filenames (headerIncludeNames) into the TEMP
    // folder specific to the OS and add the include path while
    // compiling

    //Find the temp folder for the OS
    std::string tempFolder = amd::Os::getEnvironment("TEMP");
    if (tempFolder.empty()) {
        tempFolder = amd::Os::getEnvironment("TMP");
        if (tempFolder.empty()) {
            tempFolder = WINDOWS_SWITCH(".","/tmp");;
        }
    }
    //Iterate through each source code and dump it into tmp
    std::fstream f;
    std::vector<std::string> headerFileNames(headers.size());
    std::vector<std::string> newDirs;
    for (size_t i = 0; i < headers.size(); ++i) {
        std::string headerPath = tempFolder;
        std::string headerIncludeName(headerIncludeNames[i]);
        // replace / in path with current os's file separator
        if ( amd::Os::fileSeparator() != '/') {
            for (std::string::iterator it = headerIncludeName.begin(),
                end = headerIncludeName.end();
                it != end;
                ++it) {
                if (*it == '/') *it = amd::Os::fileSeparator();
            }
        }
        size_t pos = headerIncludeName.rfind(amd::Os::fileSeparator());
        if (pos != std::string::npos) {
            headerPath += amd::Os::fileSeparator();
            headerPath += headerIncludeName.substr(0, pos);
            headerIncludeName = headerIncludeName.substr(pos+1);
        }
        if (!amd::Os::pathExists(headerPath)) {
            bool ret = amd::Os::createPath(headerPath);
            assert(ret && "failed creating path!");
            newDirs.push_back(headerPath);
        }
        std::string headerFullName
        = headerPath + amd::Os::fileSeparator() + headerIncludeName;
        headerFileNames[i] = headerFullName;
        f.open(headerFullName.c_str(), std::fstream::out);
        //Should we allow asserts
        assert(!f.fail() && "failed creating header file!");
        f.write(headers[i]->c_str(), headers[i]->length());
        f.close();
    }

    //Create Binary
    binaryElf_ = g_complibApi._aclBinaryInit(sizeof(aclBinary),
        &target,
        &binOpts_,
        &errorCode);

    if( errorCode!=ACL_SUCCESS ) {
        buildLog_ += "Error while compiling opencl source:\
                     aclBinary init failure \n";
        LogWarning("aclBinaryInit failed");
        return false;
    }

    //Insert opencl into binary
    errorCode = g_complibApi._aclInsertSection(device().compiler(),
        binaryElf_,
        sourceCode.c_str(),
        strlen(sourceCode.c_str()),
        aclSOURCE);

    if ( errorCode != ACL_SUCCESS )    {
        buildLog_ += "Error while converting to BRIG: \
                     Inserting openCl Source \n";
    }

    //Set the options for the compiler
    //Set the include path for the temp folder that contains the includes
    if(!headers.empty()) {
        this->compileOptions_.append(" -I");
        this->compileOptions_.append(tempFolder);
    }

    //Add only for CL2.0 and later
    if (options->oVariables->CLStd[2] >= '2') {
        std::stringstream opts;
        opts << " -D" << "CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE="
            << device().info().maxGlobalVariableSize_;
        compileOptions_.append(opts.str());
    }

    //Compile source to IR
    this->compileOptions_.append(hsailOptions(options));

    errorCode = g_complibApi._aclCompile(device().compiler(),
        binaryElf_,
        //"-Wf,--support_all_extensions",
        this->compileOptions_.c_str(),
        ACL_TYPE_OPENCL,
        ACL_TYPE_LLVMIR_BINARY,
        logFunction);
    buildLog_ += g_complibApi._aclGetCompilerLog(device().compiler());
    if( errorCode!=ACL_SUCCESS ) {
        LogWarning("aclCompile failed");
        buildLog_ += "Error while compiling \
                     opencl source: Compiling CL to IR";
        return false;
    }
    // Save the binary in the interface class
    saveBinaryAndSetType(TYPE_COMPILED);
    return true;
#endif // !defined(WITH_LIGHTNING_COMPILER)
}

#if defined(WITH_LIGHTNING_COMPILER)
#if defined(ATI_OS_LINUX)
static pthread_once_t once = PTHREAD_ONCE_INIT;

static void
checkLLVM_BIN()
{
    if (llvmBin_.empty()) {
        Dl_info info;
        if (dladdr((const void*)&amd::Device::init, &info)) {
            llvmBin_ = dirname(strdup(info.dli_fname));
            size_t pos = llvmBin_.rfind("lib");
            if (pos != std::string::npos) {
                llvmBin_.replace(pos, 3, "bin");
            }
        }
    }
#if defined(DEBUG)
    std::string clangExe(llvmBin_ + "/clang");
    struct stat buf;
    if (stat(clangExe.c_str(), &buf)) {
        std::string msg("Could not find the Clang binary in " + llvmBin_);
        LogWarning(msg.c_str());
    }
#endif // defined(DEBUG)
}
#endif // defined(ATI_OS_LINUX)

std::auto_ptr<amd::opencl_driver::Compiler>
HSAILProgram::newCompilerInstance()
{
#if defined(ATI_OS_LINUX)
    pthread_once(&once, checkLLVM_BIN);
#endif // defined(ATI_OS_LINUX)
    return std::auto_ptr<amd::opencl_driver::Compiler>(
        amd::opencl_driver::CompilerFactory().CreateAMDGPUCompiler(llvmBin_));
}
#endif // defined(WITH_LIGHTNING_COMPILER)

} // namespace roc
#endif // WITHOUT_GPU_BACKEND
<|endoftext|>


<commit_before>#include "blackhole/formatter/json.hpp"

#include <array>

#include <boost/variant/apply_visitor.hpp>

#ifndef RAPIDJSON_HAS_STDSTRING
#define RAPIDJSON_HAS_STDSTRING 1
#endif
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <rapidjson/pointer.h>

#include "blackhole/record.hpp"
#include "blackhole/extensions/writer.hpp"

#include "blackhole/detail/attribute.hpp"
#include "blackhole/detail/unimplemented.hpp"

namespace blackhole {
namespace formatter {

namespace {

struct visitor_t {
    typedef void result_type;

    rapidjson::Value& node;
    rapidjson::MemoryPoolAllocator<>& allocator;

    const string_view& name;

    auto operator()(std::nullptr_t) -> void {
        node.AddMember(rapidjson::StringRef(name.data(), name.size()), rapidjson::kNullType, allocator);
    }

    auto operator()(bool value) -> void {
        node.AddMember(rapidjson::StringRef(name.data(), name.size()), value, allocator);
    }

    auto operator()(std::int64_t value) -> void {
        node.AddMember(rapidjson::StringRef(name.data(), name.size()), value, allocator);
    }

    auto operator()(std::uint64_t value) -> void {
        node.AddMember(rapidjson::StringRef(name.data(), name.size()), value, allocator);
    }

    auto operator()(double value) -> void {
        node.AddMember(rapidjson::StringRef(name.data(), name.size()), value, allocator);
    }

    auto operator()(const string_view& value) -> void {
        node.AddMember(rapidjson::StringRef(name.data(), name.size()),
            rapidjson::StringRef(value.data(), value.size()), allocator);
    }
};

template<typename Map, typename F>
inline auto find(const Map& map, const typename Map::key_type& key, const F& fn) ->
    typename Map::mapped_type
{
    const auto it = map.find(key);
    if (it == map.end()) {
        return fn();
    } else {
        return it->second;
    }
}

/// A RapidJSON Stream concept implementation required to avoid intermediate buffer allocation.
struct stream_t {
    typedef char Ch;

    writer_t& wr;

    /// Writes a character directly into the underlying buffer.
    auto Put(Ch c) -> void {
        wr.inner << c;
    }

    /// Does nothing, because there is no intermediate buffer.
    auto Flush() -> void {}
};

template<typename> class builder;

}  // namespace

class json_t::factory_t {
public:
    // A JSON routing pointer for attributes that weren't mentioned in `routing` map.
    rapidjson::Pointer rest;
    // Routing map from attribute name to its JSON pointer.
    std::unordered_map<std::string, rapidjson::Pointer> routing;

    factory_t() :
        rest("")
    {}

    factory_t(routing_t routing) :
        rest(routing.unspecified)
    {
        for (const auto& route : routing.specified) {
            for (const auto& name : route.second) {
                this->routing.insert({name, rapidjson::Pointer(route.first)});
            }
        }
    }

    template<typename Document>
    auto get(const string_view& name, Document& root) -> rapidjson::Value& {
        const auto& route = find(routing, name.to_string(), [&]() -> const rapidjson::Pointer& {
            return rest;
        });

        return route.GetWithDefault(root, rapidjson::kObjectType);
    }

    template<typename Document>
    auto create(Document& root, const record_t& record) -> builder<Document>;
};

template<typename Document>
class json_t::builder {
    Document& root;
    const record_t& record;
    factory_t& factory;

public:
    builder(Document& root, const record_t& record, factory_t& factory) :
        root(root),
        record(record),
        factory(factory)
    {}

    auto message() -> void {
        apply("message", record.message());
    }

    auto severity() -> void {
        apply("severity", static_cast<std::int64_t>(record.severity()));
    }

    auto timestamp() -> void {
        apply("timestamp", std::chrono::duration_cast<
            std::chrono::microseconds
        >(record.timestamp().time_since_epoch()).count());
    }

    auto build(writer_t& writer) -> void {
        stream_t stream{writer};
        rapidjson::Writer<stream_t> wr(stream);
        root.Accept(wr);
    }

    auto attributes() -> void {
        // TODO: Make flattened range
        // TODO: Make uniqued range.
        for (const auto& attributes : record.attributes()) {
            for (const auto& attribute : attributes.get()) {
                apply(attribute.first, attribute.second);
            }
        }
    }

private:
    template<typename T>
    auto apply(const string_view& name, const T& value) -> void {
        visitor_t visitor{factory.get(name, root), root.GetAllocator(), name};
        visitor(value);
    }

    auto apply(const string_view& name, const attribute::view_t& value) -> void {
        visitor_t visitor{factory.get(name, root), root.GetAllocator(), name};
        boost::apply_visitor(visitor, value.inner().value);
    }
};

template<typename Document>
auto json_t::factory_t::create(Document& root, const record_t& record) ->
    builder<Document>
{
    return builder<Document>{root, record, *this};
}

json_t::json_t() :
    factory(new factory_t)
{}

json_t::json_t(routing_t routing) :
    factory(new factory_t(std::move(routing)))
{}

json_t::~json_t() {}

auto json_t::format(const record_t& record, writer_t& writer) -> void {
    typedef rapidjson::GenericDocument<
        rapidjson::UTF8<>,
        rapidjson::MemoryPoolAllocator<>,
        rapidjson::MemoryPoolAllocator<>
    > document_type;

    std::array<char, 4096> value_buffer;
    std::array<char, 1024> parse_buffer;
    rapidjson::MemoryPoolAllocator<> value_allocator(value_buffer.data(), value_buffer.size());
    rapidjson::MemoryPoolAllocator<> parse_allocator(parse_buffer.data(), parse_buffer.size());

    document_type root(&value_allocator, parse_buffer.size(), &parse_allocator);
    root.SetObject();

    // TODO: Try to use `AutoUTF<>` or `AutoUTFOutputStream` for UTF-8 validation.

    auto builder = factory->create(root, record);
    builder.message();
    builder.severity();
    builder.timestamp();
    builder.attributes();

    builder.build(writer);

    // TODO: Add newline if required. Obtained through config.
    // if (config.newline) {
    //     writer << '\n';
    // }
}

}  // namespace formatter
}  // namespace blackhole
<commit_msg>refactor(formatter/json): reuse the code<commit_after>#include "blackhole/formatter/json.hpp"

#include <array>

#include <boost/variant/apply_visitor.hpp>

#ifndef RAPIDJSON_HAS_STDSTRING
#define RAPIDJSON_HAS_STDSTRING 1
#endif
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <rapidjson/pointer.h>

#include "blackhole/record.hpp"
#include "blackhole/extensions/writer.hpp"

#include "blackhole/detail/attribute.hpp"
#include "blackhole/detail/unimplemented.hpp"

namespace blackhole {
namespace formatter {

namespace {

struct visitor_t {
    typedef void result_type;

    rapidjson::Value& node;
    rapidjson::MemoryPoolAllocator<>& allocator;

    const string_view& name;

    auto operator()(std::nullptr_t) -> void {
        node.AddMember(rapidjson::StringRef(name.data(), name.size()), rapidjson::kNullType, allocator);
    }

    // For `bool`, `std::int64_t`, `std::uint64_t` and `double` types.
    template<typename T>
    auto operator()(T value) -> void {
        static_assert(
            std::is_same<T, bool>::value ||
            std::is_same<T, std::int64_t>::value ||
            std::is_same<T, std::uint64_t>::value ||
            std::is_same<T, double>::value, "type mismatch");
        node.AddMember(rapidjson::StringRef(name.data(), name.size()), value, allocator);
    }

    auto operator()(const string_view& value) -> void {
        node.AddMember(rapidjson::StringRef(name.data(), name.size()),
            rapidjson::StringRef(value.data(), value.size()), allocator);
    }
};

template<typename Map, typename F>
inline auto find(const Map& map, const typename Map::key_type& key, const F& fn) ->
    typename Map::mapped_type
{
    const auto it = map.find(key);
    if (it == map.end()) {
        return fn();
    } else {
        return it->second;
    }
}

/// A RapidJSON Stream concept implementation required to avoid intermediate buffer allocation.
struct stream_t {
    typedef char Ch;

    writer_t& wr;

    /// Writes a character directly into the underlying buffer.
    auto Put(Ch c) -> void {
        wr.inner << c;
    }

    /// Does nothing, because there is no intermediate buffer.
    auto Flush() -> void {}
};

template<typename> class builder;

}  // namespace

class json_t::factory_t {
public:
    // A JSON routing pointer for attributes that weren't mentioned in `routing` map.
    rapidjson::Pointer rest;
    // Routing map from attribute name to its JSON pointer.
    std::unordered_map<std::string, rapidjson::Pointer> routing;

    factory_t() :
        rest("")
    {}

    factory_t(routing_t routing) :
        rest(routing.unspecified)
    {
        for (const auto& route : routing.specified) {
            for (const auto& name : route.second) {
                this->routing.insert({name, rapidjson::Pointer(route.first)});
            }
        }
    }

    template<typename Document>
    auto get(const string_view& name, Document& root) -> rapidjson::Value& {
        const auto& route = find(routing, name.to_string(), [&]() -> const rapidjson::Pointer& {
            return rest;
        });

        return route.GetWithDefault(root, rapidjson::kObjectType);
    }

    template<typename Document>
    auto create(Document& root, const record_t& record) -> builder<Document>;
};

template<typename Document>
class json_t::builder {
    Document& root;
    const record_t& record;
    factory_t& factory;

public:
    builder(Document& root, const record_t& record, factory_t& factory) :
        root(root),
        record(record),
        factory(factory)
    {}

    auto message() -> void {
        apply("message", record.message());
    }

    auto severity() -> void {
        apply("severity", static_cast<std::int64_t>(record.severity()));
    }

    auto timestamp() -> void {
        apply("timestamp", std::chrono::duration_cast<
            std::chrono::microseconds
        >(record.timestamp().time_since_epoch()).count());
    }

    auto build(writer_t& writer) -> void {
        stream_t stream{writer};
        rapidjson::Writer<stream_t> wr(stream);
        root.Accept(wr);
    }

    auto attributes() -> void {
        // TODO: Make flattened range
        // TODO: Make uniqued range.
        for (const auto& attributes : record.attributes()) {
            for (const auto& attribute : attributes.get()) {
                apply(attribute.first, attribute.second);
            }
        }
    }

private:
    template<typename T>
    auto apply(const string_view& name, const T& value) -> void {
        visitor_t visitor{factory.get(name, root), root.GetAllocator(), name};
        visitor(value);
    }

    auto apply(const string_view& name, const attribute::view_t& value) -> void {
        visitor_t visitor{factory.get(name, root), root.GetAllocator(), name};
        boost::apply_visitor(visitor, value.inner().value);
    }
};

template<typename Document>
auto json_t::factory_t::create(Document& root, const record_t& record) ->
    builder<Document>
{
    return builder<Document>{root, record, *this};
}

json_t::json_t() :
    factory(new factory_t)
{}

json_t::json_t(routing_t routing) :
    factory(new factory_t(std::move(routing)))
{}

json_t::~json_t() {}

auto json_t::format(const record_t& record, writer_t& writer) -> void {
    typedef rapidjson::GenericDocument<
        rapidjson::UTF8<>,
        rapidjson::MemoryPoolAllocator<>,
        rapidjson::MemoryPoolAllocator<>
    > document_type;

    std::array<char, 4096> value_buffer;
    std::array<char, 1024> parse_buffer;
    rapidjson::MemoryPoolAllocator<> value_allocator(value_buffer.data(), value_buffer.size());
    rapidjson::MemoryPoolAllocator<> parse_allocator(parse_buffer.data(), parse_buffer.size());

    document_type root(&value_allocator, parse_buffer.size(), &parse_allocator);
    root.SetObject();

    // TODO: Try to use `AutoUTF<>` or `AutoUTFOutputStream` for UTF-8 validation.

    auto builder = factory->create(root, record);
    builder.message();
    builder.severity();
    builder.timestamp();
    builder.attributes();

    builder.build(writer);

    // TODO: Add newline if required. Obtained through config.
    // if (config.newline) {
    //     writer << '\n';
    // }
}

}  // namespace formatter
}  // namespace blackhole
<|endoftext|>


<commit_before>#include <map>

#include "assert.hpp"

#include "TimingGraph.hpp"

NodeId TimingGraph::add_node(const TimingNode& new_node) {
    //Type
    TN_Type new_node_type = new_node.type();
    node_types_.push_back(new_node.type());

    //Domain
    node_clock_domains_.push_back(new_node.clock_domain());

    //Logical block
    node_logical_blocks_.push_back(new_node.logical_block());

    //Clock source
    node_is_clock_source_.push_back(new_node.is_clock_source());

    //Save primary outputs as we build the graph
    if(new_node_type == TN_Type::OUTPAD_SINK ||
       new_node_type == TN_Type::FF_SINK) {
        primary_outputs_.push_back(node_types_.size() - 1);
    }

    //Out edges
    std::vector<EdgeId> out_edges = std::vector<EdgeId>();
    out_edges.reserve(new_node.num_out_edges());
    for(int i = 0; i < new_node.num_out_edges(); i++) {
        EdgeId edge_id = new_node.out_edge_id(i);
        out_edges.emplace_back(edge_id);
    }
    node_out_edges_.push_back(std::move(out_edges));

    //In edges
    //  these get filled in later, after all nodes have been added
    std::vector<EdgeId> in_edges = std::vector<EdgeId>();
    node_in_edges_.push_back(std::move(in_edges));

    //Verify sizes
    ASSERT(node_types_.size() == node_clock_domains_.size());
    ASSERT(node_types_.size() == node_out_edges_.size());
    ASSERT(node_types_.size() == node_in_edges_.size());

    //Return the ID of the added node
    return node_types_.size() - 1;
}

EdgeId TimingGraph::add_edge(const TimingEdge& new_edge) {
    edge_sink_nodes_.push_back(new_edge.to_node_id());
    edge_src_nodes_.push_back(new_edge.from_node_id());
    edge_delays_.push_back(new_edge.delay());

    ASSERT(edge_sink_nodes_.size() == edge_src_nodes_.size());
    ASSERT(edge_sink_nodes_.size() == edge_delays_.size());

    //Return the edge id of the added edge
    return edge_delays_.size() - 1;
}

void TimingGraph::fill_back_edges() {
    //Add reverse/back links for all edges in the timing graph
    for(int i = 0; i < num_nodes(); i++) {
        for(EdgeId edge_id : node_out_edges_[i]) {
            NodeId sink_node = edge_sink_node(edge_id);

            //edge_id drives the sink so it is an in edge
            node_in_edges_[sink_node].push_back(edge_id);
        }
    }
}

void TimingGraph::add_launch_capture_edges() {
    //We represent the dependancies between the clock and data paths
    //As edges in the graph from FF_CLOCK pins to FF_SOURCES (launch path)
    //and FF_SINKS (capture path)
    //
    //We use the information about the logical blocks associated with each
    //timing node to infer these edges.  That is, we look for FF_SINKs and FF_SOURCEs
    //that share the same logical block as an FF_CLOCK.
    //
    //TODO: Currently this just works for VPR's timing graph where only one FF_CLOCK exists
    //      per basic logic block.  This will need to be generalized.

    //Build a map from logical block id to the tnodes we care about
    std::map<BlockId,std::vector<NodeId>> logical_block_FF_clocks;
    std::map<BlockId,std::vector<NodeId>> logical_block_FF_sources;
    std::map<BlockId,std::vector<NodeId>> logical_block_FF_sinks;

    for(NodeId node_id = 0; node_id < num_nodes(); node_id++) {
        if(node_type(node_id) == TN_Type::FF_CLOCK) {
            logical_block_FF_clocks[node_logical_block(node_id)].push_back(node_id);
        } else if (node_type(node_id) == TN_Type::FF_SOURCE) {
            logical_block_FF_sources[node_logical_block(node_id)].push_back(node_id);
        } else if (node_type(node_id) == TN_Type::FF_SINK) {
            logical_block_FF_sinks[node_logical_block(node_id)].push_back(node_id);
        }
    }

    //Loop through each FF_CLOCK and add edges to FF_SINKs and FF_SOURCEs
    for(const auto clock_kv : logical_block_FF_clocks) {
        BlockId logical_block_id = clock_kv.first;
        VERIFY(clock_kv.second.size() == 1);
        NodeId ff_clock_node_id = clock_kv.second[0];

        //Check for FF_SOURCEs associated with this FF_CLOCK pin
        auto src_iter = logical_block_FF_sources.find(logical_block_id);
        if(src_iter != logical_block_FF_sources.end()) {
            //Go through each assoicated source and add an edge to it
            for(NodeId ff_src_node_id : src_iter->second) {
                //TODO: remove TimingEdge class
                EdgeId edge_id = add_edge(TimingEdge(Time(0.), ff_clock_node_id, ff_src_node_id));
                node_out_edges_[ff_clock_node_id].push_back(edge_id);
            }
        }

        //Check for FF_SINKs associated with this FF_CLOCK pin
        auto sink_iter = logical_block_FF_sinks.find(logical_block_id);
        if(sink_iter != logical_block_FF_sinks.end()) {
            //Go through each assoicated sink and add an edge to it
            for(NodeId ff_sink_node_id : sink_iter->second) {
                //TODO: remove TimingEdge class
                EdgeId edge_id = add_edge(TimingEdge(Time(0.), ff_clock_node_id, ff_sink_node_id));
                node_out_edges_[ff_clock_node_id].push_back(edge_id);
            }
        }
    }
}

void TimingGraph::levelize() {
    //Levelizes the timing graph
    //This over-writes any previous levelization if it exists

    //Clear the previous levelization
    node_levels_.clear();
    primary_outputs_.clear();

    //Allocate space for the first level
    node_levels_.resize(1);

    //Copy the number of input edges per-node
    //These will be decremented to know when a node is done
    //
    //Also initialize the first level (nodes with no fanin)
    std::vector<int> node_fanin_remaining(num_nodes());
    for(NodeId node_id = 0; node_id < num_nodes(); node_id++) {
        int node_fanin = num_node_in_edges(node_id);
        node_fanin_remaining[node_id] = node_fanin;

        if(node_fanin == 0) {
            //Add a primary input
            node_levels_[0].push_back(node_id);
        }
    }

    //Walk the graph from primary inputs (no fanin) to generate a topological sort
    //
    //We inspect the output edges of each node and decrement the fanin count of the
    //target node.  Once the fanin count for a node reaches zero it can be added
    //to the level.
    int level_id = 0;
    bool inserted_node_in_level = true;
    while(inserted_node_in_level) { //If nothing was inserted we are finished
        inserted_node_in_level = false;

        for(const NodeId node_id : node_levels_[level_id]) {
            //Inspect the fanout
            for(int edge_idx = 0; edge_idx < num_node_out_edges(node_id); edge_idx++) {
                EdgeId edge_id = node_out_edge(node_id, edge_idx);
                NodeId sink_node = edge_sink_node(edge_id);

                //Decrement the fanin count
                ASSERT(node_fanin_remaining[sink_node] > 0);
                node_fanin_remaining[sink_node]--;

                //Add to the next level if all fanin has been seen
                if(node_fanin_remaining[sink_node] == 0) {
                    //Ensure there is space by allocating the next level if required
                    node_levels_.resize(level_id+2);

                    //Add the node
                    node_levels_[level_id+1].push_back(sink_node);

                    inserted_node_in_level = true;
                }
            }

            //Also track the primary outputs
            if(num_node_out_edges(node_id) == 0) {
                primary_outputs_.push_back(node_id);
            }
        }
        level_id++;
    }
}

void TimingGraph::contiguize_level_edges() {
    //Make all edges in a level be contiguous in memory
    std::cout << "Re-allocating edges so levels are in contiguous memory" << std::endl;

    //Collect levels for edges
    std::vector<std::vector<EdgeId>> edge_levels;
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        edge_levels.push_back(std::vector<EdgeId>());
        for(auto node_id : node_levels_[level_idx]) {
            for(int i = 0; i < num_node_out_edges(node_id); i++) {
                EdgeId edge_id = node_out_edge(node_id, i);

                edge_levels[level_idx].push_back(edge_id);
            }
        }
    }

    //Save a map from old edge_id to new edge_id, will be used to update node refs
    std::map<EdgeId,EdgeId> old_edge_to_new_edge;
    int cnt = 0;
    for(std::vector<EdgeId>& edge_level : edge_levels) {
        for(EdgeId orig_edge_id : edge_level) {
            old_edge_to_new_edge[orig_edge_id] = cnt;
            cnt++;
        }
    }

    /*
     * Re-allocate edges to be contiguous in memory
     */

    //Save the old values while we write the new ones
    std::vector<NodeId> old_edge_sink_nodes_;
    std::vector<NodeId> old_edge_src_nodes_;
#ifdef TIME_MEM_ALIGN
    std::vector<Time, aligned_allocator<Time, TIME_MEM_ALIGN>> old_edge_delays_;
#else
    std::vector<Time> old_edge_delays_;
#endif

    //Swap them
    std::swap(old_edge_sink_nodes_, edge_sink_nodes_);
    std::swap(old_edge_src_nodes_, edge_src_nodes_);
    std::swap(old_edge_delays_, edge_delays_);

    //Update values
    for(auto& edge_level : edge_levels) {
        for(auto& orig_edge_id : edge_level) {
            //Write edges in the new contiguous order
            edge_sink_nodes_.push_back(old_edge_sink_nodes_[orig_edge_id]);
            edge_src_nodes_.push_back(old_edge_src_nodes_[orig_edge_id]);
            edge_delays_.push_back(old_edge_delays_[orig_edge_id]);
        }
    }

    /*
     * Update edge refs in nodes
     */
    for(int i = 0; i < num_nodes(); i++) {
        for(size_t j = 0; j < node_out_edges_[i].size(); j++) {
            EdgeId old_edge_id = node_out_edges_[i][j];
            node_out_edges_[i][j] = old_edge_to_new_edge[old_edge_id];
        }
        for(size_t j = 0; j < node_in_edges_[i].size(); j++) {
            EdgeId old_edge_id = node_in_edges_[i][j];
            node_in_edges_[i][j] = old_edge_to_new_edge[old_edge_id];
        }
    }
}

std::map<NodeId,NodeId> TimingGraph::contiguize_level_nodes() {
    //Make all nodes in a level be contiguous in memory
    std::cout << "Re-allocating nodes so levels are in contiguous memory" << std::endl;

    /*
     * Build a map of the old and new node ids to update edges
     * and node levels later
     */
    std::map<NodeId,NodeId> old_node_to_new_node;
    int cnt = 0;
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        for(NodeId node_id : node_levels_[level_idx]) {
            old_node_to_new_node[node_id] = cnt;
            cnt++;
        }
    }

    /*
     * Re-allocate nodes so levels are in contiguous memory
     */
    std::vector<TN_Type> old_node_types;
    std::vector<DomainId> old_node_clock_domains;
    std::vector<std::vector<EdgeId>> old_node_out_edges;
    std::vector<std::vector<EdgeId>> old_node_in_edges;

    //Swap the values
    std::swap(old_node_types, node_types_);
    std::swap(old_node_clock_domains, node_clock_domains_);
    std::swap(old_node_out_edges, node_out_edges_);
    std::swap(old_node_in_edges, node_in_edges_);

    //Update the values
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        for(NodeId old_node_id : node_levels_[level_idx]) {
            node_types_.push_back(old_node_types[old_node_id]);
            node_clock_domains_.push_back(old_node_clock_domains[old_node_id]);
            node_out_edges_.push_back(old_node_out_edges[old_node_id]);
            node_in_edges_.push_back(old_node_in_edges[old_node_id]);
        }
    }

    /*
     * Update old references to node_ids with thier new values
     */
    //The node levels
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        for(size_t i = 0; i < node_levels_[level_idx].size(); i++) {
            NodeId old_node_id = node_levels_[level_idx][i];
            node_levels_[level_idx][i] = old_node_to_new_node[old_node_id];
        }
    }

    //The primary outputs
    for(size_t i = 0; i < primary_outputs_.size(); i++) {
        NodeId old_node_id = primary_outputs_[i];
        primary_outputs_[i] = old_node_to_new_node[old_node_id];
    }

    //The Edges
    for(int i = 0; i < num_edges(); i++) {
        NodeId old_sink_node = edge_sink_nodes_[i];
        NodeId old_src_node = edge_src_nodes_[i];

        edge_sink_nodes_[i] = old_node_to_new_node[old_sink_node];
        edge_src_nodes_[i] = old_node_to_new_node[old_src_node];
    }

    return old_node_to_new_node;
}
<commit_msg>Whitespace cleanup<commit_after>#include <map>

#include "assert.hpp"

#include "TimingGraph.hpp"

NodeId TimingGraph::add_node(const TimingNode& new_node) {
    //Type
    TN_Type new_node_type = new_node.type();
    node_types_.push_back(new_node.type());

    //Domain
    node_clock_domains_.push_back(new_node.clock_domain());

    //Logical block
    node_logical_blocks_.push_back(new_node.logical_block());

    //Clock source
    node_is_clock_source_.push_back(new_node.is_clock_source());

    //Save primary outputs as we build the graph
    if(new_node_type == TN_Type::OUTPAD_SINK ||
       new_node_type == TN_Type::FF_SINK) {
        primary_outputs_.push_back(node_types_.size() - 1);
    }

    //Out edges
    std::vector<EdgeId> out_edges = std::vector<EdgeId>();
    out_edges.reserve(new_node.num_out_edges());
    for(int i = 0; i < new_node.num_out_edges(); i++) {
        EdgeId edge_id = new_node.out_edge_id(i);
        out_edges.emplace_back(edge_id);
    }
    node_out_edges_.push_back(std::move(out_edges));

    //In edges
    //  these get filled in later, after all nodes have been added
    std::vector<EdgeId> in_edges = std::vector<EdgeId>();
    node_in_edges_.push_back(std::move(in_edges));

    //Verify sizes
    ASSERT(node_types_.size() == node_clock_domains_.size());
    ASSERT(node_types_.size() == node_out_edges_.size());
    ASSERT(node_types_.size() == node_in_edges_.size());

    //Return the ID of the added node
    return node_types_.size() - 1;
}

EdgeId TimingGraph::add_edge(const TimingEdge& new_edge) {
    edge_sink_nodes_.push_back(new_edge.to_node_id());
    edge_src_nodes_.push_back(new_edge.from_node_id());
    edge_delays_.push_back(new_edge.delay());

    ASSERT(edge_sink_nodes_.size() == edge_src_nodes_.size());
    ASSERT(edge_sink_nodes_.size() == edge_delays_.size());

    //Return the edge id of the added edge
    return edge_delays_.size() - 1;
}

void TimingGraph::fill_back_edges() {
    //Add reverse/back links for all edges in the timing graph
    for(int i = 0; i < num_nodes(); i++) {
        for(EdgeId edge_id : node_out_edges_[i]) {
            NodeId sink_node = edge_sink_node(edge_id);

            //edge_id drives the sink so it is an in edge
            node_in_edges_[sink_node].push_back(edge_id);
        }
    }
}

void TimingGraph::add_launch_capture_edges() {
    //We represent the dependancies between the clock and data paths
    //As edges in the graph from FF_CLOCK pins to FF_SOURCES (launch path)
    //and FF_SINKS (capture path)
    //
    //We use the information about the logical blocks associated with each
    //timing node to infer these edges.  That is, we look for FF_SINKs and FF_SOURCEs
    //that share the same logical block as an FF_CLOCK.
    //
    //TODO: Currently this just works for VPR's timing graph where only one FF_CLOCK exists
    //      per basic logic block.  This will need to be generalized.

    //Build a map from logical block id to the tnodes we care about
    std::map<BlockId,std::vector<NodeId>> logical_block_FF_clocks;
    std::map<BlockId,std::vector<NodeId>> logical_block_FF_sources;
    std::map<BlockId,std::vector<NodeId>> logical_block_FF_sinks;

    for(NodeId node_id = 0; node_id < num_nodes(); node_id++) {
        if(node_type(node_id) == TN_Type::FF_CLOCK) {
            logical_block_FF_clocks[node_logical_block(node_id)].push_back(node_id);
        } else if (node_type(node_id) == TN_Type::FF_SOURCE) {
            logical_block_FF_sources[node_logical_block(node_id)].push_back(node_id);
        } else if (node_type(node_id) == TN_Type::FF_SINK) {
            logical_block_FF_sinks[node_logical_block(node_id)].push_back(node_id);
        }
    }

    //Loop through each FF_CLOCK and add edges to FF_SINKs and FF_SOURCEs
    for(const auto clock_kv : logical_block_FF_clocks) {
        BlockId logical_block_id = clock_kv.first;
        VERIFY(clock_kv.second.size() == 1);
        NodeId ff_clock_node_id = clock_kv.second[0];

        //Check for FF_SOURCEs associated with this FF_CLOCK pin
        auto src_iter = logical_block_FF_sources.find(logical_block_id);
        if(src_iter != logical_block_FF_sources.end()) {
            //Go through each assoicated source and add an edge to it
            for(NodeId ff_src_node_id : src_iter->second) {
                //TODO: remove TimingEdge class
                EdgeId edge_id = add_edge(TimingEdge(Time(0.), ff_clock_node_id, ff_src_node_id));
                node_out_edges_[ff_clock_node_id].push_back(edge_id);
            }
        }

        //Check for FF_SINKs associated with this FF_CLOCK pin
        auto sink_iter = logical_block_FF_sinks.find(logical_block_id);
        if(sink_iter != logical_block_FF_sinks.end()) {
            //Go through each assoicated sink and add an edge to it
            for(NodeId ff_sink_node_id : sink_iter->second) {
                //TODO: remove TimingEdge class
                EdgeId edge_id = add_edge(TimingEdge(Time(0.), ff_clock_node_id, ff_sink_node_id));
                node_out_edges_[ff_clock_node_id].push_back(edge_id);
            }
        }
    }
}

void TimingGraph::levelize() {
    //Levelizes the timing graph
    //This over-writes any previous levelization if it exists

    //Clear the previous levelization
    node_levels_.clear();
    primary_outputs_.clear();

    //Allocate space for the first level
    node_levels_.resize(1);

    //Copy the number of input edges per-node
    //These will be decremented to know when a node is done
    //
    //Also initialize the first level (nodes with no fanin)
    std::vector<int> node_fanin_remaining(num_nodes());
    for(NodeId node_id = 0; node_id < num_nodes(); node_id++) {
        int node_fanin = num_node_in_edges(node_id);
        node_fanin_remaining[node_id] = node_fanin;

        if(node_fanin == 0) {
            //Add a primary input
            node_levels_[0].push_back(node_id);
        }
    }

    //Walk the graph from primary inputs (no fanin) to generate a topological sort
    //
    //We inspect the output edges of each node and decrement the fanin count of the
    //target node.  Once the fanin count for a node reaches zero it can be added
    //to the level.
    int level_id = 0;
    bool inserted_node_in_level = true;
    while(inserted_node_in_level) { //If nothing was inserted we are finished
        inserted_node_in_level = false;

        for(const NodeId node_id : node_levels_[level_id]) {
            //Inspect the fanout
            for(int edge_idx = 0; edge_idx < num_node_out_edges(node_id); edge_idx++) {
                EdgeId edge_id = node_out_edge(node_id, edge_idx);
                NodeId sink_node = edge_sink_node(edge_id);

                //Decrement the fanin count
                ASSERT(node_fanin_remaining[sink_node] > 0);
                node_fanin_remaining[sink_node]--;

                //Add to the next level if all fanin has been seen
                if(node_fanin_remaining[sink_node] == 0) {
                    //Ensure there is space by allocating the next level if required
                    node_levels_.resize(level_id+2);

                    //Add the node
                    node_levels_[level_id+1].push_back(sink_node);

                    inserted_node_in_level = true;
                }
            }

            //Also track the primary outputs
            if(num_node_out_edges(node_id) == 0) {
                primary_outputs_.push_back(node_id);
            }
        }
        level_id++;
    }
}

void TimingGraph::contiguize_level_edges() {
    //Make all edges in a level be contiguous in memory
    std::cout << "Re-allocating edges so levels are in contiguous memory" << std::endl;

    //Collect levels for edges
    std::vector<std::vector<EdgeId>> edge_levels;
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        edge_levels.push_back(std::vector<EdgeId>());
        for(auto node_id : node_levels_[level_idx]) {
            for(int i = 0; i < num_node_out_edges(node_id); i++) {
                EdgeId edge_id = node_out_edge(node_id, i);

                edge_levels[level_idx].push_back(edge_id);
            }
        }
    }

    //Save a map from old edge_id to new edge_id, will be used to update node refs
    std::map<EdgeId,EdgeId> old_edge_to_new_edge;
    int cnt = 0;
    for(std::vector<EdgeId>& edge_level : edge_levels) {
        for(EdgeId orig_edge_id : edge_level) {
            old_edge_to_new_edge[orig_edge_id] = cnt;
            cnt++;
        }
    }

    /*
     * Re-allocate edges to be contiguous in memory
     */

    //Save the old values while we write the new ones
    std::vector<NodeId> old_edge_sink_nodes_;
    std::vector<NodeId> old_edge_src_nodes_;
#ifdef TIME_MEM_ALIGN
    std::vector<Time, aligned_allocator<Time, TIME_MEM_ALIGN>> old_edge_delays_;
#else
    std::vector<Time> old_edge_delays_;
#endif

    //Swap them
    std::swap(old_edge_sink_nodes_, edge_sink_nodes_);
    std::swap(old_edge_src_nodes_, edge_src_nodes_);
    std::swap(old_edge_delays_, edge_delays_);

    //Update values
    for(auto& edge_level : edge_levels) {
        for(auto& orig_edge_id : edge_level) {
            //Write edges in the new contiguous order
            edge_sink_nodes_.push_back(old_edge_sink_nodes_[orig_edge_id]);
            edge_src_nodes_.push_back(old_edge_src_nodes_[orig_edge_id]);
            edge_delays_.push_back(old_edge_delays_[orig_edge_id]);
        }
    }

    /*
     * Update edge refs in nodes
     */
    for(int i = 0; i < num_nodes(); i++) {
        for(size_t j = 0; j < node_out_edges_[i].size(); j++) {
            EdgeId old_edge_id = node_out_edges_[i][j];
            node_out_edges_[i][j] = old_edge_to_new_edge[old_edge_id];
        }
        for(size_t j = 0; j < node_in_edges_[i].size(); j++) {
            EdgeId old_edge_id = node_in_edges_[i][j];
            node_in_edges_[i][j] = old_edge_to_new_edge[old_edge_id];
        }
    }
}

std::map<NodeId,NodeId> TimingGraph::contiguize_level_nodes() {
    //Make all nodes in a level be contiguous in memory
    std::cout << "Re-allocating nodes so levels are in contiguous memory" << std::endl;

    /*
     * Build a map of the old and new node ids to update edges
     * and node levels later
     */
    std::map<NodeId,NodeId> old_node_to_new_node;
    int cnt = 0;
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        for(NodeId node_id : node_levels_[level_idx]) {
            old_node_to_new_node[node_id] = cnt;
            cnt++;
        }
    }

    /*
     * Re-allocate nodes so levels are in contiguous memory
     */
    std::vector<TN_Type> old_node_types;
    std::vector<DomainId> old_node_clock_domains;
    std::vector<std::vector<EdgeId>> old_node_out_edges;
    std::vector<std::vector<EdgeId>> old_node_in_edges;

    //Swap the values
    std::swap(old_node_types, node_types_);
    std::swap(old_node_clock_domains, node_clock_domains_);
    std::swap(old_node_out_edges, node_out_edges_);
    std::swap(old_node_in_edges, node_in_edges_);

    //Update the values
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        for(NodeId old_node_id : node_levels_[level_idx]) {
            node_types_.push_back(old_node_types[old_node_id]);
            node_clock_domains_.push_back(old_node_clock_domains[old_node_id]);
            node_out_edges_.push_back(old_node_out_edges[old_node_id]);
            node_in_edges_.push_back(old_node_in_edges[old_node_id]);
        }
    }

    /*
     * Update old references to node_ids with thier new values
     */
    //The node levels
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        for(size_t i = 0; i < node_levels_[level_idx].size(); i++) {
            NodeId old_node_id = node_levels_[level_idx][i];
            node_levels_[level_idx][i] = old_node_to_new_node[old_node_id];
        }
    }

    //The primary outputs
    for(size_t i = 0; i < primary_outputs_.size(); i++) {
        NodeId old_node_id = primary_outputs_[i];
        primary_outputs_[i] = old_node_to_new_node[old_node_id];
    }

    //The Edges
    for(int i = 0; i < num_edges(); i++) {
        NodeId old_sink_node = edge_sink_nodes_[i];
        NodeId old_src_node = edge_src_nodes_[i];

        edge_sink_nodes_[i] = old_node_to_new_node[old_sink_node];
        edge_src_nodes_[i] = old_node_to_new_node[old_src_node];
    }

    return old_node_to_new_node;
}
<|endoftext|>


<commit_before><commit_msg><= for extra safely I suppose<commit_after><|endoftext|>


<commit_before>#include <iostream>
#include <armadillo>

using namespace std;
using namespace arma;

// EstructruraCapaRed especifica la cantidad de neuronas en cada capa.
// Por ejemplo, si la red tiene 2 neuronas en la primera capa,
// 3 en la capa oculta y 1 en la capa de salida,
// EstructuraCapasRed para esa red será [2 3 1].
using EstructuraCapasRed = vec;

pair<vector<mat>, double> entrenarMulticapa(const EstructuraCapasRed& estructura,
                                            const mat& datos,
                                            int nEpocas,
                                            double tasaAprendizaje,
                                            double toleranciaError);
double errorPrueba(const vec& pesos,
                   const mat& patrones,
                   const vec& salidaDeseada);

int main()
{
    arma_rng::set_seed_random();
    mat datos;
    datos.load("XOR_trn.csv");

    return 0;
}

namespace ic {
vec sigmoid(const vec& v, double b)
{
    vec result(v.n_elem);

    for (unsigned int i = 0; i < v.n_elem; ++i)
        result(i) = 2 / (1 + exp(-b * v(i))) - 1;

    return result;
}
}

pair<vec, double> epocaMulticapa(const mat& patronesExt,
                                 const mat& salidaDeseada,
                                 double tasaAprendizaje,
                                 const vector<mat>& pesos)
{
    //Entrenamiento
    vector<mat> nuevosPesos = pesos;
    const int nCapas = nuevosPesos.size();

    for (unsigned int n = 0; n < patronesExt.n_rows; ++n) {
        // Calcular las salidas para cada capa
        // También vamos a meter la entrada a la red en la estructura de salidas.
        // Esto es necesario para el cálculo de ajuste de pesos.
        vector<vec> ySalidas;
        ySalidas.push_back(patronesExt.row(n));

        for (int i = 1; i <= nCapas; ++i) {
            vec v = pesos[i - 1] * ySalidas[i - 1]; // FIXME: Esto va a explotar luego de la
                                                    // primer capa, porque no le estamos metiendo el sesgo
            ySalidas[i] = ic::sigmoid(v, 1);        // TODO: ver qué valor le pasamos como parámetro
                                                    // a la sigmoidea
        }
    }

    // Validacion
    int errores = 0;

    for (unsigned int i = 0; i < patronesExt.n_rows; ++i) {
        double z = dot(patronesExt.row(i), pesos);
        //        int y = ic::sign(z);

        //        if (y != salidaDeseada(i))
        //            ++errores;
    }

    double tasaError = static_cast<double>(errores) / patronesExt.n_rows * 100;

    return {nuevosPesos, tasaError};
} // fin funcion Epoca

double errorPrueba(const vec& pesos,
                   const mat& patrones,
                   const vec& salidaDeseada)
{
    // Se extiende la matriz de patrones con la entrada correspondiente al umbral
    const mat patronesExt = join_horiz(ones(patrones.n_rows) * (-1), patrones);

    int errores = 0;

    for (unsigned int i = 0; i < patronesExt.n_rows; ++i) {
        double z = dot(patronesExt.row(i), pesos);
        //        int y = ic::sign(z);

        //        if (y != salidaDeseada(i))
        //            ++errores;
    }

    double tasaError = static_cast<double>(errores) / patronesExt.n_rows * 100;

    return tasaError;
}

pair<vector<mat>, double> entrenarMulticapa(const EstructuraCapasRed& estructura,
                                            const mat& datos,
                                            int nEpocas,
                                            double tasaAprendizaje,
                                            double toleranciaError)
{
    const int nSalidas = estructura(estructura.n_elem - 1);
    const int nEntradas = datos.n_cols - nSalidas;
    const int nCapas = estructura.n_elem;
    // Vamos a tener tantas columnas en salidaDeseada
    // como neuronas en la capa de salida
    const mat salidaDeseada = datos.tail_cols(nSalidas);
    // Extender la matriz de patrones con la entrada correspondiente al umbral
    const mat patronesExt = join_horiz(ones(datos.n_rows) * (-1), datos.head_cols(nEntradas));

    // Inicializar pesos y tasa de error
    vector<mat> pesos;

    // La primer matriz matriz de pesos tiene tantas filas como neuronas en la primer capa
    // y tantas columnas como entradas.
    pesos.push_back(randu<mat>(estructura(0), nEntradas));
    for (int i = 1; i < nCapas; ++i) {
        // Las siguientes matrices de pesos tienen tantas filas como neuronas en dicha capa
        // y tantas columnas como entradas a esa capa, que van a ser las salidas de
        // la capa anterior.
        // Las salidas de la capa anterior es igual al nro de neuronas en la capa anterior.
        pesos.push_back(randu<mat>(estructura(i), estructura(i - 1)));
    }

    double tasaError = 0;

    // Ciclo de las epocas
    for (int epoca = 1; epoca <= nEpocas; ++epoca) {
        // Ciclo para una época
        tie(pesos, tasaError) = epocaMulticapa(patronesExt,
                                               salidaDeseada,
                                               tasaAprendizaje,
                                               pesos);

        if (tasaError < toleranciaError)
            break;
    }
    // Fin ciclo (epocas)

    return {pesos, tasaError};
}
<commit_msg>Guia 1 - xor_multicapa: Cambiar ic::sigmoid para que haga el cálculo sobre todo el vector a la vez<commit_after>#include <iostream>
#include <armadillo>

using namespace std;
using namespace arma;

// EstructruraCapaRed especifica la cantidad de neuronas en cada capa.
// Por ejemplo, si la red tiene 2 neuronas en la primera capa,
// 3 en la capa oculta y 1 en la capa de salida,
// EstructuraCapasRed para esa red será [2 3 1].
using EstructuraCapasRed = vec;

pair<vector<mat>, double> entrenarMulticapa(const EstructuraCapasRed& estructura,
                                            const mat& datos,
                                            int nEpocas,
                                            double tasaAprendizaje,
                                            double toleranciaError);
double errorPrueba(const vec& pesos,
                   const mat& patrones,
                   const vec& salidaDeseada);

int main()
{
    arma_rng::set_seed_random();
    mat datos;
    datos.load("XOR_trn.csv");

    return 0;
}

namespace ic {
vec sigmoid(const vec& v, double b)
{
    return 2 / (1 + exp(-b * v)) - 1;
}
}

pair<vec, double> epocaMulticapa(const mat& patronesExt,
                                 const mat& salidaDeseada,
                                 double tasaAprendizaje,
                                 const vector<mat>& pesos)
{
    //Entrenamiento
    vector<mat> nuevosPesos = pesos;
    const int nCapas = nuevosPesos.size();

    for (unsigned int n = 0; n < patronesExt.n_rows; ++n) {
        // Calcular las salidas para cada capa
        // También vamos a meter la entrada a la red en la estructura de salidas.
        // Esto es necesario para el cálculo de ajuste de pesos.
        vector<vec> ySalidas;
        ySalidas.push_back(patronesExt.row(n));

        for (int i = 1; i <= nCapas; ++i) {
            vec v = pesos[i - 1] * ySalidas[i - 1]; // FIXME: Esto va a explotar luego de la
                                                    // primer capa, porque no le estamos metiendo el sesgo
            ySalidas[i] = ic::sigmoid(v, 1);        // TODO: ver qué valor le pasamos como parámetro
                                                    // a la sigmoidea
        }
    }

    // Validacion
    int errores = 0;

    for (unsigned int i = 0; i < patronesExt.n_rows; ++i) {
        double z = dot(patronesExt.row(i), pesos);
        //        int y = ic::sign(z);

        //        if (y != salidaDeseada(i))
        //            ++errores;
    }

    double tasaError = static_cast<double>(errores) / patronesExt.n_rows * 100;

    return {nuevosPesos, tasaError};
} // fin funcion Epoca

double errorPrueba(const vec& pesos,
                   const mat& patrones,
                   const vec& salidaDeseada)
{
    // Se extiende la matriz de patrones con la entrada correspondiente al umbral
    const mat patronesExt = join_horiz(ones(patrones.n_rows) * (-1), patrones);

    int errores = 0;

    for (unsigned int i = 0; i < patronesExt.n_rows; ++i) {
        double z = dot(patronesExt.row(i), pesos);
        //        int y = ic::sign(z);

        //        if (y != salidaDeseada(i))
        //            ++errores;
    }

    double tasaError = static_cast<double>(errores) / patronesExt.n_rows * 100;

    return tasaError;
}

pair<vector<mat>, double> entrenarMulticapa(const EstructuraCapasRed& estructura,
                                            const mat& datos,
                                            int nEpocas,
                                            double tasaAprendizaje,
                                            double toleranciaError)
{
    const int nSalidas = estructura(estructura.n_elem - 1);
    const int nEntradas = datos.n_cols - nSalidas;
    const int nCapas = estructura.n_elem;
    // Vamos a tener tantas columnas en salidaDeseada
    // como neuronas en la capa de salida
    const mat salidaDeseada = datos.tail_cols(nSalidas);
    // Extender la matriz de patrones con la entrada correspondiente al umbral
    const mat patronesExt = join_horiz(ones(datos.n_rows) * (-1), datos.head_cols(nEntradas));

    // Inicializar pesos y tasa de error
    vector<mat> pesos;

    // La primer matriz matriz de pesos tiene tantas filas como neuronas en la primer capa
    // y tantas columnas como entradas.
    pesos.push_back(randu<mat>(estructura(0), nEntradas));
    for (int i = 1; i < nCapas; ++i) {
        // Las siguientes matrices de pesos tienen tantas filas como neuronas en dicha capa
        // y tantas columnas como entradas a esa capa, que van a ser las salidas de
        // la capa anterior.
        // Las salidas de la capa anterior es igual al nro de neuronas en la capa anterior.
        pesos.push_back(randu<mat>(estructura(i), estructura(i - 1)));
    }

    double tasaError = 0;

    // Ciclo de las epocas
    for (int epoca = 1; epoca <= nEpocas; ++epoca) {
        // Ciclo para una época
        tie(pesos, tasaError) = epocaMulticapa(patronesExt,
                                               salidaDeseada,
                                               tasaAprendizaje,
                                               pesos);

        if (tasaError < toleranciaError)
            break;
    }
    // Fin ciclo (epocas)

    return {pesos, tasaError};
}
<|endoftext|>


<commit_before>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2011,2012 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
#include "conf.hh"
#include "dparse.h"
#include "helper.hh"
#include "history.hh"
#include <cstring>

#ifndef DROI
#include <glib.h>
#else

#endif

extern "C" {
extern D_ParserTables parser_tables_conf;
}

extern Conf* conf_obj;

#define RETURN_ERROR_VOID(s) { \
  set_exitvalue(on_error); \
  log.pop();    \
  status=false; \
  errormsg=s;   \
  return; \
  }

#define RETURN_ERROR_VERDICT(s) { \
  set_exitvalue(on_error); \
  log.pop();    \
  status=false; \
  errormsg=s;   \
  return Verdict::ERROR; \
  }

void Conf::load(std::string& name,std::string& content)
{
  D_Parser *p = new_D_Parser(&parser_tables_conf, 512);
  p->loc.pathname = name.c_str();
  char *s;

  Conf* tmp=conf_obj;
  log.push("conf_load");
  log.debug("Conf::load %s",name.c_str());
  conf_obj=this;

  s=readfile(name.c_str());
  std::string ss(s);
  ss=ss+"\n"+content;
  if ((name!="" && s==NULL))
    RETURN_ERROR_VOID("Loading \"" + name + "\" failed.");

  if (ss=="")
    RETURN_ERROR_VOID("Empthy configuration");

  bool ret=dparse(p,(char*)ss.c_str(),std::strlen(ss.c_str()));

  ret=p->syntax_errors==0 && ret;

  if (!ret)
    RETURN_ERROR_VOID("Parsing \"" + name + "\" failed.");

  free(s);

  free_D_Parser(p);

  conf_obj=tmp;

  if ((heuristic=HeuristicFactory::create(log, heuristic_name, heuristic_param)) == NULL)
    RETURN_ERROR_VOID("Creating heuristic \"" + heuristic_name + "\" failed.");

  if (heuristic->status==false)
    RETURN_ERROR_VOID("Error in heuristic \"" + heuristic_name + "\":" +
		      heuristic->errormsg);

  if ((model=Model::create(log, model_name, model_param)) == NULL) {
    RETURN_ERROR_VOID("Creating model loader \"" +
		      filetype(model_name)
		      + "\" failed.");
  }

  Coverage* coverage = CoverageFactory::create(log,coverage_name,coverage_param);

  if (coverage == NULL)
    RETURN_ERROR_VOID("Creating coverage \"" + coverage_name + "\" failed.");

  if (!coverage->status)
    RETURN_ERROR_VOID("Coverage error on \"" + coverage_name + "\":" + coverage->errormsg);

  if (!model->status || !model->init() || !model->reset())
    RETURN_ERROR_VOID("Model error: " + model->stringify());

  heuristic->set_coverage(coverage);

  heuristic->set_model(model);

  coverage->set_model(model);

  adapter = AdapterFactory::create(log, adapter_name, adapter_param);

  if (adapter && !adapter->status) {
    status=false;
    errormsg=adapter->errormsg;
    return;
  }

  /* handle history */
  for(unsigned i=0;i<history.size();i++) {
    std::string name,param;
    split(*history[i],name,param);

    History* h=HistoryFactory::create(log, name, param);

    if (h) {
      h->set_coverage(coverage,model);
      if (!h->status) {
	RETURN_ERROR_VOID(h->errormsg);
      }
    } else {
      RETURN_ERROR_VOID("Creating history \""+ *history[i] + "\" failed");
    }
  }

  if (adapter == NULL)
    RETURN_ERROR_VOID("Creating adapter \"" + adapter_name + "\" failed.");

  adapter->set_actions(&model->getActionNames());

  if (!coverage->status)
    RETURN_ERROR_VOID("Coverage error: " + coverage->stringify());

  if (!adapter->status)
    RETURN_ERROR_VOID("Adapter error: " + adapter->stringify());

  log.pop();
}

#include <sstream>

std::string Conf::stringify() {
  std::ostringstream t(std::ios::out | std::ios::binary);

  if (!status) {
    return errormsg;
  }

  t << "model = \"" << removehash(model_name) << capsulate(model->stringify()) << std::endl;
  t << "heuristic = \"" << heuristic_name << "\"" << std::endl;
  t << "coverage = \"" <<  coverage_name << "\"" << std::endl;
  t << "adapter = \"" << removehash(adapter_name) << ":"
    << removehash(adapter_param)
    << capsulate(adapter->stringify()) << std::endl;

  /* TODO: stringify end conditions */

  return t.str();
}

Verdict::Verdict Conf::execute(bool interactive) {

  Policy policy;
  log.push("conf_execute");

  if (!status) {
    errormsg = "cannot start executing test due to earlier errors: " + errormsg;
    return Verdict::ERROR;
  }

  if (!adapter->init())
    RETURN_ERROR_VERDICT("Initialising adapter failed: " + adapter->stringify());

  // Validate and finish existing end_conditions
  {
    bool end_by_coverage = false;
    for (unsigned int i = 0; i < end_conditions.size(); i++) {
      End_condition* e = end_conditions[i];
      if (e->status == false)
        RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
      if (e->counter == End_condition::STATETAG) {
        // avoid string comparisons, fetch the index of the tag
        e->param_long = find(model->getSPNames(), *(e->param));
      }
      if (e->counter == End_condition::COVERAGE) {
        end_by_coverage = true;
      }
      if (e->counter == End_condition::DURATION) {
        end_time = e->param_time;
      }
    }
    // Add default end conditions (if coverage is reached, test is passed)
    if (!end_by_coverage) {
      end_conditions.push_back(
        new End_condition(Verdict::PASS, End_condition::COVERAGE, new std::string("1.0")));
    }
  }

  Test_engine engine(*heuristic,*adapter,log,policy,end_conditions);

  if (interactive) {
    engine.interactive();
  } else {
    Verdict::Verdict v = engine.run(end_time);

    switch (v) {
    case Verdict::FAIL: {
      set_exitvalue(on_fail);
      // Test failed. Continue according to the on_error
      // configuration. In addition to the following it could at
      // somepoint specify a shell command (for instance, package and
      // send log files, etc.)
      if (on_fail == "interactive")
        engine.interactive();
      break;
    }
    case Verdict::PASS: {
      // Test passed
      set_exitvalue(on_pass);
      break;
    }
    case Verdict::INCONCLUSIVE: {
      set_exitvalue(on_inconc);
      break;
    }
    case Verdict::ERROR: {
      RETURN_ERROR_VERDICT(engine.verdict_msg() + ": " + engine.reason_msg());
      break;
    }
    default: {
      // unknown verdict?
    }
    }
  }
  log.pop();
  status = true;
  errormsg = engine.verdict_msg() + ": " + engine.reason_msg();
  return engine.verdict();
}

void Conf::set_exitvalue(std::string& s)
{
  std::string cmd;
  std::string value;
  split(s,cmd,value);
  exit_status=atoi(value.c_str());
}

void Conf::set_observe_sleep(std::string &s)
{
  Adapter::sleeptime=atoi(s.c_str());
}
<commit_msg>Fix core-dumping on configuration file read error<commit_after>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2011,2012 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
#include "conf.hh"
#include "dparse.h"
#include "helper.hh"
#include "history.hh"
#include <cstring>

#ifndef DROI
#include <glib.h>
#else

#endif

extern "C" {
extern D_ParserTables parser_tables_conf;
}

extern Conf* conf_obj;

#define RETURN_ERROR_VOID(s) { \
  set_exitvalue(on_error); \
  log.pop();    \
  status=false; \
  errormsg=s;   \
  return; \
  }

#define RETURN_ERROR_VERDICT(s) { \
  set_exitvalue(on_error); \
  log.pop();    \
  status=false; \
  errormsg=s;   \
  return Verdict::ERROR; \
  }

void Conf::load(std::string& name,std::string& content)
{
  D_Parser *p = new_D_Parser(&parser_tables_conf, 512);
  p->loc.pathname = name.c_str();
  char *s;

  log.push("conf_load");
  log.debug("Conf::load %s",name.c_str());
  s=readfile(name.c_str());

  if (s==NULL) {
    status=false;
    errormsg=std::string("Can't read configuration file \"")+name+"\"";
    log.pop();
    return;
  }

  Conf* tmp=conf_obj;
  conf_obj=this;

  std::string ss(s);
  ss=ss+"\n"+content;
  if ((name!="" && s==NULL))
    RETURN_ERROR_VOID("Loading \"" + name + "\" failed.");

  if (ss=="")
    RETURN_ERROR_VOID("Empthy configuration");

  bool ret=dparse(p,(char*)ss.c_str(),std::strlen(ss.c_str()));

  ret=p->syntax_errors==0 && ret;

  if (!ret)
    RETURN_ERROR_VOID("Parsing \"" + name + "\" failed.");

  free(s);

  free_D_Parser(p);

  conf_obj=tmp;

  if ((heuristic=HeuristicFactory::create(log, heuristic_name, heuristic_param)) == NULL)
    RETURN_ERROR_VOID("Creating heuristic \"" + heuristic_name + "\" failed.");

  if (heuristic->status==false)
    RETURN_ERROR_VOID("Error in heuristic \"" + heuristic_name + "\":" +
		      heuristic->errormsg);

  if ((model=Model::create(log, model_name, model_param)) == NULL) {
    RETURN_ERROR_VOID("Creating model loader \"" +
		      filetype(model_name)
		      + "\" failed.");
  }

  Coverage* coverage = CoverageFactory::create(log,coverage_name,coverage_param);

  if (coverage == NULL)
    RETURN_ERROR_VOID("Creating coverage \"" + coverage_name + "\" failed.");

  if (!coverage->status)
    RETURN_ERROR_VOID("Coverage error on \"" + coverage_name + "\":" + coverage->errormsg);

  if (!model->status || !model->init() || !model->reset())
    RETURN_ERROR_VOID("Model error: " + model->stringify());

  heuristic->set_coverage(coverage);

  heuristic->set_model(model);

  coverage->set_model(model);

  adapter = AdapterFactory::create(log, adapter_name, adapter_param);

  if (adapter && !adapter->status) {
    status=false;
    errormsg=adapter->errormsg;
    return;
  }

  /* handle history */
  for(unsigned i=0;i<history.size();i++) {
    std::string name,param;
    split(*history[i],name,param);

    History* h=HistoryFactory::create(log, name, param);

    if (h) {
      h->set_coverage(coverage,model);
      if (!h->status) {
	RETURN_ERROR_VOID(h->errormsg);
      }
    } else {
      RETURN_ERROR_VOID("Creating history \""+ *history[i] + "\" failed");
    }
  }

  if (adapter == NULL)
    RETURN_ERROR_VOID("Creating adapter \"" + adapter_name + "\" failed.");

  adapter->set_actions(&model->getActionNames());

  if (!coverage->status)
    RETURN_ERROR_VOID("Coverage error: " + coverage->stringify());

  if (!adapter->status)
    RETURN_ERROR_VOID("Adapter error: " + adapter->stringify());

  log.pop();
}

#include <sstream>

std::string Conf::stringify() {
  std::ostringstream t(std::ios::out | std::ios::binary);

  if (!status) {
    return errormsg;
  }

  t << "model = \"" << removehash(model_name) << capsulate(model->stringify()) << std::endl;
  t << "heuristic = \"" << heuristic_name << "\"" << std::endl;
  t << "coverage = \"" <<  coverage_name << "\"" << std::endl;
  t << "adapter = \"" << removehash(adapter_name) << ":"
    << removehash(adapter_param)
    << capsulate(adapter->stringify()) << std::endl;

  /* TODO: stringify end conditions */

  return t.str();
}

Verdict::Verdict Conf::execute(bool interactive) {

  Policy policy;
  log.push("conf_execute");

  if (!status) {
    errormsg = "cannot start executing test due to earlier errors: " + errormsg;
    return Verdict::ERROR;
  }

  if (!adapter->init())
    RETURN_ERROR_VERDICT("Initialising adapter failed: " + adapter->stringify());

  // Validate and finish existing end_conditions
  {
    bool end_by_coverage = false;
    for (unsigned int i = 0; i < end_conditions.size(); i++) {
      End_condition* e = end_conditions[i];
      if (e->status == false)
        RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
      if (e->counter == End_condition::STATETAG) {
        // avoid string comparisons, fetch the index of the tag
        e->param_long = find(model->getSPNames(), *(e->param));
      }
      if (e->counter == End_condition::COVERAGE) {
        end_by_coverage = true;
      }
      if (e->counter == End_condition::DURATION) {
        end_time = e->param_time;
      }
    }
    // Add default end conditions (if coverage is reached, test is passed)
    if (!end_by_coverage) {
      end_conditions.push_back(
        new End_condition(Verdict::PASS, End_condition::COVERAGE, new std::string("1.0")));
    }
  }

  Test_engine engine(*heuristic,*adapter,log,policy,end_conditions);

  if (interactive) {
    engine.interactive();
  } else {
    Verdict::Verdict v = engine.run(end_time);

    switch (v) {
    case Verdict::FAIL: {
      set_exitvalue(on_fail);
      // Test failed. Continue according to the on_error
      // configuration. In addition to the following it could at
      // somepoint specify a shell command (for instance, package and
      // send log files, etc.)
      if (on_fail == "interactive")
        engine.interactive();
      break;
    }
    case Verdict::PASS: {
      // Test passed
      set_exitvalue(on_pass);
      break;
    }
    case Verdict::INCONCLUSIVE: {
      set_exitvalue(on_inconc);
      break;
    }
    case Verdict::ERROR: {
      RETURN_ERROR_VERDICT(engine.verdict_msg() + ": " + engine.reason_msg());
      break;
    }
    default: {
      // unknown verdict?
    }
    }
  }
  log.pop();
  status = true;
  errormsg = engine.verdict_msg() + ": " + engine.reason_msg();
  return engine.verdict();
}

void Conf::set_exitvalue(std::string& s)
{
  std::string cmd;
  std::string value;
  split(s,cmd,value);
  exit_status=atoi(value.c_str());
}

void Conf::set_observe_sleep(std::string &s)
{
  Adapter::sleeptime=atoi(s.c_str());
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestSpiderPlotActor.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
// This tests the spider plot capabilities in VTK.
#include "vtkSpiderPlotActor.h"
#include "vtkFloatArray.h"
#include "vtkDataObject.h"
#include "vtkFieldData.h"
#include "vtkMath.h"
#include "vtkTextProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkPolyData.h"
#include "vtkPoints.h"
#include "vtkIdList.h"
#include "vtkProperty2D.h"
#include "vtkLegendBoxActor.h"
#include "vtkTestUtilities.h"
#include "vtkRegressionTestImage.h"

//----------------------------------------------------------------------------
int TestSpiderPlotActor( int argc, char * argv [] )
{
  int numTuples = 12;

  vtkFloatArray *bitter = vtkFloatArray::New();
  bitter->SetNumberOfTuples(numTuples);

  vtkFloatArray *crispy = vtkFloatArray::New();
  crispy->SetNumberOfTuples(numTuples);

  vtkFloatArray *crunchy = vtkFloatArray::New();
  crunchy->SetNumberOfTuples(numTuples);

  vtkFloatArray *salty = vtkFloatArray::New();
  salty->SetNumberOfTuples(numTuples);

  vtkFloatArray *oily = vtkFloatArray::New();
  oily->SetNumberOfTuples(numTuples);

  for (int i=0; i<numTuples; i++)
    {
    bitter->SetTuple1(i, vtkMath::Random(1,10));
    crispy->SetTuple1(i, vtkMath::Random(-1,1));
    crunchy->SetTuple1(i, vtkMath::Random(1,100));
    salty->SetTuple1(i, vtkMath::Random(0,10));
    oily->SetTuple1(i, vtkMath::Random(5,25));
    }

  vtkDataObject *dobj = vtkDataObject::New();
  dobj->GetFieldData()->AddArray(bitter);
  dobj->GetFieldData()->AddArray(crispy);
  dobj->GetFieldData()->AddArray(crunchy);
  dobj->GetFieldData()->AddArray(salty);
  dobj->GetFieldData()->AddArray(oily);

  vtkSpiderPlotActor *actor = vtkSpiderPlotActor::New();
  actor->SetInput(dobj);
  actor->SetTitle("Spider Plot");
  actor->SetIndependentVariablesToColumns();
  actor->GetPositionCoordinate()->SetValue(0.05,0.1,0.0);
  actor->GetPosition2Coordinate()->SetValue(0.95,0.85,0.0);
  actor->GetProperty()->SetColor(1,0,0);
  actor->SetAxisLabel(0,"Bitter");
  actor->SetAxisRange(0,1,10);
  actor->SetAxisLabel(1,"Crispy");
  actor->SetAxisRange(1,-1,1);
  actor->SetAxisLabel(2,"Crunchy");
  actor->SetAxisRange(2,1,100);
  actor->SetAxisLabel(3,"Salty");
  actor->SetAxisRange(3,0,10);
  actor->SetAxisLabel(4,"Oily");
  actor->SetAxisRange(4,5,25);
  actor->GetLegendActor()->SetNumberOfEntries(numTuples);
  for (int i=0; i<numTuples; i++)
    {
    double red=vtkMath::Random(0,255);
    double green=vtkMath::Random(0,255);
    double blue=vtkMath::Random(0,255);
    actor->SetPlotColor(i,red,green,blue);
    }
  actor->LegendVisibilityOn();

  // Set text colors (same as actor for backward compat with test)
  actor->GetTitleTextProperty()->SetColor(1,1,0);
  actor->GetLabelTextProperty()->SetColor(1,0,0);

  // Create the RenderWindow, Renderer and both Actors
  vtkRenderer *ren1 = vtkRenderer::New();
  vtkRenderWindow *renWin = vtkRenderWindow::New();
  renWin->AddRenderer(ren1);
  vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
  iren->SetRenderWindow(renWin);

  ren1->AddActor(actor);
  ren1->SetBackground(0,0,0);
  renWin->SetSize(500,200);

  // render the image
  renWin->Render();

  int retVal = vtkRegressionTestImage( renWin );
  if ( retVal == vtkRegressionTester::DO_INTERACTOR)
    {
    iren->Start();
    }

  bitter->Delete();
  crispy->Delete();
  crunchy->Delete();
  salty->Delete();
  oily->Delete();
  dobj->Delete();
  actor->Delete();
  ren1->Delete();
  renWin->Delete();
  iren->Delete();

  return !retVal;
}
<commit_msg>BUG: Use correct range for color components in test code. New image corresponds to new test code. Old test code was using incorrect values for color components, colors have changed in the expected output image.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestSpiderPlotActor.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
// This tests the spider plot capabilities in VTK.
#include "vtkSpiderPlotActor.h"
#include "vtkFloatArray.h"
#include "vtkDataObject.h"
#include "vtkFieldData.h"
#include "vtkMath.h"
#include "vtkTextProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkPolyData.h"
#include "vtkPoints.h"
#include "vtkIdList.h"
#include "vtkProperty2D.h"
#include "vtkLegendBoxActor.h"
#include "vtkTestUtilities.h"
#include "vtkRegressionTestImage.h"

//----------------------------------------------------------------------------
int TestSpiderPlotActor( int argc, char * argv [] )
{
  int numTuples = 12;

  vtkFloatArray *bitter = vtkFloatArray::New();
  bitter->SetNumberOfTuples(numTuples);

  vtkFloatArray *crispy = vtkFloatArray::New();
  crispy->SetNumberOfTuples(numTuples);

  vtkFloatArray *crunchy = vtkFloatArray::New();
  crunchy->SetNumberOfTuples(numTuples);

  vtkFloatArray *salty = vtkFloatArray::New();
  salty->SetNumberOfTuples(numTuples);

  vtkFloatArray *oily = vtkFloatArray::New();
  oily->SetNumberOfTuples(numTuples);

  for (int i=0; i<numTuples; i++)
    {
    bitter->SetTuple1(i, vtkMath::Random(1,10));
    crispy->SetTuple1(i, vtkMath::Random(-1,1));
    crunchy->SetTuple1(i, vtkMath::Random(1,100));
    salty->SetTuple1(i, vtkMath::Random(0,10));
    oily->SetTuple1(i, vtkMath::Random(5,25));
    }

  vtkDataObject *dobj = vtkDataObject::New();
  dobj->GetFieldData()->AddArray(bitter);
  dobj->GetFieldData()->AddArray(crispy);
  dobj->GetFieldData()->AddArray(crunchy);
  dobj->GetFieldData()->AddArray(salty);
  dobj->GetFieldData()->AddArray(oily);

  vtkSpiderPlotActor *actor = vtkSpiderPlotActor::New();
  actor->SetInput(dobj);
  actor->SetTitle("Spider Plot");
  actor->SetIndependentVariablesToColumns();
  actor->GetPositionCoordinate()->SetValue(0.05,0.1,0.0);
  actor->GetPosition2Coordinate()->SetValue(0.95,0.85,0.0);
  actor->GetProperty()->SetColor(1,0,0);
  actor->SetAxisLabel(0,"Bitter");
  actor->SetAxisRange(0,1,10);
  actor->SetAxisLabel(1,"Crispy");
  actor->SetAxisRange(1,-1,1);
  actor->SetAxisLabel(2,"Crunchy");
  actor->SetAxisRange(2,1,100);
  actor->SetAxisLabel(3,"Salty");
  actor->SetAxisRange(3,0,10);
  actor->SetAxisLabel(4,"Oily");
  actor->SetAxisRange(4,5,25);
  actor->GetLegendActor()->SetNumberOfEntries(numTuples);
  for (int i=0; i<numTuples; i++)
    {
    double red=vtkMath::Random(0,1);
    double green=vtkMath::Random(0,1);
    double blue=vtkMath::Random(0,1);
    actor->SetPlotColor(i,red,green,blue);
    }
  actor->LegendVisibilityOn();

  // Set text colors (same as actor for backward compat with test)
  actor->GetTitleTextProperty()->SetColor(1,1,0);
  actor->GetLabelTextProperty()->SetColor(1,0,0);

  // Create the RenderWindow, Renderer and both Actors
  vtkRenderer *ren1 = vtkRenderer::New();
  vtkRenderWindow *renWin = vtkRenderWindow::New();
  renWin->AddRenderer(ren1);
  vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
  iren->SetRenderWindow(renWin);

  ren1->AddActor(actor);
  ren1->SetBackground(0,0,0);
  renWin->SetSize(500,200);

  // render the image
  renWin->Render();

  int retVal = vtkRegressionTestImage( renWin );
  if ( retVal == vtkRegressionTester::DO_INTERACTOR)
    {
    iren->Start();
    }

  bitter->Delete();
  crispy->Delete();
  crunchy->Delete();
  salty->Delete();
  oily->Delete();
  dobj->Delete();
  actor->Delete();
  ren1->Delete();
  renWin->Delete();
  iren->Delete();

  return !retVal;
}
<|endoftext|>