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

#include <algorithm>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <numeric>

#include "amxprofiler.h"

#include "amx/amx.h"
#include "amx/amxdbg.h"

std::map<AMX*, AmxProfiler*> AmxProfiler::instances_;

AmxProfiler::AmxProfiler() {}

// Extracts the names of native functions from the native table.
static void GetNatives(AMX *amx, std::vector<AmxProfiler::Function> &names) {
    AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
    AMX_FUNCSTUBNT *natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);

    int numberOfNatives;
    amx_NumNatives(amx, &numberOfNatives);

    for (int i = 0; i < numberOfNatives; i++) {
        names.push_back(AmxProfiler::Function(natives[i].address,
            reinterpret_cast<char*>(amx->base + natives[i].nameofs)));
    }
}

// Extracts the names of public functions from the native table.
static void GetPublics(AMX *amx, std::vector<AmxProfiler::Function> &names) {
    AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
    AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->publics);

    int numberOfPublics;
    amx_NumPublics(amx, &numberOfPublics);

    for (int i = 0; i < numberOfPublics; i++) {
        names.push_back(AmxProfiler::Function(publics[i].address,
            reinterpret_cast<char*>(amx->base + publics[i].nameofs)));
    }
}

// Reads from a code section at a given location.
static inline cell ReadAmxCode(AMX *amx, cell where) {
    AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
    return *reinterpret_cast<cell*>(amx->base + hdr->cod + where);
}

// Comparison functiosn for different stats sorting modes
static bool ByCalls(const std::pair<cell, AmxPerformanceCounter> &op1,
                         const std::pair<cell, AmxPerformanceCounter> &op2) {
    return op1.second.GetCalls() > op2.second.GetCalls();
}

static bool ByTime(const std::pair<cell, AmxPerformanceCounter> &op1,
                        const std::pair<cell, AmxPerformanceCounter> &op2) {
    return op1.second.GetTime() > op2.second.GetTime();
}

static bool ByTimePerCall(const std::pair<cell, AmxPerformanceCounter> &op1,
                               const std::pair<cell, AmxPerformanceCounter> &op2) {
    return static_cast<double>(op1.second.GetTime()) / static_cast<double>(op1.second.GetCalls())
         > static_cast<double>(op2.second.GetTime()) / static_cast<double>(op2.second.GetCalls());
}

AmxProfiler::AmxProfiler(AMX *amx)
    : amx_(amx),
      debug_(amx->debug),
      callback_(amx->callback),
      active_(false),
      haveDbg_(false)
{
    // Since PrintStats is done in AmxUnload and amx->base is already freed before
    // AmxUnload gets called, therefore both native and public tables are not accessible,
    // from there, so they must be stored separately in some global place.
    GetNatives(amx, natives_);
    GetPublics(amx, publics_);
}

AmxProfiler::AmxProfiler(AMX *amx, AMX_DBG amxdbg)
    : amx_(amx),
      amxdbg_(amxdbg),
      debug_(amx->debug),
      callback_(amx->callback),
      active_(false),
      haveDbg_(true)
{
    GetNatives(amx, natives_);
    GetPublics(amx, publics_);
}

void AmxProfiler::Attach(AMX *amx) {
    AmxProfiler *prof = new AmxProfiler(amx);
    instances_[amx] = prof;
    prof->Activate();
}

void AmxProfiler::Attach(AMX *amx, AMX_DBG amxdbg) {
    AmxProfiler *prof = new AmxProfiler(amx, amxdbg);
    instances_[amx] = prof;
    prof->Activate();
}

void AmxProfiler::Detach(AMX *amx) {
    AmxProfiler *prof = AmxProfiler::Get(amx);
    if (prof != 0) {
        prof->Deactivate();
        delete prof;
    }
    instances_.erase(amx);
}

AmxProfiler *AmxProfiler::Get(AMX *amx) {
    std::map<AMX*, AmxProfiler*>::iterator it = instances_.find(amx);
    if (it != instances_.end()) {
        return it->second;
    }
    return 0;
}

static int AMXAPI Debug(AMX *amx) {
    return AmxProfiler::Get(amx)->Debug();
}

static int AMXAPI Callback(AMX *amx, cell index, cell *result, cell *params) {
    return AmxProfiler::Get(amx)->Callback(index, result, params);
}

void AmxProfiler::Activate() {
    if (!active_) {
        active_ = true;
        amx_SetDebugHook(amx_, ::Debug);
        amx_SetCallback(amx_, ::Callback);
    }
}

bool AmxProfiler::IsActive() const {
    return active_;
}

void AmxProfiler::Deactivate() {
    if (active_) {
        active_ = false;
        amx_SetDebugHook(amx_, debug_);
        amx_SetCallback(amx_, callback_);
    }
}

void AmxProfiler::ResetStats() {
    counters_.clear();
}

bool AmxProfiler::PrintStats(const std::string &filename, StatsPrintOrder order) {
    std::ofstream stream(filename.c_str());

    if (stream.is_open()) {
        std::vector<std::pair<cell, AmxPerformanceCounter> > stats(counters_.begin(),
                                                     counters_.end());
        switch (order) {
            case ORDER_BY_CALLS:
                std::sort(stats.begin(), stats.end(), ByCalls);
                break;
            case ORDER_BY_TIME:
                std::sort(stats.begin(), stats.end(), ByTime);
                break;
            case ORDER_BY_TIME_PER_CALL:
                std::sort(stats.begin(), stats.end(), ByTimePerCall);
                break;
            default:
                // leave as is
                break;
        }

        stream << "
\n"
               << "\t
\n"
               << "\t\tFunction	\n"
               << "\t\tCalls	\n"
               << "\t\tTime per call, µs	\n"
               << "\t\tOverall time, µs	\n"
               << "\t\tOverall time, %	\n"
               << "\t
\n";

        platformstl::int64_t totalTime = 0;

        for (std::vector<std::pair<cell, AmxPerformanceCounter> >::iterator it = stats.begin();
             it != stats.end(); ++it)
        {
            totalTime += it->second.GetTime();
        }

        for (std::vector<std::pair<cell, AmxPerformanceCounter> >::iterator it = stats.begin();
             it != stats.end(); ++it)
        {
            stream << "\t
\n";

            cell address = it->first;

            if (address <= 0) {
                stream << "\t\t" << natives_[-address].name() << "	\n";
            } else {
                const char *name = 0;
                if (haveDbg_ && dbg_LookupFunction(&amxdbg_, address, &name) == AMX_ERR_NONE) {
                    stream << "\t\t" << name << "	\n";
                } else {
                    bool found = false;
                    for (std::vector<AmxProfiler::Function>::iterator pubIt = publics_.begin();
                         pubIt != publics_.end(); ++pubIt)
                    {
                        if (pubIt->address() == address)  {
                            stream << "\t\t" << pubIt->name() << "	\n";
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        // OK we tried all means but still don't know the name, so just print the address.
                        stream << "\t\t" << "0x" << std::hex << address << std::dec << "	\n";
                    }
                }
            }

            AmxPerformanceCounter &counter = it->second;

            stream << "\t\t" << counter.GetCalls() << "	\n"
                   << "\t\t" << std::fixed << std::setprecision(0)
                                 << static_cast<double>(counter.GetTime()) /
                                        static_cast<double>(counter.GetCalls()) << "	\n"
                   << "\t\t" << counter.GetTime() << "	\n"
                   << "\t\t" << std::setprecision(2)
                                 << static_cast<double>(counter.GetTime() * 100) /
                                        static_cast<double>(totalTime) << "	\n";
            stream << "\t
\n";
        }

        stream << "
\n";

        return true;
    }

    return false;
}

int AmxProfiler::Debug() {
    // Get previous stack frame.
    cell prevFrame = amx_->stp;
    if (!calls_.empty()) {
        prevFrame = calls_.top().frame();
    }

    // Check whether current frame is different.
    if (amx_->frm < prevFrame) {
        // Probably entered a function body (first BREAK after PROC).
        cell address = amx_->cip - 2*sizeof(cell);
        // Check if we have a PROC opcode behind.
        if (ReadAmxCode(amx_, address) == 46) {
            calls_.push(CallInfo(amx_->frm, address, false));
            if (active_) {
                counters_[address].Start();
            }
            //logprintf("==> %x | frame = %x", address, amx_->frm);
        }
    } else if (amx_->frm > prevFrame) {
        if (!calls_.top().entryPoint()) { // entry points are handled by Exec
            // Left the function
            cell address = calls_.top().address();
            if (active_) {
                counters_[address].Stop();
            }
            calls_.pop();
            //logprintf("<== %x | frame = %x", address, amx_->frm);
        }
    }

    if (debug_ != 0) {
        // Others could set their own debug hooks
        return debug_(amx_);
    }

    return AMX_ERR_NONE;
}

int AmxProfiler::Callback(cell index, cell *result, cell *params) {
    // The default AMX callback (amx_Callback) can replace SYSREQ.C opcodes
    // with SYSREQ.D for better performance.
    amx_->sysreq_d = 0;

    if (active_) counters_[-index].Start();; // Notice negative index
    int error = callback_(amx_, index, result, params);
    if (active_) counters_[-index].Stop();

    return error;
}

int AmxProfiler::Exec(cell *retval, int index) {
    if (index >= 0 || index == AMX_EXEC_MAIN) {
        AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx_->base);
        cell address = 0;

        if (index == AMX_EXEC_MAIN) {
            address = hdr->cip;
        } else {
            AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx_->base + hdr->publics);
            address = publics[index].address;
        }

        calls_.push(CallInfo(amx_->stk - 3*sizeof(cell), address, true));

        if (active_) counters_[address].Start();
        int error = amx_Exec(amx_, retval, index);
        if (active_) counters_[address].Stop();

        calls_.pop();

        return error;
    } else {
        return amx_Exec(amx_, retval, index);
    }
}

<commit_msg>Rename last parameters of GetNatives and GetPublics<commit_after>// SA:MP Profiler plugin
//
// Copyright (c) 2011 Zeex
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <algorithm>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <numeric>

#include "amxprofiler.h"

#include "amx/amx.h"
#include "amx/amxdbg.h"

std::map<AMX*, AmxProfiler*> AmxProfiler::instances_;

AmxProfiler::AmxProfiler() {}

// Extracts the names of native functions from the native table.
static void GetNatives(AMX *amx, std::vector<AmxProfiler::Function> &natives) {
    AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
    AMX_FUNCSTUBNT *nativeTable = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);

    int numberOfNatives;
    amx_NumNatives(amx, &numberOfNatives);

    for (int i = 0; i < numberOfNatives; i++) {
        natives.push_back(AmxProfiler::Function(nativeTable[i].address,
            reinterpret_cast<char*>(amx->base + nativeTable[i].nameofs)));
    }
}

// Extracts the names of public functions from the native table.
static void GetPublics(AMX *amx, std::vector<AmxProfiler::Function> &publics) {
    AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
    AMX_FUNCSTUBNT *publicTable = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->publics);

    int numberOfPublics;
    amx_NumPublics(amx, &numberOfPublics);

    for (int i = 0; i < numberOfPublics; i++) {
        publics.push_back(AmxProfiler::Function(publicTable[i].address,
            reinterpret_cast<char*>(amx->base + publicTable[i].nameofs)));
    }
}

// Reads from a code section at a given location.
static inline cell ReadAmxCode(AMX *amx, cell where) {
    AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
    return *reinterpret_cast<cell*>(amx->base + hdr->cod + where);
}

// Comparison functiosn for different stats sorting modes
static bool ByCalls(const std::pair<cell, AmxPerformanceCounter> &op1,
                         const std::pair<cell, AmxPerformanceCounter> &op2) {
    return op1.second.GetCalls() > op2.second.GetCalls();
}

static bool ByTime(const std::pair<cell, AmxPerformanceCounter> &op1,
                        const std::pair<cell, AmxPerformanceCounter> &op2) {
    return op1.second.GetTime() > op2.second.GetTime();
}

static bool ByTimePerCall(const std::pair<cell, AmxPerformanceCounter> &op1,
                               const std::pair<cell, AmxPerformanceCounter> &op2) {
    return static_cast<double>(op1.second.GetTime()) / static_cast<double>(op1.second.GetCalls())
         > static_cast<double>(op2.second.GetTime()) / static_cast<double>(op2.second.GetCalls());
}

AmxProfiler::AmxProfiler(AMX *amx)
    : amx_(amx),
      debug_(amx->debug),
      callback_(amx->callback),
      active_(false),
      haveDbg_(false)
{
    // Since PrintStats is done in AmxUnload and amx->base is already freed before
    // AmxUnload gets called, therefore both native and public tables are not accessible,
    // from there, so they must be stored separately in some global place.
    GetNatives(amx, natives_);
    GetPublics(amx, publics_);
}

AmxProfiler::AmxProfiler(AMX *amx, AMX_DBG amxdbg)
    : amx_(amx),
      amxdbg_(amxdbg),
      debug_(amx->debug),
      callback_(amx->callback),
      active_(false),
      haveDbg_(true)
{
    GetNatives(amx, natives_);
    GetPublics(amx, publics_);
}

void AmxProfiler::Attach(AMX *amx) {
    AmxProfiler *prof = new AmxProfiler(amx);
    instances_[amx] = prof;
    prof->Activate();
}

void AmxProfiler::Attach(AMX *amx, AMX_DBG amxdbg) {
    AmxProfiler *prof = new AmxProfiler(amx, amxdbg);
    instances_[amx] = prof;
    prof->Activate();
}

void AmxProfiler::Detach(AMX *amx) {
    AmxProfiler *prof = AmxProfiler::Get(amx);
    if (prof != 0) {
        prof->Deactivate();
        delete prof;
    }
    instances_.erase(amx);
}

AmxProfiler *AmxProfiler::Get(AMX *amx) {
    std::map<AMX*, AmxProfiler*>::iterator it = instances_.find(amx);
    if (it != instances_.end()) {
        return it->second;
    }
    return 0;
}

static int AMXAPI Debug(AMX *amx) {
    return AmxProfiler::Get(amx)->Debug();
}

static int AMXAPI Callback(AMX *amx, cell index, cell *result, cell *params) {
    return AmxProfiler::Get(amx)->Callback(index, result, params);
}

void AmxProfiler::Activate() {
    if (!active_) {
        active_ = true;
        amx_SetDebugHook(amx_, ::Debug);
        amx_SetCallback(amx_, ::Callback);
    }
}

bool AmxProfiler::IsActive() const {
    return active_;
}

void AmxProfiler::Deactivate() {
    if (active_) {
        active_ = false;
        amx_SetDebugHook(amx_, debug_);
        amx_SetCallback(amx_, callback_);
    }
}

void AmxProfiler::ResetStats() {
    counters_.clear();
}

bool AmxProfiler::PrintStats(const std::string &filename, StatsPrintOrder order) {
    std::ofstream stream(filename.c_str());

    if (stream.is_open()) {
        std::vector<std::pair<cell, AmxPerformanceCounter> > stats(counters_.begin(),
                                                     counters_.end());
        switch (order) {
            case ORDER_BY_CALLS:
                std::sort(stats.begin(), stats.end(), ByCalls);
                break;
            case ORDER_BY_TIME:
                std::sort(stats.begin(), stats.end(), ByTime);
                break;
            case ORDER_BY_TIME_PER_CALL:
                std::sort(stats.begin(), stats.end(), ByTimePerCall);
                break;
            default:
                // leave as is
                break;
        }

        stream << "
\n"
               << "\t
\n"
               << "\t\tFunction	\n"
               << "\t\tCalls	\n"
               << "\t\tTime per call, µs	\n"
               << "\t\tOverall time, µs	\n"
               << "\t\tOverall time, %	\n"
               << "\t
\n";

        platformstl::int64_t totalTime = 0;

        for (std::vector<std::pair<cell, AmxPerformanceCounter> >::iterator it = stats.begin();
             it != stats.end(); ++it)
        {
            totalTime += it->second.GetTime();
        }

        for (std::vector<std::pair<cell, AmxPerformanceCounter> >::iterator it = stats.begin();
             it != stats.end(); ++it)
        {
            stream << "\t
\n";

            cell address = it->first;

            if (address <= 0) {
                stream << "\t\t" << natives_[-address].name() << "	\n";
            } else {
                const char *name = 0;
                if (haveDbg_ && dbg_LookupFunction(&amxdbg_, address, &name) == AMX_ERR_NONE) {
                    stream << "\t\t" << name << "	\n";
                } else {
                    bool found = false;
                    for (std::vector<AmxProfiler::Function>::iterator pubIt = publics_.begin();
                         pubIt != publics_.end(); ++pubIt)
                    {
                        if (pubIt->address() == address)  {
                            stream << "\t\t" << pubIt->name() << "	\n";
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        // OK we tried all means but still don't know the name, so just print the address.
                        stream << "\t\t" << "0x" << std::hex << address << std::dec << "	\n";
                    }
                }
            }

            AmxPerformanceCounter &counter = it->second;

            stream << "\t\t" << counter.GetCalls() << "	\n"
                   << "\t\t" << std::fixed << std::setprecision(0)
                                 << static_cast<double>(counter.GetTime()) /
                                        static_cast<double>(counter.GetCalls()) << "	\n"
                   << "\t\t" << counter.GetTime() << "	\n"
                   << "\t\t" << std::setprecision(2)
                                 << static_cast<double>(counter.GetTime() * 100) /
                                        static_cast<double>(totalTime) << "	\n";
            stream << "\t
\n";
        }

        stream << "
\n";

        return true;
    }

    return false;
}

int AmxProfiler::Debug() {
    // Get previous stack frame.
    cell prevFrame = amx_->stp;
    if (!calls_.empty()) {
        prevFrame = calls_.top().frame();
    }

    // Check whether current frame is different.
    if (amx_->frm < prevFrame) {
        // Probably entered a function body (first BREAK after PROC).
        cell address = amx_->cip - 2*sizeof(cell);
        // Check if we have a PROC opcode behind.
        if (ReadAmxCode(amx_, address) == 46) {
            calls_.push(CallInfo(amx_->frm, address, false));
            if (active_) {
                counters_[address].Start();
            }
            //logprintf("==> %x | frame = %x", address, amx_->frm);
        }
    } else if (amx_->frm > prevFrame) {
        if (!calls_.top().entryPoint()) { // entry points are handled by Exec
            // Left the function
            cell address = calls_.top().address();
            if (active_) {
                counters_[address].Stop();
            }
            calls_.pop();
            //logprintf("<== %x | frame = %x", address, amx_->frm);
        }
    }

    if (debug_ != 0) {
        // Others could set their own debug hooks
        return debug_(amx_);
    }

    return AMX_ERR_NONE;
}

int AmxProfiler::Callback(cell index, cell *result, cell *params) {
    // The default AMX callback (amx_Callback) can replace SYSREQ.C opcodes
    // with SYSREQ.D for better performance.
    amx_->sysreq_d = 0;

    if (active_) counters_[-index].Start();; // Notice negative index
    int error = callback_(amx_, index, result, params);
    if (active_) counters_[-index].Stop();

    return error;
}

int AmxProfiler::Exec(cell *retval, int index) {
    if (index >= 0 || index == AMX_EXEC_MAIN) {
        AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx_->base);
        cell address = 0;

        if (index == AMX_EXEC_MAIN) {
            address = hdr->cip;
        } else {
            AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx_->base + hdr->publics);
            address = publics[index].address;
        }

        calls_.push(CallInfo(amx_->stk - 3*sizeof(cell), address, true));

        if (active_) counters_[address].Start();
        int error = amx_Exec(amx_, retval, index);
        if (active_) counters_[address].Stop();

        calls_.pop();

        return error;
    } else {
        return amx_Exec(amx_, retval, index);
    }
}

<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/*!
 *  Copyright (c) 2017 by Contributors
 *  Exposre of pass functions.
 * \file api_pass.cc
 */
#include <tvm/expr.h>
#include <tvm/ir.h>
#include <tvm/attrs.h>
#include <tvm/ir_pass.h>
#include <tvm/ir_visitor.h>
#include <tvm/ir_mutator.h>
#include <tvm/api_registry.h>

namespace tvm {
namespace ir {

TVM_REGISTER_API("ir_pass.Simplify")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    if (args[0].IsNodeType<Stmt>()) {
      if (args.size() > 1) {
        *ret = Simplify(args[0].operator Stmt(), args[1]);
      } else {
        *ret = Simplify(args[0].operator Stmt());
      }
    } else {
      if (args.size() > 1) {
        *ret = Simplify(args[0].operator Expr(), args[1]);
      } else {
        *ret = Simplify(args[0].operator Expr());
      }
    }
  });

TVM_REGISTER_API("ir_pass.CanonicalSimplify")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    if (args[0].IsNodeType<Stmt>()) {
      if (args.size() > 1) {
        *ret = CanonicalSimplify(args[0].operator Stmt(), args[1]);
      } else {
        *ret = CanonicalSimplify(args[0].operator Stmt());
      }
    } else {
      if (args.size() > 1) {
        *ret = CanonicalSimplify(args[0].operator Expr(), args[1]);
      } else {
        *ret = CanonicalSimplify(args[0].operator Expr());
      }
    }
  });

TVM_REGISTER_API("ir_pass.Substitute")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    if (args[0].IsNodeType<Stmt>()) {
      *ret = Substitute(args[0].operator Stmt(), args[1].operator Map<Var, Expr>());
    } else {
      *ret = Substitute(args[0].operator Expr(), args[1].operator Map<Var, Expr>());
    }
  });

TVM_REGISTER_API("ir_pass.Equal")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    if (args[0].IsNodeType<Stmt>()) {
      *ret = Equal(args[0].operator Stmt(), args[1].operator Stmt());
    } else {
      *ret = Equal(args[0].operator Expr(), args[1].operator Expr());
    }
  });

TVM_REGISTER_API("ir_pass.StorageFlatten")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    if (args.size() <= 3) {
      *ret = StorageFlatten(args[0], args[1], args[2]);
    } else {
      *ret = StorageFlatten(args[0], args[1], args[2], args[3]);
    }
  });

TVM_REGISTER_API("ir_pass.AttrsEqual")
.set_body_typed<bool(const NodeRef&, const NodeRef&)>([](const NodeRef& lhs, const NodeRef& rhs) {
    return AttrsEqual()(lhs, rhs);
  });

TVM_REGISTER_API("ir_pass.AttrsHash")
.set_body_typed<int64_t(const NodeRef&)>([](const NodeRef &node) {
    return AttrsHash()(node);
  });

TVM_REGISTER_API("ir_pass.ExprUseVar")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    *ret = ExprUseVar(args[0].operator Expr(), args[1].operator Var());
  });

TVM_REGISTER_API("ir_pass.PostOrderVisit")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    PackedFunc f = args[1];
    ir::PostOrderVisit(args[0], [f](const NodeRef& n) {
        f(n);
      });
  });

// make from two arguments
#define REGISTER_PASS(PassName)                                   \
  TVM_REGISTER_API("ir_pass."#PassName)                           \
  .set_body_typed(PassName);                                     \

REGISTER_PASS(ConvertSSA);
REGISTER_PASS(VerifySSA);
REGISTER_PASS(RewriteUnsafeSelect);
REGISTER_PASS(Inline);
REGISTER_PASS(IRTransform);
REGISTER_PASS(VectorizeLoop);
REGISTER_PASS(UnrollLoop);
REGISTER_PASS(InjectCopyIntrin);
REGISTER_PASS(ThreadSync);
REGISTER_PASS(MakeAPI);
REGISTER_PASS(BindDeviceType);
REGISTER_PASS(SplitHostDevice);
REGISTER_PASS(StorageRewrite);
REGISTER_PASS(CoProcSync);
REGISTER_PASS(LowerStorageAccessInfo);
REGISTER_PASS(InjectVirtualThread);
REGISTER_PASS(InjectPrefetch);
REGISTER_PASS(InjectDoubleBuffer);
REGISTER_PASS(LoopPartition);
REGISTER_PASS(RemoveNoOp);
REGISTER_PASS(SplitPipeline);
REGISTER_PASS(LiftAttrScope);
REGISTER_PASS(NarrowChannelAccess);
REGISTER_PASS(LowerThreadAllreduce);
REGISTER_PASS(LowerWarpMemory);
REGISTER_PASS(RemapThreadAxis);
REGISTER_PASS(LowerIntrin);
REGISTER_PASS(LowerCustomDatatypes);
REGISTER_PASS(LowerTVMBuiltin);
REGISTER_PASS(CombineContextCall);
REGISTER_PASS(VerifyMemory);
REGISTER_PASS(VerifyGPUCode);
REGISTER_PASS(DecorateDeviceScope);
REGISTER_PASS(InstrumentBoundCheckers);
}  // namespace ir
}  // namespace tvm
<commit_msg>Register SkipVectorize (#3228)<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/*!
 *  Copyright (c) 2017 by Contributors
 *  Exposre of pass functions.
 * \file api_pass.cc
 */
#include <tvm/expr.h>
#include <tvm/ir.h>
#include <tvm/attrs.h>
#include <tvm/ir_pass.h>
#include <tvm/ir_visitor.h>
#include <tvm/ir_mutator.h>
#include <tvm/api_registry.h>

namespace tvm {
namespace ir {

TVM_REGISTER_API("ir_pass.Simplify")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    if (args[0].IsNodeType<Stmt>()) {
      if (args.size() > 1) {
        *ret = Simplify(args[0].operator Stmt(), args[1]);
      } else {
        *ret = Simplify(args[0].operator Stmt());
      }
    } else {
      if (args.size() > 1) {
        *ret = Simplify(args[0].operator Expr(), args[1]);
      } else {
        *ret = Simplify(args[0].operator Expr());
      }
    }
  });

TVM_REGISTER_API("ir_pass.CanonicalSimplify")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    if (args[0].IsNodeType<Stmt>()) {
      if (args.size() > 1) {
        *ret = CanonicalSimplify(args[0].operator Stmt(), args[1]);
      } else {
        *ret = CanonicalSimplify(args[0].operator Stmt());
      }
    } else {
      if (args.size() > 1) {
        *ret = CanonicalSimplify(args[0].operator Expr(), args[1]);
      } else {
        *ret = CanonicalSimplify(args[0].operator Expr());
      }
    }
  });

TVM_REGISTER_API("ir_pass.Substitute")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    if (args[0].IsNodeType<Stmt>()) {
      *ret = Substitute(args[0].operator Stmt(), args[1].operator Map<Var, Expr>());
    } else {
      *ret = Substitute(args[0].operator Expr(), args[1].operator Map<Var, Expr>());
    }
  });

TVM_REGISTER_API("ir_pass.Equal")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    if (args[0].IsNodeType<Stmt>()) {
      *ret = Equal(args[0].operator Stmt(), args[1].operator Stmt());
    } else {
      *ret = Equal(args[0].operator Expr(), args[1].operator Expr());
    }
  });

TVM_REGISTER_API("ir_pass.StorageFlatten")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    if (args.size() <= 3) {
      *ret = StorageFlatten(args[0], args[1], args[2]);
    } else {
      *ret = StorageFlatten(args[0], args[1], args[2], args[3]);
    }
  });

TVM_REGISTER_API("ir_pass.AttrsEqual")
.set_body_typed<bool(const NodeRef&, const NodeRef&)>([](const NodeRef& lhs, const NodeRef& rhs) {
    return AttrsEqual()(lhs, rhs);
  });

TVM_REGISTER_API("ir_pass.AttrsHash")
.set_body_typed<int64_t(const NodeRef&)>([](const NodeRef &node) {
    return AttrsHash()(node);
  });

TVM_REGISTER_API("ir_pass.ExprUseVar")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    *ret = ExprUseVar(args[0].operator Expr(), args[1].operator Var());
  });

TVM_REGISTER_API("ir_pass.PostOrderVisit")
.set_body([](TVMArgs args, TVMRetValue *ret) {
    PackedFunc f = args[1];
    ir::PostOrderVisit(args[0], [f](const NodeRef& n) {
        f(n);
      });
  });

// make from two arguments
#define REGISTER_PASS(PassName)                                   \
  TVM_REGISTER_API("ir_pass."#PassName)                           \
  .set_body_typed(PassName);                                     \

REGISTER_PASS(ConvertSSA);
REGISTER_PASS(VerifySSA);
REGISTER_PASS(RewriteUnsafeSelect);
REGISTER_PASS(Inline);
REGISTER_PASS(IRTransform);
REGISTER_PASS(VectorizeLoop);
REGISTER_PASS(SkipVectorize);
REGISTER_PASS(UnrollLoop);
REGISTER_PASS(InjectCopyIntrin);
REGISTER_PASS(ThreadSync);
REGISTER_PASS(MakeAPI);
REGISTER_PASS(BindDeviceType);
REGISTER_PASS(SplitHostDevice);
REGISTER_PASS(StorageRewrite);
REGISTER_PASS(CoProcSync);
REGISTER_PASS(LowerStorageAccessInfo);
REGISTER_PASS(InjectVirtualThread);
REGISTER_PASS(InjectPrefetch);
REGISTER_PASS(InjectDoubleBuffer);
REGISTER_PASS(LoopPartition);
REGISTER_PASS(RemoveNoOp);
REGISTER_PASS(SplitPipeline);
REGISTER_PASS(LiftAttrScope);
REGISTER_PASS(NarrowChannelAccess);
REGISTER_PASS(LowerThreadAllreduce);
REGISTER_PASS(LowerWarpMemory);
REGISTER_PASS(RemapThreadAxis);
REGISTER_PASS(LowerIntrin);
REGISTER_PASS(LowerCustomDatatypes);
REGISTER_PASS(LowerTVMBuiltin);
REGISTER_PASS(CombineContextCall);
REGISTER_PASS(VerifyMemory);
REGISTER_PASS(VerifyGPUCode);
REGISTER_PASS(DecorateDeviceScope);
REGISTER_PASS(InstrumentBoundCheckers);
}  // namespace ir
}  // namespace tvm
<|endoftext|>


<commit_before>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <vector>
#include <cassert>

#include <af/array.h>
#include <af/index.h>
#include <ArrayInfo.hpp>
#include <err_common.hpp>
#include <handle.hpp>
#include <backend.hpp>
#include <Array.hpp>

using namespace detail;
using std::vector;
using std::swap;

template<typename T>
static void indexArray(af_array &dest, const af_array &src, const unsigned ndims, const af_seq *index)
{
    using af::toOffset;
    using af::toDims;
    using af::toStride;

    const Array<T> &parent = getArray<T>(src);
    vector<af_seq> index_(index, index+ndims);
    Array<T>* dst =  createSubArray(    parent,
                                        toDims(index_, parent.dims()),
                                        toOffset(index_, parent.dims()),
                                        toStride(index_, parent.dims()) );
    dest = getHandle(*dst);
}

af_err af_index(af_array *result, const af_array in, const unsigned ndims, const af_seq* index)
{
    //TODO: Check ndims agains max_dims
    af_err ret = AF_ERR_INTERNAL;
    af_array out;
    try {
        if(result)  { out = *result; }

        switch(getInfo(in).getType()) {
            case f32:    indexArray<float>   (out, in, ndims, index);  break;
            case c32:    indexArray<cfloat>  (out, in, ndims, index);  break;
            case f64:    indexArray<double>  (out, in, ndims, index);  break;
            case c64:    indexArray<cdouble> (out, in, ndims, index);  break;
            case b8:     indexArray<char>    (out, in, ndims, index);  break;
            case s32:    indexArray<int>     (out, in, ndims, index);  break;
            case u32:    indexArray<unsigned>(out, in, ndims, index);  break;
            case u8:     indexArray<uchar>   (out, in, ndims, index);  break;
            default:    ret = AF_ERR_NOT_SUPPORTED;                    break;
        }
        if(ret !=AF_ERR_NOT_SUPPORTED)
            ret = AF_SUCCESS;
    }
    CATCHALL

    swap(*result, out);
    return ret;
}
<commit_msg>Adding proper error checking macros to src/api/c/index.cpp<commit_after>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <vector>
#include <cassert>

#include <af/array.h>
#include <af/index.h>
#include <ArrayInfo.hpp>
#include <err_common.hpp>
#include <handle.hpp>
#include <backend.hpp>
#include <Array.hpp>

using namespace detail;
using std::vector;
using std::swap;

template<typename T>
static void indexArray(af_array &dest, const af_array &src, const unsigned ndims, const af_seq *index)
{
    using af::toOffset;
    using af::toDims;
    using af::toStride;

    const Array<T> &parent = getArray<T>(src);
    vector<af_seq> index_(index, index+ndims);
    Array<T>* dst =  createSubArray(    parent,
                                        toDims(index_, parent.dims()),
                                        toOffset(index_, parent.dims()),
                                        toStride(index_, parent.dims()) );
    dest = getHandle(*dst);
}

af_err af_index(af_array *result, const af_array in, const unsigned ndims, const af_seq* index)
{
    af_array out;
    try {
        if(result)  { out = *result; }

        af_dtype in_type = getInfo(in).getType();

        switch(in_type) {
        case f32:    indexArray<float>   (out, in, ndims, index);  break;
        case c32:    indexArray<cfloat>  (out, in, ndims, index);  break;
        case f64:    indexArray<double>  (out, in, ndims, index);  break;
        case c64:    indexArray<cdouble> (out, in, ndims, index);  break;
        case b8:     indexArray<char>    (out, in, ndims, index);  break;
        case s32:    indexArray<int>     (out, in, ndims, index);  break;
        case u32:    indexArray<unsigned>(out, in, ndims, index);  break;
        case u8:     indexArray<uchar>   (out, in, ndims, index);  break;
        default:    TYPE_ERROR(1, in_type);
        }
    }
    CATCHALL

    swap(*result, out);
    return AF_SUCCESS;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011 Scientific Computation Research Center
 *
 * This work is open source software, licensed under the terms of the
 * BSD license as described in the LICENSE file in the top-level directory.
 */

/* see Bousetta et al.
   "Adaptive remeshing based on a posteriori error estimation
   for forging simulation" */

#include "spr.h"

#include <PCU.h>
#include <apfMesh.h>
#include <apfShape.h>
#include <apfCavityOp.h>

#include <limits>
#include <cassert>

namespace spr {
namespace target {

struct Estimation {
  apf::Mesh* mesh;
  int integration_order;
  int recovered_order;
  apf::Field* eps;
  apf::Field* eps_star;
  size_t target_number;
  double size_factor;
  double alpha;
  double beta;
  apf::Field* elem_size;
  apf::Field* vtx_size;
};

static void setupEstimation(
    Estimation* e,
    apf::Field* eps,
    size_t target,
    double alpha,
    double beta)
{
  e->mesh = apf::getMesh(eps);
  e->integration_order = apf::getShape(eps)->getOrder();
  e->recovered_order = e->mesh->getShape()->getOrder();
  e->eps = eps;
  e->eps_star = 0;
  e->target_number = target;
  e->size_factor = 0;
  e->alpha = alpha;
  e->beta = beta;
  e->elem_size = 0;
  e->vtx_size = 0;
}

class ScalarIntegrator : public apf::Integrator
{
  public:
    ScalarIntegrator(int order):
      apf::Integrator(order),
      result(0)
    {
    }
    void parallelReduce()
    {
      PCU_Add_Doubles(&result,1);
    }
    double result;
};

class ElementError : public ScalarIntegrator
{
  public:
    ElementError(Estimation* e):
      ScalarIntegrator(e->integration_order),
      estimation(e),
      element(0),
      entity(0),
      sum(0),
      ip(0)
    {
      v1.setSize(apf::countComponents(e->eps));
      v2.setSize(apf::countComponents(e->eps_star));
    }
    void inElement(apf::MeshElement* meshElement)
    {
      element = apf::createElement(estimation->eps_star, meshElement);
      entity = apf::getMeshEntity(meshElement);
      sum = 0;
      ip = 0;
    }
    void outElement()
    {
      apf::destroyElement(element);
    }
    void atPoint(apf::Vector3 const& xi, double w, double dv)
    {
      apf::getComponents(estimation->eps, entity, ip, &v1[0]);
      apf::getComponents(element, xi, &v2[0]);
      apf::DynamicVector& diff = v1;
      diff -= v2;
      sum += (diff*diff)*w*dv;
      ++ip;
    }
    Estimation* estimation;
    apf::Element* element;
    apf::MeshEntity* entity;
    double sum;
    int ip;
    apf::DynamicVector v1,v2;
};

class GlobalErrorTerm : public ElementError
{
  public:
    GlobalErrorTerm(Estimation* e) : ElementError(e) {}
    void outElement()
    {
      ElementError::outElement();
      double d = estimation->mesh->getDimension();
      double p = estimation->recovered_order;
      result += pow(sqrt(sum), ((2*d)/(2*p+d)));
    }
};

static void computeSizeFactor(Estimation* e)
{
  GlobalErrorTerm globalError(e);
  globalError.process(e->mesh);
  int d = e->mesh->getDimension();
  double G = globalError.result;
  double N = e->target_number;
  e->size_factor = pow((G/N), (1.0/d));
}

static double getCurrentSize(apf::Mesh* m, apf::MeshEntity* e)
{
  double h=0;
  apf::Downward edges;
  int ne = m->getDownward(e,1,edges);
  for (int i=0; i < ne; ++i)
    h = std::max(h, apf::measure(m, edges[i]));
  return h;
}

static double getNewSize(Estimation* e, apf::MeshEntity* ent)
{
  ElementError elemError(e);
  apf::MeshElement* elem = apf::createMeshElement(e->mesh, ent);
  elemError.process(elem);
  int p = e->recovered_order;
  int d = e->mesh->getDimension();
  double h = getCurrentSize(e->mesh, ent);
  double theta_e = sqrt(elemError.sum);
  double r = pow(theta_e, ((-2.0)/(2.0*p+d)));
  double h_new = e->size_factor * r * h;
  if (h_new < e->alpha*h) h_new = e->alpha*h;
  if (h_new > e->beta*h) h_new = e->beta*h;
  return h_new;
}

static void getElemSizeField(Estimation* e)
{
  apf::Field* esize = apf::createStepField(e->mesh,"esize",apf::SCALAR);
  int d = e->mesh->getDimension();
  apf::MeshEntity* elem;
  apf::MeshIterator* elems = e->mesh->begin(d);
  while ((elem = e->mesh->iterate(elems))) {
    double h = getNewSize(e, elem);
    apf::setScalar(esize, elem, 0, h);
  }
  e->mesh->end(elems);
  e->elem_size = esize;
}

static void avgToVtx(apf::Field* ef, apf::Field* vf, apf::MeshEntity* ent)
{
  apf::Mesh* m = apf::getMesh(ef);
  apf::Adjacent elems;
  m->getAdjacent(ent, m->getDimension(), elems);
  double s = 0;
  for (size_t i=0; i < elems.getSize(); ++i)
    s += apf::getScalar(ef, elems[i], 0);
  s /= elems.getSize();
  apf::setScalar(vf, ent, 0, s);
}

class AverageOp : public apf::CavityOp
{
  public:
    AverageOp(Estimation* est):
      apf::CavityOp(est->mesh),
      estimation(est),
      entity(0)
    {
    }
    virtual Outcome setEntity(apf::MeshEntity* e)
    {
      entity = e;
      if (apf::hasEntity(estimation->vtx_size, entity))
        return SKIP;
      if ( ! requestLocality(&entity, 1))
        return REQUEST;
      return OK;
    }
    virtual void apply()
    {
      avgToVtx(
          estimation->elem_size,
          estimation->vtx_size,
          entity);
    }
    Estimation* estimation;
    apf::MeshEntity* entity;
};

static void averageSizeField(Estimation* e)
{
  e->vtx_size =
    apf::createLagrangeField(e->mesh, "size", apf::SCALAR, 1);
  AverageOp op(e);
  op.applyToDimension(0);
}

static void estimateError(Estimation* e)
{
  e->eps_star = recoverField(e->eps);
  computeSizeFactor(e);
  getElemSizeField(e);
  apf::destroyField(e->eps_star);
  averageSizeField(e);
  apf::destroyField(e->elem_size);
}

}

apf::Field* getTargetSPRSizeField(
    apf::Field* eps,
    size_t target,
    double alpha,
    double beta)
{
  double t0 = PCU_Time();
  assert(target > 0);
  assert(alpha < beta);
  target::Estimation e;
  target::setupEstimation(&e, eps, target, alpha, beta);
  target::estimateError(&e);
  double t1 = PCU_Time();
  if (!PCU_Comm_Self())
    fprintf(stderr, "SPR (target): error estimated in %f seconds\n",t1-t0);
  return e.vtx_size;
}

}
<commit_msg>spr: more correct citation<commit_after>/*
 * Copyright (C) 2011 Scientific Computation Research Center
 *
 * This work is open source software, licensed under the terms of the
 * BSD license as described in the LICENSE file in the top-level directory.
 */

/* see Boussetta, Ramzy et al.
   "Adaptive remeshing based on a posteriori error estimation
   for forging simulation." Computer methods in applied mechanics
   and engineering 195.48 (2006): 6626-6645. */

#include "spr.h"

#include <PCU.h>
#include <apfMesh.h>
#include <apfShape.h>
#include <apfCavityOp.h>

#include <limits>
#include <cassert>

namespace spr {
namespace target {

struct Estimation {
  apf::Mesh* mesh;
  int integration_order;
  int recovered_order;
  apf::Field* eps;
  apf::Field* eps_star;
  size_t target_number;
  double size_factor;
  double alpha;
  double beta;
  apf::Field* elem_size;
  apf::Field* vtx_size;
};

static void setupEstimation(
    Estimation* e,
    apf::Field* eps,
    size_t target,
    double alpha,
    double beta)
{
  e->mesh = apf::getMesh(eps);
  e->integration_order = apf::getShape(eps)->getOrder();
  e->recovered_order = e->mesh->getShape()->getOrder();
  e->eps = eps;
  e->eps_star = 0;
  e->target_number = target;
  e->size_factor = 0;
  e->alpha = alpha;
  e->beta = beta;
  e->elem_size = 0;
  e->vtx_size = 0;
}

class ScalarIntegrator : public apf::Integrator
{
  public:
    ScalarIntegrator(int order):
      apf::Integrator(order),
      result(0)
    {
    }
    void parallelReduce()
    {
      PCU_Add_Doubles(&result,1);
    }
    double result;
};

class ElementError : public ScalarIntegrator
{
  public:
    ElementError(Estimation* e):
      ScalarIntegrator(e->integration_order),
      estimation(e),
      element(0),
      entity(0),
      sum(0),
      ip(0)
    {
      v1.setSize(apf::countComponents(e->eps));
      v2.setSize(apf::countComponents(e->eps_star));
    }
    void inElement(apf::MeshElement* meshElement)
    {
      element = apf::createElement(estimation->eps_star, meshElement);
      entity = apf::getMeshEntity(meshElement);
      sum = 0;
      ip = 0;
    }
    void outElement()
    {
      apf::destroyElement(element);
    }
    void atPoint(apf::Vector3 const& xi, double w, double dv)
    {
      apf::getComponents(estimation->eps, entity, ip, &v1[0]);
      apf::getComponents(element, xi, &v2[0]);
      apf::DynamicVector& diff = v1;
      diff -= v2;
      sum += (diff*diff)*w*dv;
      ++ip;
    }
    Estimation* estimation;
    apf::Element* element;
    apf::MeshEntity* entity;
    double sum;
    int ip;
    apf::DynamicVector v1,v2;
};

class GlobalErrorTerm : public ElementError
{
  public:
    GlobalErrorTerm(Estimation* e) : ElementError(e) {}
    void outElement()
    {
      ElementError::outElement();
      double d = estimation->mesh->getDimension();
      double p = estimation->recovered_order;
      result += pow(sqrt(sum), ((2*d)/(2*p+d)));
    }
};

static void computeSizeFactor(Estimation* e)
{
  GlobalErrorTerm globalError(e);
  globalError.process(e->mesh);
  int d = e->mesh->getDimension();
  double G = globalError.result;
  double N = e->target_number;
  e->size_factor = pow((G/N), (1.0/d));
}

static double getCurrentSize(apf::Mesh* m, apf::MeshEntity* e)
{
  double h=0;
  apf::Downward edges;
  int ne = m->getDownward(e,1,edges);
  for (int i=0; i < ne; ++i)
    h = std::max(h, apf::measure(m, edges[i]));
  return h;
}

static double getNewSize(Estimation* e, apf::MeshEntity* ent)
{
  ElementError elemError(e);
  apf::MeshElement* elem = apf::createMeshElement(e->mesh, ent);
  elemError.process(elem);
  int p = e->recovered_order;
  int d = e->mesh->getDimension();
  double h = getCurrentSize(e->mesh, ent);
  double theta_e = sqrt(elemError.sum);
  double r = pow(theta_e, ((-2.0)/(2.0*p+d)));
  double h_new = e->size_factor * r * h;
  if (h_new < e->alpha*h) h_new = e->alpha*h;
  if (h_new > e->beta*h) h_new = e->beta*h;
  return h_new;
}

static void getElemSizeField(Estimation* e)
{
  apf::Field* esize = apf::createStepField(e->mesh,"esize",apf::SCALAR);
  int d = e->mesh->getDimension();
  apf::MeshEntity* elem;
  apf::MeshIterator* elems = e->mesh->begin(d);
  while ((elem = e->mesh->iterate(elems))) {
    double h = getNewSize(e, elem);
    apf::setScalar(esize, elem, 0, h);
  }
  e->mesh->end(elems);
  e->elem_size = esize;
}

static void avgToVtx(apf::Field* ef, apf::Field* vf, apf::MeshEntity* ent)
{
  apf::Mesh* m = apf::getMesh(ef);
  apf::Adjacent elems;
  m->getAdjacent(ent, m->getDimension(), elems);
  double s = 0;
  for (size_t i=0; i < elems.getSize(); ++i)
    s += apf::getScalar(ef, elems[i], 0);
  s /= elems.getSize();
  apf::setScalar(vf, ent, 0, s);
}

class AverageOp : public apf::CavityOp
{
  public:
    AverageOp(Estimation* est):
      apf::CavityOp(est->mesh),
      estimation(est),
      entity(0)
    {
    }
    virtual Outcome setEntity(apf::MeshEntity* e)
    {
      entity = e;
      if (apf::hasEntity(estimation->vtx_size, entity))
        return SKIP;
      if ( ! requestLocality(&entity, 1))
        return REQUEST;
      return OK;
    }
    virtual void apply()
    {
      avgToVtx(
          estimation->elem_size,
          estimation->vtx_size,
          entity);
    }
    Estimation* estimation;
    apf::MeshEntity* entity;
};

static void averageSizeField(Estimation* e)
{
  e->vtx_size =
    apf::createLagrangeField(e->mesh, "size", apf::SCALAR, 1);
  AverageOp op(e);
  op.applyToDimension(0);
}

static void estimateError(Estimation* e)
{
  e->eps_star = recoverField(e->eps);
  computeSizeFactor(e);
  getElemSizeField(e);
  apf::destroyField(e->eps_star);
  averageSizeField(e);
  apf::destroyField(e->elem_size);
}

}

apf::Field* getTargetSPRSizeField(
    apf::Field* eps,
    size_t target,
    double alpha,
    double beta)
{
  double t0 = PCU_Time();
  assert(target > 0);
  assert(alpha < beta);
  target::Estimation e;
  target::setupEstimation(&e, eps, target, alpha, beta);
  target::estimateError(&e);
  double t1 = PCU_Time();
  if (!PCU_Comm_Self())
    fprintf(stderr, "SPR (target): error estimated in %f seconds\n",t1-t0);
  return e.vtx_size;
}

}
<|endoftext|>


<commit_before>/*

This file is part of VROOM.

Copyright (c) 2015-2022, Julien Coupey.
All rights reserved (see LICENSE).

*/

#include <mutex>
#include <set>
#include <thread>

#include "algorithms/heuristics/heuristics.h"
#include "algorithms/local_search/local_search.h"
#include "problems/cvrp/cvrp.h"
#include "problems/cvrp/operators/cross_exchange.h"
#include "problems/cvrp/operators/intra_cross_exchange.h"
#include "problems/cvrp/operators/intra_exchange.h"
#include "problems/cvrp/operators/intra_mixed_exchange.h"
#include "problems/cvrp/operators/intra_or_opt.h"
#include "problems/cvrp/operators/intra_relocate.h"
#include "problems/cvrp/operators/intra_two_opt.h"
#include "problems/cvrp/operators/mixed_exchange.h"
#include "problems/cvrp/operators/or_opt.h"
#include "problems/cvrp/operators/pd_shift.h"
#include "problems/cvrp/operators/relocate.h"
#include "problems/cvrp/operators/reverse_two_opt.h"
#include "problems/cvrp/operators/route_exchange.h"
#include "problems/cvrp/operators/swap_star.h"
#include "problems/cvrp/operators/two_opt.h"
#include "problems/cvrp/operators/unassigned_exchange.h"
#include "problems/tsp/tsp.h"
#include "utils/helpers.h"

namespace vroom {

using RawSolution = std::vector<RawRoute>;

namespace cvrp {

using LocalSearch = ls::LocalSearch<RawRoute,
                                    cvrp::UnassignedExchange,
                                    cvrp::SwapStar,
                                    cvrp::CrossExchange,
                                    cvrp::MixedExchange,
                                    cvrp::TwoOpt,
                                    cvrp::ReverseTwoOpt,
                                    cvrp::Relocate,
                                    cvrp::OrOpt,
                                    cvrp::IntraExchange,
                                    cvrp::IntraCrossExchange,
                                    cvrp::IntraMixedExchange,
                                    cvrp::IntraRelocate,
                                    cvrp::IntraOrOpt,
                                    cvrp::IntraTwoOpt,
                                    cvrp::PDShift,
                                    cvrp::RouteExchange>;
} // namespace cvrp

const std::vector<HeuristicParameters> CVRP::homogeneous_parameters =
  {HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.3),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.1),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.5),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 0.3),

   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.7),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.3),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 2.1),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 0.2),

   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.1),
   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.6),
   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.9),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 2.4),

   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.2),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.8),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 1.2),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 0.4),

   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 1.2),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 1),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 1.1),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 2.4),

   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.2),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.9),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 1.5),

   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.5),
   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 1.3),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 1.5),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 0.1),

   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.4),
   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 1.6),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.6),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 0.5)};

const std::vector<HeuristicParameters> CVRP::heterogeneous_parameters =
  {HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.4),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.2),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0.1),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0.3),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.3),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.6),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.1),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0.2),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.2),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.9),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.3),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0.4),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.1),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.5),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 1.4),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 2.1),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.8),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0.6),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.8),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.4),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.5),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.6),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.7),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 1.2),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0.5),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.7),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 1),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 1.7),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 2.2)};

CVRP::CVRP(const Input& input) : VRP(input) {
}

Solution CVRP::solve(unsigned exploration_level,
                     unsigned nb_threads,
                     const Timeout& timeout,
                     const std::vector<HeuristicParameters>& h_param) const {
  if (_input.vehicles.size() == 1 and !_input.has_skills() and
      _input.zero_amount().size() == 0 and !_input.has_shipments() and
      (_input.jobs.size() <= _input.vehicles[0].max_tasks) and
      _input.vehicles[0].steps.empty()) {
    // This is a plain TSP, no need to go through the trouble below.
    std::vector<Index> job_ranks(_input.jobs.size());
    std::iota(job_ranks.begin(), job_ranks.end(), 0);

    TSP p(_input, job_ranks, 0);

    RawRoute r(_input, 0, 0);
    r.set_route(_input, p.raw_solve(nb_threads, timeout));

    return utils::format_solution(_input, {r});
  }

  // Use vector of parameters when passed for debugging, else use
  // predefined parameter set.
  const auto& parameters = (!h_param.empty())
                             ? h_param
                             : (_input.has_homogeneous_locations())
                                 ? homogeneous_parameters
                                 : heterogeneous_parameters;
  unsigned max_nb_jobs_removal = exploration_level;
  unsigned nb_init_solutions = h_param.size();

  if (nb_init_solutions == 0) {
    // Local search parameter.
    nb_init_solutions = 4 * (exploration_level + 1);
    if (exploration_level >= 4) {
      nb_init_solutions += 4;
    }
    if (exploration_level >= 5) {
      nb_init_solutions += 4;
    }
  }
  assert(nb_init_solutions <= parameters.size());

  std::vector<RawSolution> solutions(nb_init_solutions);

  // Split the heuristic parameters among threads.
  std::vector<std::vector<std::size_t>>
    thread_ranks(nb_threads, std::vector<std::size_t>());
  for (std::size_t i = 0; i < nb_init_solutions; ++i) {
    thread_ranks[i % nb_threads].push_back(i);
  }

  std::exception_ptr ep = nullptr;
  std::mutex ep_m;

  auto run_heuristics = [&](const std::vector<std::size_t>& param_ranks) {
    try {
      for (auto rank : param_ranks) {
        auto& p = parameters[rank];

        switch (p.heuristic) {
        case HEURISTIC::INIT_ROUTES:
          solutions[rank] = heuristics::initial_routes<RawSolution>(_input);
          break;
        case HEURISTIC::BASIC:
          solutions[rank] =
            heuristics::basic<RawSolution>(_input, p.init, p.regret_coeff);
          break;
        case HEURISTIC::DYNAMIC:
          solutions[rank] =
            heuristics::dynamic_vehicle_choice<RawSolution>(_input,
                                                            p.init,
                                                            p.regret_coeff);
          break;
        }
      }
    } catch (...) {
      ep_m.lock();
      ep = std::current_exception();
      ep_m.unlock();
    }
  };

  std::vector<std::thread> heuristics_threads;

  for (const auto& param_ranks : thread_ranks) {
    if (!param_ranks.empty()) {
      heuristics_threads.emplace_back(run_heuristics, param_ranks);
    }
  }

  for (auto& t : heuristics_threads) {
    t.join();
  }

  if (ep != nullptr) {
    std::rethrow_exception(ep);
  }

  // Filter out duplicate heuristics solutions.
  std::set<utils::SolutionIndicators<RawRoute>> unique_indicators;
  std::vector<unsigned> to_remove;
  for (unsigned i = 0; i < solutions.size(); ++i) {
    const auto result = unique_indicators.emplace(_input, solutions[i]);
    if (!result.second) {
      // No insertion means an equivalent solution already exists.
      to_remove.push_back(i);
    }
  }

  for (auto remove_rank = to_remove.rbegin(); remove_rank != to_remove.rend();
       remove_rank++) {
    solutions.erase(solutions.begin() + *remove_rank);
  }

  // Split local searches across threads.
  unsigned nb_solutions = solutions.size();
  std::vector<utils::SolutionIndicators<RawRoute>> sol_indicators(nb_solutions);
#ifdef LOG_LS_OPERATORS
  std::vector<std::array<ls::OperatorStats, OperatorName::MAX>> ls_stats(
    nb_solutions);
#endif

  std::fill(thread_ranks.begin(),
            thread_ranks.end(),
            std::vector<std::size_t>());
  for (std::size_t i = 0; i < nb_solutions; ++i) {
    thread_ranks[i % nb_threads].push_back(i);
  }

  auto run_ls = [&](const std::vector<std::size_t>& sol_ranks) {
    try {
      // Decide time allocated for each search.
      Timeout search_time;
      if (timeout.has_value()) {
        search_time = timeout.value() / sol_ranks.size();
      }

      for (auto rank : sol_ranks) {
        // Local search phase.
        cvrp::LocalSearch ls(_input,
                             solutions[rank],
                             max_nb_jobs_removal,
                             search_time);
        ls.run();

        // Store solution indicators.
        sol_indicators[rank] = ls.indicators();
#ifdef LOG_LS_OPERATORS
        ls_stats[rank] = ls.get_stats();
#endif
      }
    } catch (...) {
      ep_m.lock();
      ep = std::current_exception();
      ep_m.unlock();
    }
  };

  std::vector<std::thread> ls_threads;

  for (const auto& sol_ranks : thread_ranks) {
    if (!sol_ranks.empty()) {
      ls_threads.emplace_back(run_ls, sol_ranks);
    }
  }

  for (auto& t : ls_threads) {
    t.join();
  }

  if (ep != nullptr) {
    std::rethrow_exception(ep);
  }

#ifdef LOG_LS_OPERATORS
  utils::log_LS_operators(ls_stats);
#endif

  auto best_indic =
    std::min_element(sol_indicators.cbegin(), sol_indicators.cend());

  return utils::format_solution(_input,
                                solutions[std::distance(sol_indicators.cbegin(),
                                                        best_indic)]);
}

} // namespace vroom
<commit_msg>Change CVRP to use VRP::solve()<commit_after>/*

This file is part of VROOM.

Copyright (c) 2015-2022, Julien Coupey.
All rights reserved (see LICENSE).

*/

#include <mutex>
#include <set>
#include <thread>

#include "algorithms/heuristics/heuristics.h"
#include "algorithms/local_search/local_search.h"
#include "problems/cvrp/cvrp.h"
#include "problems/cvrp/operators/cross_exchange.h"
#include "problems/cvrp/operators/intra_cross_exchange.h"
#include "problems/cvrp/operators/intra_exchange.h"
#include "problems/cvrp/operators/intra_mixed_exchange.h"
#include "problems/cvrp/operators/intra_or_opt.h"
#include "problems/cvrp/operators/intra_relocate.h"
#include "problems/cvrp/operators/intra_two_opt.h"
#include "problems/cvrp/operators/mixed_exchange.h"
#include "problems/cvrp/operators/or_opt.h"
#include "problems/cvrp/operators/pd_shift.h"
#include "problems/cvrp/operators/relocate.h"
#include "problems/cvrp/operators/reverse_two_opt.h"
#include "problems/cvrp/operators/route_exchange.h"
#include "problems/cvrp/operators/swap_star.h"
#include "problems/cvrp/operators/two_opt.h"
#include "problems/cvrp/operators/unassigned_exchange.h"
#include "problems/tsp/tsp.h"
#include "utils/helpers.h"

namespace vroom {

using RawSolution = std::vector<RawRoute>;

namespace cvrp {

using LocalSearch = ls::LocalSearch<RawRoute,
                                    cvrp::UnassignedExchange,
                                    cvrp::SwapStar,
                                    cvrp::CrossExchange,
                                    cvrp::MixedExchange,
                                    cvrp::TwoOpt,
                                    cvrp::ReverseTwoOpt,
                                    cvrp::Relocate,
                                    cvrp::OrOpt,
                                    cvrp::IntraExchange,
                                    cvrp::IntraCrossExchange,
                                    cvrp::IntraMixedExchange,
                                    cvrp::IntraRelocate,
                                    cvrp::IntraOrOpt,
                                    cvrp::IntraTwoOpt,
                                    cvrp::PDShift,
                                    cvrp::RouteExchange>;
} // namespace cvrp

const std::vector<HeuristicParameters> CVRP::homogeneous_parameters =
  {HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.3),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.1),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.5),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 0.3),

   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.7),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.3),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 2.1),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 0.2),

   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.1),
   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.6),
   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.9),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 2.4),

   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.2),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.8),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 1.2),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 0.4),

   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 1.2),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 1),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 1.1),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 2.4),

   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.2),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.9),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 1.5),

   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.5),
   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 1.3),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 1.5),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 0.1),

   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 0.4),
   HeuristicParameters(HEURISTIC::BASIC, INIT::NONE, 1.6),
   HeuristicParameters(HEURISTIC::BASIC, INIT::HIGHER_AMOUNT, 0.6),
   HeuristicParameters(HEURISTIC::BASIC, INIT::FURTHEST, 0.5)};

const std::vector<HeuristicParameters> CVRP::heterogeneous_parameters =
  {HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.4),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.2),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0.1),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0.3),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.3),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.6),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.1),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0.2),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.2),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.9),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.3),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0.4),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.1),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.5),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 1.4),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 2.1),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.8),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0.6),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.8),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.4),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.5),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.6),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 0.7),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 1.2),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 0.5),

   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::NONE, 0.7),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::HIGHER_AMOUNT, 1),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 1.7),
   HeuristicParameters(HEURISTIC::DYNAMIC, INIT::FURTHEST, 2.2)};

CVRP::CVRP(const Input& input) : VRP(input) {
}

Solution CVRP::solve(unsigned exploration_level,
                     unsigned nb_threads,
                     const Timeout& timeout,
                     const std::vector<HeuristicParameters>& h_param) const {
  if (_input.vehicles.size() == 1 and !_input.has_skills() and
      _input.zero_amount().size() == 0 and !_input.has_shipments() and
      (_input.jobs.size() <= _input.vehicles[0].max_tasks) and
      _input.vehicles[0].steps.empty()) {
    // This is a plain TSP, no need to go through the trouble below.
    std::vector<Index> job_ranks(_input.jobs.size());
    std::iota(job_ranks.begin(), job_ranks.end(), 0);

    TSP p(_input, job_ranks, 0);

    RawRoute r(_input, 0, 0);
    r.set_route(_input, p.raw_solve(nb_threads, timeout));

    return utils::format_solution(_input, {r});
  }

  return VRP::solve<RawRoute, RawSolution, cvrp::LocalSearch>(exploration_level, nb_threads, timeout, h_param, homogeneous_parameters, heterogeneous_parameters);
}

} // namespace vroom
<|endoftext|>


<commit_before>#pragma once

#include <unordered_set>

#include "types.hpp"

namespace opossum {

/**
 * Abstract container class for the definition of table constraints based on a set of column ids.
 * Subclasses should leverage the OOP structure to add additional fields. In case of CHECK and FOREIGN KEY constraint
 * implementations, these fields may include check definitions and referenced keys.
 */
class AbstractTableConstraint {
 public:
  explicit AbstractTableConstraint(std::unordered_set<ColumnID> init_columns);
  virtual ~AbstractTableConstraint() = default;

  const std::unordered_set<ColumnID>& columns() const;

  bool operator==(const AbstractTableConstraint& rhs) const;
  bool operator!=(const AbstractTableConstraint& rhs) const;

 protected:
  /**
   * Compare two table constraints of the same type. Only additional fields have to be compared since column ids are
   * already compared by the caller.
   */
  virtual bool _on_equals(const AbstractTableConstraint& table_constraint) const = 0;

 private:
  std::unordered_set<ColumnID> _columns;
};

}  // namespace opossum
<commit_msg>Fix missing constructors for AbstractTableConstraint (#2166)<commit_after>#pragma once

#include <unordered_set>

#include "types.hpp"

namespace opossum {

/**
 * Abstract container class for the definition of table constraints based on a set of column ids.
 * Subclasses should leverage the OOP structure to add additional fields. In case of CHECK and FOREIGN KEY constraint
 * implementations, these fields may include check definitions and referenced keys.
 */
class AbstractTableConstraint {
 public:
  explicit AbstractTableConstraint(std::unordered_set<ColumnID> init_columns);

  AbstractTableConstraint(const AbstractTableConstraint&) = default;
  AbstractTableConstraint(AbstractTableConstraint&&) = default;
  AbstractTableConstraint& operator=(const AbstractTableConstraint&) = default;
  AbstractTableConstraint& operator=(AbstractTableConstraint&&) = default;

  virtual ~AbstractTableConstraint() = default;

  const std::unordered_set<ColumnID>& columns() const;

  bool operator==(const AbstractTableConstraint& rhs) const;
  bool operator!=(const AbstractTableConstraint& rhs) const;

 protected:
  /**
   * Compare two table constraints of the same type. Only additional fields have to be compared since column ids are
   * already compared by the caller.
   */
  virtual bool _on_equals(const AbstractTableConstraint& table_constraint) const = 0;

 private:
  std::unordered_set<ColumnID> _columns;
};

}  // namespace opossum
<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2019 LibRaw LLC (info@libraw.org)
    Copyright (C) 2020 Roman Lebedev

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that 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 library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/PanasonicDecompressorV6.h" // for PanasonicDecompre...
#include "common/Point.h"                          // for iPoint2D
#include "common/RawImage.h"                       // for RawImage, RawImag...
#include "decoders/RawDecoderException.h"          // for ThrowRDE
#include <algorithm>                               // for copy_n
#include <array>
#include <cstdint> // for uint16_t, uint32_t
#include <cstdlib> // for free, malloc

namespace rawspeed {

namespace {
struct pana_cs6_page_decoder {
  std::array<unsigned int, 14> pixelbuffer;
  unsigned lastoffset, maxoffset;
  unsigned char current;
  const unsigned char* buffer;
  pana_cs6_page_decoder(const unsigned char* _buffer, unsigned int bsize)
      : lastoffset(0), maxoffset(bsize), current(0), buffer(_buffer) {}
  void read_page(); // will throw IO error if not enough space in buffer
  unsigned int nextpixel() { return current < 14 ? pixelbuffer[current++] : 0; }
};

void pana_cs6_page_decoder::read_page() {
  if (!buffer || (maxoffset - lastoffset < 16))
    ThrowRDE("Input failure");
  auto wbuffer = [&](int i) {
    return static_cast<uint16_t>(buffer[lastoffset + 15 - i]);
  };
  pixelbuffer[0] = (wbuffer(0) << 6) | (wbuffer(1) >> 2); // 14 bit
  pixelbuffer[1] =
      (((wbuffer(1) & 0x3) << 12) | (wbuffer(2) << 4) | (wbuffer(3) >> 4)) &
      0x3fff;
  pixelbuffer[2] = (wbuffer(3) >> 2) & 0x3;
  pixelbuffer[3] = ((wbuffer(3) & 0x3) << 8) | wbuffer(4);
  pixelbuffer[4] = (wbuffer(5) << 2) | (wbuffer(6) >> 6);
  pixelbuffer[5] = ((wbuffer(6) & 0x3f) << 4) | (wbuffer(7) >> 4);
  pixelbuffer[6] = (wbuffer(7) >> 2) & 0x3;
  pixelbuffer[7] = ((wbuffer(7) & 0x3) << 8) | wbuffer(8);
  pixelbuffer[8] = ((wbuffer(9) << 2) & 0x3fc) | (wbuffer(10) >> 6);
  pixelbuffer[9] = ((wbuffer(10) << 4) | (wbuffer(11) >> 4)) & 0x3ff;
  pixelbuffer[10] = (wbuffer(11) >> 2) & 0x3;
  pixelbuffer[11] = ((wbuffer(11) & 0x3) << 8) | wbuffer(12);
  pixelbuffer[12] = (((wbuffer(13) << 2) & 0x3fc) | wbuffer(14) >> 6) & 0x3ff;
  pixelbuffer[13] = ((wbuffer(14) << 4) | (wbuffer(15) >> 4)) & 0x3ff;
#undef wbuffer
  current = 0;
  lastoffset += 16;
}
} // namespace

PanasonicDecompressorV6::PanasonicDecompressorV6(const RawImage& img,
                                                 ByteStream input_,
                                                 uint32_t bps_)
    : mRaw(img), input(std::move(input_)) {
  if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
      mRaw->getBpp() != sizeof(uint16_t))
    ThrowRDE("Unexpected component count / data type");

  if (!mRaw->dim.hasPositiveArea()) {
    ThrowRDE("Unexpected image dimensions found: (%i; %i)", mRaw->dim.x,
             mRaw->dim.y);
  }

  const int blocksperrow = mRaw->dim.x / 11;
  const int bytesPerRow = 16 * blocksperrow;
  const int bytesTotal = bytesPerRow * mRaw->dim.y;
  input = input_.peekStream(bytesTotal);
}

void PanasonicDecompressorV6::decompressBlock(ByteStream* rowInput, int row,
                                              int col) const {
  auto* rowptr = reinterpret_cast<uint16_t*>(mRaw->getDataUncropped(0, row));
  pana_cs6_page_decoder page(rowInput->getData(16), 16);
  page.read_page();
  std::array<unsigned int, 2> oddeven = {0, 0};
  std::array<unsigned int, 2> nonzero = {0, 0};
  unsigned pmul = 0;
  unsigned pixel_base = 0;
  for (int pix = 0; pix < 11; pix++) {
    if (pix % 3 == 2) {
      unsigned base = page.nextpixel();
      if (base > 3)
        ThrowRDE("Invariant failure");
      if (base == 3)
        base = 4;
      pixel_base = 0x200 << base;
      pmul = 1 << base;
    }
    unsigned epixel = page.nextpixel();
    if (oddeven[pix % 2]) {
      epixel *= pmul;
      if (pixel_base < 0x2000 && nonzero[pix % 2] > pixel_base)
        epixel += nonzero[pix % 2] - pixel_base;
      nonzero[pix % 2] = epixel;
    } else {
      oddeven[pix % 2] = epixel;
      if (epixel)
        nonzero[pix % 2] = epixel;
      else
        epixel = nonzero[pix % 2];
    }
    auto spix = static_cast<unsigned>(static_cast<int>(epixel) - 0xf);
    if (spix <= 0xffff)
      rowptr[col++] = spix & 0xffff;
    else {
      epixel = static_cast<signed int>(epixel + 0x7ffffff1) >> 0x1f;
      rowptr[col++] = epixel & 0x3fff;
    }
  }
}

void PanasonicDecompressorV6::decompressRow(int row) const {
  const int blocksperrow = mRaw->dim.x / 11;
  const int bytesPerRow = 16 * blocksperrow;

  ByteStream rowInput = input.getSubStream(bytesPerRow * row, bytesPerRow);
  for (int rblock = 0, col = 0; rblock < blocksperrow; rblock++, col += 11)
    decompressBlock(&rowInput, row, col);
}

void PanasonicDecompressorV6::decompress() const {
#ifdef HAVE_OPENMP
#pragma omp parallel for num_threads(rawspeed_get_number_of_processor_cores()) \
    schedule(static) default(none)
#endif
  for (int row = 0; row < mRaw->dim.y; ++row) {
    try {
      decompressRow(row);
    } catch (RawspeedException& err) {
      // Propagate the exception out of OpenMP magic.
      mRaw->setError(err.what());
    }
  }

  std::string firstErr;
  if (mRaw->isTooManyErrors(1, &firstErr)) {
    ThrowRDE("Too many errors encountered. Giving up. First Error:\n%s",
             firstErr.c_str());
  }
}

} // namespace rawspeed
<commit_msg>PanasonicDecompressorV6: use Array2DRef abstraction (-5%)<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2019 LibRaw LLC (info@libraw.org)
    Copyright (C) 2020 Roman Lebedev

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that 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 library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/PanasonicDecompressorV6.h" // for PanasonicDecompre...
#include "common/Array2DRef.h"                     // for Array2DRef
#include "common/Point.h"                          // for iPoint2D
#include "common/RawImage.h"                       // for RawImage, RawImag...
#include "decoders/RawDecoderException.h"          // for ThrowRDE
#include <algorithm>                               // for copy_n
#include <array>
#include <cstdint> // for uint16_t, uint32_t
#include <cstdlib> // for free, malloc

namespace rawspeed {

namespace {
struct pana_cs6_page_decoder {
  std::array<unsigned int, 14> pixelbuffer;
  unsigned lastoffset, maxoffset;
  unsigned char current;
  const unsigned char* buffer;
  pana_cs6_page_decoder(const unsigned char* _buffer, unsigned int bsize)
      : lastoffset(0), maxoffset(bsize), current(0), buffer(_buffer) {}
  void read_page(); // will throw IO error if not enough space in buffer
  unsigned int nextpixel() { return current < 14 ? pixelbuffer[current++] : 0; }
};

void pana_cs6_page_decoder::read_page() {
  if (!buffer || (maxoffset - lastoffset < 16))
    ThrowRDE("Input failure");
  auto wbuffer = [&](int i) {
    return static_cast<uint16_t>(buffer[lastoffset + 15 - i]);
  };
  pixelbuffer[0] = (wbuffer(0) << 6) | (wbuffer(1) >> 2); // 14 bit
  pixelbuffer[1] =
      (((wbuffer(1) & 0x3) << 12) | (wbuffer(2) << 4) | (wbuffer(3) >> 4)) &
      0x3fff;
  pixelbuffer[2] = (wbuffer(3) >> 2) & 0x3;
  pixelbuffer[3] = ((wbuffer(3) & 0x3) << 8) | wbuffer(4);
  pixelbuffer[4] = (wbuffer(5) << 2) | (wbuffer(6) >> 6);
  pixelbuffer[5] = ((wbuffer(6) & 0x3f) << 4) | (wbuffer(7) >> 4);
  pixelbuffer[6] = (wbuffer(7) >> 2) & 0x3;
  pixelbuffer[7] = ((wbuffer(7) & 0x3) << 8) | wbuffer(8);
  pixelbuffer[8] = ((wbuffer(9) << 2) & 0x3fc) | (wbuffer(10) >> 6);
  pixelbuffer[9] = ((wbuffer(10) << 4) | (wbuffer(11) >> 4)) & 0x3ff;
  pixelbuffer[10] = (wbuffer(11) >> 2) & 0x3;
  pixelbuffer[11] = ((wbuffer(11) & 0x3) << 8) | wbuffer(12);
  pixelbuffer[12] = (((wbuffer(13) << 2) & 0x3fc) | wbuffer(14) >> 6) & 0x3ff;
  pixelbuffer[13] = ((wbuffer(14) << 4) | (wbuffer(15) >> 4)) & 0x3ff;
#undef wbuffer
  current = 0;
  lastoffset += 16;
}
} // namespace

PanasonicDecompressorV6::PanasonicDecompressorV6(const RawImage& img,
                                                 ByteStream input_,
                                                 uint32_t bps_)
    : mRaw(img), input(std::move(input_)) {
  if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
      mRaw->getBpp() != sizeof(uint16_t))
    ThrowRDE("Unexpected component count / data type");

  if (!mRaw->dim.hasPositiveArea()) {
    ThrowRDE("Unexpected image dimensions found: (%i; %i)", mRaw->dim.x,
             mRaw->dim.y);
  }

  const int blocksperrow = mRaw->dim.x / 11;
  const int bytesPerRow = 16 * blocksperrow;
  const int bytesTotal = bytesPerRow * mRaw->dim.y;
  input = input_.peekStream(bytesTotal);
}

void PanasonicDecompressorV6::decompressBlock(ByteStream* rowInput, int row,
                                              int col) const {
  const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());

  pana_cs6_page_decoder page(rowInput->getData(16), 16);
  page.read_page();
  std::array<unsigned int, 2> oddeven = {0, 0};
  std::array<unsigned int, 2> nonzero = {0, 0};
  unsigned pmul = 0;
  unsigned pixel_base = 0;
  for (int pix = 0; pix < 11; pix++, col++) {
    if (pix % 3 == 2) {
      unsigned base = page.nextpixel();
      if (base > 3)
        ThrowRDE("Invariant failure");
      if (base == 3)
        base = 4;
      pixel_base = 0x200 << base;
      pmul = 1 << base;
    }
    unsigned epixel = page.nextpixel();
    if (oddeven[pix % 2]) {
      epixel *= pmul;
      if (pixel_base < 0x2000 && nonzero[pix % 2] > pixel_base)
        epixel += nonzero[pix % 2] - pixel_base;
      nonzero[pix % 2] = epixel;
    } else {
      oddeven[pix % 2] = epixel;
      if (epixel)
        nonzero[pix % 2] = epixel;
      else
        epixel = nonzero[pix % 2];
    }
    auto spix = static_cast<unsigned>(static_cast<int>(epixel) - 0xf);
    if (spix <= 0xffff)
      out(row, col) = spix & 0xffff;
    else {
      epixel = static_cast<signed int>(epixel + 0x7ffffff1) >> 0x1f;
      out(row, col) = epixel & 0x3fff;
    }
  }
}

void PanasonicDecompressorV6::decompressRow(int row) const {
  const int blocksperrow = mRaw->dim.x / 11;
  const int bytesPerRow = 16 * blocksperrow;

  ByteStream rowInput = input.getSubStream(bytesPerRow * row, bytesPerRow);
  for (int rblock = 0, col = 0; rblock < blocksperrow; rblock++, col += 11)
    decompressBlock(&rowInput, row, col);
}

void PanasonicDecompressorV6::decompress() const {
#ifdef HAVE_OPENMP
#pragma omp parallel for num_threads(rawspeed_get_number_of_processor_cores()) \
    schedule(static) default(none)
#endif
  for (int row = 0; row < mRaw->dim.y; ++row) {
    try {
      decompressRow(row);
    } catch (RawspeedException& err) {
      // Propagate the exception out of OpenMP magic.
      mRaw->setError(err.what());
    }
  }

  std::string firstErr;
  if (mRaw->isTooManyErrors(1, &firstErr)) {
    ThrowRDE("Too many errors encountered. Giving up. First Error:\n%s",
             firstErr.c_str());
  }
}

} // namespace rawspeed
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "app/gfx/canvas.h"

#include <cairo/cairo.h>
#include <pango/pango.h>
#include <pango/pangocairo.h>

#include "app/gfx/font.h"
#include "base/gfx/rect.h"
#include "base/logging.h"
#include "base/string_util.h"

namespace {

// Returns a new pango font, free with pango_font_description_free().
PangoFontDescription* PangoFontFromGfxFont(const gfx::Font& gfx_font) {
  gfx::Font font = gfx_font;  // Copy so we can call non-const methods.
  PangoFontDescription* pfd = pango_font_description_new();
  pango_font_description_set_family(pfd, WideToUTF8(font.FontName()).c_str());
  pango_font_description_set_size(pfd, font.FontSize() * PANGO_SCALE);

  switch (font.style()) {
    case gfx::Font::NORMAL:
      // Nothing to do, should already be PANGO_STYLE_NORMAL.
      break;
    case gfx::Font::BOLD:
      pango_font_description_set_weight(pfd, PANGO_WEIGHT_BOLD);
      break;
    case gfx::Font::ITALIC:
      pango_font_description_set_style(pfd, PANGO_STYLE_ITALIC);
      break;
    case gfx::Font::UNDERLINED:
      // TODO(deanm): How to do underlined?  Where do we use it?  Probably have
      // to paint it ourselves, see pango_font_metrics_get_underline_position.
      break;
  }

  return pfd;
}

}  // namespace

namespace gfx {

Canvas::Canvas(int width, int height, bool is_opaque)
    : skia::PlatformCanvas(width, height, is_opaque) {
}

Canvas::Canvas() : skia::PlatformCanvas() {
}

Canvas::~Canvas() {
}

// static
void Canvas::SizeStringInt(const std::wstring& text,
                           const gfx::Font& font,
                           int* width, int* height, int flags) {
  cairo_surface_t* surface =
      cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
  cairo_t* cr = cairo_create(surface);
  PangoLayout* layout = pango_cairo_create_layout(cr);

  if (flags & NO_ELLIPSIS) {
    pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
  } else {
    pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
  }

  if (flags & TEXT_ALIGN_CENTER) {
    pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
  } else if (flags & TEXT_ALIGN_RIGHT) {
    pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
  }

  if (flags & MULTI_LINE) {
    pango_layout_set_wrap(layout,
        (flags & CHARACTER_BREAK) ? PANGO_WRAP_WORD_CHAR : PANGO_WRAP_WORD);
  }

  std::string utf8 = WideToUTF8(text);
  pango_layout_set_text(layout, utf8.data(), utf8.size());
  PangoFontDescription* desc = PangoFontFromGfxFont(font);
  pango_layout_set_font_description(layout, desc);

  pango_layout_get_size(layout, width, height);
  *width /= PANGO_SCALE;
  *height /= PANGO_SCALE;
  g_object_unref(layout);
  pango_font_description_free(desc);
  cairo_destroy(cr);
  cairo_surface_destroy(surface);
}

void Canvas::DrawStringInt(const std::wstring& text,
                           const gfx::Font& font,
                           const SkColor& color, int x, int y, int w, int h,
                           int flags) {
  cairo_t* cr = beginPlatformPaint();
  PangoLayout* layout = pango_cairo_create_layout(cr);

  // Callers of DrawStringInt handle RTL layout themselves, so tell pango to not
  // scope out RTL characters.
  pango_layout_set_auto_dir(layout, FALSE);

  cairo_set_source_rgb(cr,
                       SkColorGetR(color) / 255.0,
                       SkColorGetG(color) / 255.0,
                       SkColorGetB(color) / 255.0);

  // TODO(deanm): Implement the rest of the Canvas flags.
  if (!(flags & Canvas::NO_ELLIPSIS))
    pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);

  pango_layout_set_width(layout, w * PANGO_SCALE);
  pango_layout_set_height(layout, h * PANGO_SCALE);

  if (flags & TEXT_ALIGN_CENTER) {
    pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
  } else if (flags & TEXT_ALIGN_RIGHT) {
    pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
  }

  if (flags & MULTI_LINE) {
    pango_layout_set_wrap(layout,
        (flags & CHARACTER_BREAK) ? PANGO_WRAP_WORD_CHAR : PANGO_WRAP_WORD);
  }

  if (flags & NO_ELLIPSIS)
    pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);

  std::string utf8 = WideToUTF8(text);
  pango_layout_set_text(layout, utf8.data(), utf8.size());

  PangoFontDescription* desc = PangoFontFromGfxFont(font);
  pango_layout_set_font_description(layout, desc);
  pango_font_description_free(desc);

  int width, height;
  pango_layout_get_size(layout, &width, &height);

  if (flags & Canvas::TEXT_VALIGN_TOP) {
    // Cairo should draw from the top left corner already.
  } else if (flags & Canvas::TEXT_VALIGN_BOTTOM) {
    y = y + (h - (height / PANGO_SCALE));
  } else {
    // Vertically centered.
    y = y + ((h - (height / PANGO_SCALE)) / 2);
  }

  cairo_move_to(cr, x, y);
  pango_cairo_show_layout(cr, layout);

  g_object_unref(layout);
  // NOTE: beginPlatformPaint returned its surface, we shouldn't destroy it.
}

}  // namespace gfx
<commit_msg>Linux: make gfx::Canvas honor GTK font settings.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "app/gfx/canvas.h"

#include <cairo/cairo.h>
#include <gtk/gtk.h>
#include <pango/pango.h>
#include <pango/pangocairo.h>

#include "app/gfx/font.h"
#include "base/gfx/rect.h"
#include "base/logging.h"
#include "base/string_util.h"

namespace {

// Font settings that we initialize once and then use when drawing text in
// DrawStringInt().
static cairo_font_options_t* cairo_font_options = NULL;

// Returns a new pango font, free with pango_font_description_free().
PangoFontDescription* PangoFontFromGfxFont(const gfx::Font& gfx_font) {
  gfx::Font font = gfx_font;  // Copy so we can call non-const methods.
  PangoFontDescription* pfd = pango_font_description_new();
  pango_font_description_set_family(pfd, WideToUTF8(font.FontName()).c_str());
  pango_font_description_set_size(pfd, font.FontSize() * PANGO_SCALE);

  switch (font.style()) {
    case gfx::Font::NORMAL:
      // Nothing to do, should already be PANGO_STYLE_NORMAL.
      break;
    case gfx::Font::BOLD:
      pango_font_description_set_weight(pfd, PANGO_WEIGHT_BOLD);
      break;
    case gfx::Font::ITALIC:
      pango_font_description_set_style(pfd, PANGO_STYLE_ITALIC);
      break;
    case gfx::Font::UNDERLINED:
      // TODO(deanm): How to do underlined?  Where do we use it?  Probably have
      // to paint it ourselves, see pango_font_metrics_get_underline_position.
      break;
  }

  return pfd;
}

// Update |cairo_font_options| based on GtkSettings, allocating it if needed.
static void UpdateCairoFontOptions() {
  if (!cairo_font_options)
    cairo_font_options = cairo_font_options_create();

  GtkSettings* gtk_settings = gtk_settings_get_default();
  gint antialias = 0;
  gint hinting = 0;
  gchar* hint_style = NULL;
  gchar* rgba_style = NULL;
  g_object_get(gtk_settings,
               "gtk-xft-antialias", &antialias,
               "gtk-xft-hinting", &hinting,
               "gtk-xft-hintstyle", &hint_style,
               "gtk-xft-rgba", &rgba_style,
               NULL);

  // g_object_get() doesn't tell us whether the properties were present or not,
  // but if they aren't (because gnome-settings-daemon isn't running), we'll get
  // NULL values for the strings.
  if (hint_style && rgba_style) {
    if (!antialias) {
      cairo_font_options_set_antialias(cairo_font_options,
                                       CAIRO_ANTIALIAS_NONE);
    } else if (strcmp(rgba_style, "none") == 0) {
      cairo_font_options_set_antialias(cairo_font_options,
                                       CAIRO_ANTIALIAS_GRAY);
    } else {
      cairo_font_options_set_antialias(cairo_font_options,
                                       CAIRO_ANTIALIAS_SUBPIXEL);
      cairo_subpixel_order_t cairo_subpixel_order =
          CAIRO_SUBPIXEL_ORDER_DEFAULT;
      if (strcmp(rgba_style, "rgb") == 0) {
        cairo_subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
      } else if (strcmp(rgba_style, "bgr") == 0) {
        cairo_subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
      } else if (strcmp(rgba_style, "vrgb") == 0) {
        cairo_subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
      } else if (strcmp(rgba_style, "vbgr") == 0) {
        cairo_subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
      }
      cairo_font_options_set_subpixel_order(cairo_font_options,
                                            cairo_subpixel_order);
    }

    cairo_hint_style_t cairo_hint_style = CAIRO_HINT_STYLE_DEFAULT;
    if (hinting == 0 || strcmp(hint_style, "hintnone") == 0) {
      cairo_hint_style = CAIRO_HINT_STYLE_NONE;
    } else if (strcmp(hint_style, "hintslight") == 0) {
      cairo_hint_style = CAIRO_HINT_STYLE_SLIGHT;
    } else if (strcmp(hint_style, "hintmedium") == 0) {
      cairo_hint_style = CAIRO_HINT_STYLE_MEDIUM;
    } else if (strcmp(hint_style, "hintfull") == 0) {
      cairo_hint_style = CAIRO_HINT_STYLE_FULL;
    }
    cairo_font_options_set_hint_style(cairo_font_options, cairo_hint_style);
  }

  if (hint_style)
    g_free(hint_style);
  if (rgba_style)
    g_free(rgba_style);
}

}  // namespace

namespace gfx {

Canvas::Canvas(int width, int height, bool is_opaque)
    : skia::PlatformCanvas(width, height, is_opaque) {
}

Canvas::Canvas() : skia::PlatformCanvas() {
}

Canvas::~Canvas() {
}

// static
void Canvas::SizeStringInt(const std::wstring& text,
                           const gfx::Font& font,
                           int* width, int* height, int flags) {
  cairo_surface_t* surface =
      cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
  cairo_t* cr = cairo_create(surface);
  PangoLayout* layout = pango_cairo_create_layout(cr);

  if (flags & NO_ELLIPSIS) {
    pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
  } else {
    pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
  }

  if (flags & TEXT_ALIGN_CENTER) {
    pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
  } else if (flags & TEXT_ALIGN_RIGHT) {
    pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
  }

  if (flags & MULTI_LINE) {
    pango_layout_set_wrap(layout,
        (flags & CHARACTER_BREAK) ? PANGO_WRAP_WORD_CHAR : PANGO_WRAP_WORD);
  }

  std::string utf8 = WideToUTF8(text);
  pango_layout_set_text(layout, utf8.data(), utf8.size());
  PangoFontDescription* desc = PangoFontFromGfxFont(font);
  pango_layout_set_font_description(layout, desc);

  pango_layout_get_size(layout, width, height);
  *width /= PANGO_SCALE;
  *height /= PANGO_SCALE;
  g_object_unref(layout);
  pango_font_description_free(desc);
  cairo_destroy(cr);
  cairo_surface_destroy(surface);
}

void Canvas::DrawStringInt(const std::wstring& text,
                           const gfx::Font& font,
                           const SkColor& color, int x, int y, int w, int h,
                           int flags) {
  cairo_t* cr = beginPlatformPaint();
  PangoLayout* layout = pango_cairo_create_layout(cr);

  if (!cairo_font_options)
    UpdateCairoFontOptions();
  // This needs to be done early on; it has no effect when called just before
  // pango_cairo_show_layout().
  pango_cairo_context_set_font_options(
      pango_layout_get_context(layout), cairo_font_options);

  // Callers of DrawStringInt handle RTL layout themselves, so tell pango to not
  // scope out RTL characters.
  pango_layout_set_auto_dir(layout, FALSE);

  cairo_set_source_rgb(cr,
                       SkColorGetR(color) / 255.0,
                       SkColorGetG(color) / 255.0,
                       SkColorGetB(color) / 255.0);

  // TODO(deanm): Implement the rest of the Canvas flags.
  if (!(flags & Canvas::NO_ELLIPSIS))
    pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);

  pango_layout_set_width(layout, w * PANGO_SCALE);
  pango_layout_set_height(layout, h * PANGO_SCALE);

  if (flags & TEXT_ALIGN_CENTER) {
    pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
  } else if (flags & TEXT_ALIGN_RIGHT) {
    pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
  }

  if (flags & MULTI_LINE) {
    pango_layout_set_wrap(layout,
        (flags & CHARACTER_BREAK) ? PANGO_WRAP_WORD_CHAR : PANGO_WRAP_WORD);
  }

  if (flags & NO_ELLIPSIS)
    pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);

  std::string utf8 = WideToUTF8(text);
  pango_layout_set_text(layout, utf8.data(), utf8.size());

  PangoFontDescription* desc = PangoFontFromGfxFont(font);
  pango_layout_set_font_description(layout, desc);
  pango_font_description_free(desc);

  int width, height;
  pango_layout_get_size(layout, &width, &height);

  if (flags & Canvas::TEXT_VALIGN_TOP) {
    // Cairo should draw from the top left corner already.
  } else if (flags & Canvas::TEXT_VALIGN_BOTTOM) {
    y = y + (h - (height / PANGO_SCALE));
  } else {
    // Vertically centered.
    y = y + ((h - (height / PANGO_SCALE)) / 2);
  }

  cairo_move_to(cr, x, y);
  pango_cairo_show_layout(cr, layout);

  g_object_unref(layout);
  // NOTE: beginPlatformPaint returned its surface, we shouldn't destroy it.
}

}  // namespace gfx
<|endoftext|>