<commit_before>#include "nanocv.h"
#include "models/forward_network.h"
#include "task.h"
#include <boost/program_options.hpp>

namespace ncv
{
        class dummy_tast_t : public ncv::task_t
        {
        public:

                NANOCV_MAKE_CLONABLE(dummy_tast_t)

                // constructor
                dummy_tast_t(const string_t& = string_t())
                        :       task_t("test task")
                {
                }

                // create samples
                void resize(size_t samples)
                {
                        m_images.clear();
                        m_samples.clear();

                        for (size_t i = 0; i < samples; i ++)
                        {
                                sample_t sample(m_images.size(), sample_region(0, 0));
                                sample.m_label = "label";
                                sample.m_target = ncv::class_target(i % n_outputs(), n_outputs());
                                sample.m_fold = { 0, protocol::train };
                                m_samples.push_back(sample);

                                image_t image(n_rows(), n_cols(), color());
                                m_images.push_back(image);
                        }
                }

                // load images from the given directory
                virtual bool load(const string_t&) { return true; }

                // access functions
                virtual size_t n_rows() const { return 28; }
                virtual size_t n_cols() const { return 28; }
                virtual size_t n_outputs() const { return 10; }
                virtual size_t n_folds() const { return 1; }
                virtual color_mode color() const { return color_mode::luma; }
        };
}

int main(int argc, char *argv[])
{
        ncv::init();

        using namespace ncv;

        // parse the command line
        boost::program_options::options_description po_desc("", 160);
        po_desc.add_options()("help,h", "test program");
        po_desc.add_options()("threads,t",
                boost::program_options::value<size_t>()->default_value(1),
                "number of threads to use [1, 16], 0 - use all available threads");
        po_desc.add_options()("samples,s",
                boost::program_options::value<size_t>()->default_value(100000),
                "number of samples to use [1000, 100000]");
        po_desc.add_options()("forward",
                "evaluate the \'forward\' pass (output)");
        po_desc.add_options()("backward",
                "evaluate the \'backward' pass (gradient)");

        boost::program_options::variables_map po_vm;
        boost::program_options::store(
                boost::program_options::command_line_parser(argc, argv).options(po_desc).run(),
                po_vm);
        boost::program_options::notify(po_vm);

        // check arguments and options
        if (	po_vm.empty() ||
                po_vm.count("help"))
        {
                std::cout << po_desc;
                return EXIT_FAILURE;
        }

        const size_t cmd_threads = math::clamp(po_vm["threads"].as<size_t>(), 0, 16);
        const size_t cmd_samples = math::clamp(po_vm["samples"].as<size_t>(), 1000, 100 * 1000);
        const bool cmd_forward = po_vm.count("forward");
        const bool cmd_backward = po_vm.count("backward");

        if (!cmd_forward && !cmd_backward)
        {
                std::cout << po_desc;
                return EXIT_FAILURE;
        }

        dummy_tast_t task;
        task.resize(cmd_samples * 100);

        const size_t cmd_outputs = task.n_outputs();

        const string_t lmodel0;
        const string_t lmodel1 = lmodel0 + "linear:dims=128;act-snorm;";
        const string_t lmodel2 = lmodel1 + "linear:dims=64;act-snorm;";
        const string_t lmodel3 = lmodel2 + "linear:dims=32;act-snorm;";
        const string_t lmodel4 = lmodel3 + "linear:dims=16;act-snorm;";
        const string_t lmodel5 = lmodel4 + "linear:dims=8;act-snorm;";

        string_t cmodel;
        cmodel = cmodel + "conv:dims=16,rows=6,cols=6;act-snorm;pool-max;";
        cmodel = cmodel + "conv:dims=32,rows=5,cols=5;act-snorm;pool-max;";
        cmodel = cmodel + "conv:dims=64,rows=4,cols=4;act-snorm;";

        const string_t outlayer = "linear:dims=" + text::to_string(cmd_outputs) + ";softmax:type=global;";

        strings_t cmd_networks =
        {
                lmodel0 + outlayer,
                lmodel1 + outlayer,
                lmodel2 + outlayer,
                lmodel3 + outlayer,
                lmodel4 + outlayer,
                lmodel5 + outlayer,
                cmodel + outlayer
        };

        const rloss_t rloss = loss_manager_t::instance().get("class-ratio");
        assert(rloss);
        const loss_t& loss = *rloss;

        for (const string_t& cmd_network : cmd_networks)
        {
                log_info() << "<<< running network [" << cmd_network << "] ...";

                // create feed-forward network
                forward_network_t model(cmd_network);
                model.resize(task, true);

                // select random samples
                samples_t samples;
                {
                        const ncv::timer_t timer;

                        sampler_t sampler(task);
                        sampler.setup(sampler_t::stype::uniform, cmd_samples).setup(sampler_t::atype::annotated);

                        samples = sampler.get();

                        log_info() << "<<< selected [" << samples.size() << "] random samples in " << timer.elapsed() << ".";
                }

                // simulate parameter loading & saving
                {
                        const ncv::timer_t timer;

                        vector_t params(model.psize());

                        const size_t tests = 1024;
                        for (size_t t = 0; t < tests; t ++)
                        {
                                params = model.params();
                                model.load_params(params);
                        }

                        log_info() << "<<< loaded & saved " << tests << "x " << model.psize()
                                   << " parameters in " << timer.elapsed() << ".";
                }

                // process the samples
                if (cmd_forward)
                {
                        accumulator_t ldata(model, cmd_threads, "l2-reg", criterion_t::type::value, 0.1);

                        const ncv::timer_t timer;
                        ldata.update(task, samples, loss);

                        log_info() << "<<< processed [" << ldata.count() << "] forward samples in " << timer.elapsed() << ".";
                }

                if (cmd_backward)
                {
                        accumulator_t gdata(model, cmd_threads, "l2-reg", criterion_t::type::vgrad, 0.1);

                        const ncv::timer_t timer;
                        gdata.update(task, samples, loss);

                        log_info() << "<<< processed [" << gdata.count() << "] backward samples in " << timer.elapsed() << ".";
                }
        }

        // OK
        log_info() << done;
        return EXIT_SUCCESS;
}
<commit_msg>improve logging<commit_after>#include "nanocv.h"
#include "models/forward_network.h"
#include "task.h"
#include <boost/program_options.hpp>

namespace ncv
{
        class dummy_tast_t : public ncv::task_t
        {
        public:

                NANOCV_MAKE_CLONABLE(dummy_tast_t)

                // constructor
                dummy_tast_t(const string_t& = string_t())
                        :       task_t("test task")
                {
                }

                // create samples
                void resize(size_t samples)
                {
                        m_images.clear();
                        m_samples.clear();

                        for (size_t i = 0; i < samples; i ++)
                        {
                                sample_t sample(m_images.size(), sample_region(0, 0));
                                sample.m_label = "label";
                                sample.m_target = ncv::class_target(i % n_outputs(), n_outputs());
                                sample.m_fold = { 0, protocol::train };
                                m_samples.push_back(sample);

                                image_t image(n_rows(), n_cols(), color());
                                m_images.push_back(image);
                        }
                }

                // load images from the given directory
                virtual bool load(const string_t&) { return true; }

                // access functions
                virtual size_t n_rows() const { return 28; }
                virtual size_t n_cols() const { return 28; }
                virtual size_t n_outputs() const { return 10; }
                virtual size_t n_folds() const { return 1; }
                virtual color_mode color() const { return color_mode::luma; }
        };
}

int main(int argc, char *argv[])
{
        ncv::init();

        using namespace ncv;

        // parse the command line
        boost::program_options::options_description po_desc("", 160);
        po_desc.add_options()("help,h", "test program");
        po_desc.add_options()("threads,t",
                boost::program_options::value<size_t>()->default_value(1),
                "number of threads to use [1, 16], 0 - use all available threads");
        po_desc.add_options()("samples,s",
                boost::program_options::value<size_t>()->default_value(100000),
                "number of samples to use [1000, 100000]");
        po_desc.add_options()("forward",
                "evaluate the \'forward\' pass (output)");
        po_desc.add_options()("backward",
                "evaluate the \'backward' pass (gradient)");

        boost::program_options::variables_map po_vm;
        boost::program_options::store(
                boost::program_options::command_line_parser(argc, argv).options(po_desc).run(),
                po_vm);
        boost::program_options::notify(po_vm);

        // check arguments and options
        if (	po_vm.empty() ||
                po_vm.count("help"))
        {
                std::cout << po_desc;
                return EXIT_FAILURE;
        }

        const size_t cmd_threads = math::clamp(po_vm["threads"].as<size_t>(), 0, 16);
        const size_t cmd_samples = math::clamp(po_vm["samples"].as<size_t>(), 1000, 100 * 1000);
        const bool cmd_forward = po_vm.count("forward");
        const bool cmd_backward = po_vm.count("backward");

        if (!cmd_forward && !cmd_backward)
        {
                std::cout << po_desc;
                return EXIT_FAILURE;
        }

        dummy_tast_t task;
        task.resize(cmd_samples * 100);

        const size_t cmd_outputs = task.n_outputs();

        const string_t lmodel0;
        const string_t lmodel1 = lmodel0 + "linear:dims=128;act-snorm;";
        const string_t lmodel2 = lmodel1 + "linear:dims=64;act-snorm;";
        const string_t lmodel3 = lmodel2 + "linear:dims=32;act-snorm;";
        const string_t lmodel4 = lmodel3 + "linear:dims=16;act-snorm;";
        const string_t lmodel5 = lmodel4 + "linear:dims=8;act-snorm;";

        string_t cmodel;
        cmodel = cmodel + "conv:dims=16,rows=6,cols=6;act-snorm;pool-max;";
        cmodel = cmodel + "conv:dims=32,rows=5,cols=5;act-snorm;pool-max;";
        cmodel = cmodel + "conv:dims=64,rows=4,cols=4;act-snorm;";

        const string_t outlayer = "linear:dims=" + text::to_string(cmd_outputs) + ";softmax:type=global;";

        strings_t cmd_networks =
        {
                lmodel0 + outlayer,
                lmodel1 + outlayer,
                lmodel2 + outlayer,
                lmodel3 + outlayer,
                lmodel4 + outlayer,
                lmodel5 + outlayer,
                cmodel + outlayer
        };

        const rloss_t rloss = loss_manager_t::instance().get("class-ratio");
        assert(rloss);
        const loss_t& loss = *rloss;

        for (const string_t& cmd_network : cmd_networks)
        {
                log_info() << "<<< running network [" << cmd_network << "] ...";

                // create feed-forward network
                forward_network_t model(cmd_network);
                model.resize(task, true);

                // select random samples
                samples_t samples;
                {
                        const ncv::timer_t timer;

                        sampler_t sampler(task);
                        sampler.setup(sampler_t::stype::uniform, cmd_samples).setup(sampler_t::atype::annotated);

                        samples = sampler.get();

                        log_info() << "<<< selected [" << samples.size() << "] random samples in " << timer.elapsed() << ".";
                }

                // simulate parameter loading & saving
                {
                        const ncv::timer_t timer;

                        vector_t params(model.psize());

                        const size_t tests = 1024;
                        for (size_t t = 0; t < tests; t ++)
                        {
                                params = model.params();
                                model.load_params(params);
                        }

                        log_info() << "<<< loaded & saved " << tests << "x " << model.psize()
                                   << " parameters in " << timer.elapsed() << ".";
                }

                // process the samples
                if (cmd_forward)
                {
                        accumulator_t ldata(model, cmd_threads, "l2-reg", criterion_t::type::value, 0.1);

                        const ncv::timer_t timer;
                        ldata.update(task, samples, loss);

                        log_info() << "<<< processed [" << ldata.count() << "] forward samples in " << timer.elapsed() << ".";
                }

                if (cmd_backward)
                {
                        accumulator_t gdata(model, cmd_threads, "l2-reg", criterion_t::type::vgrad, 0.1);

                        const ncv::timer_t timer;
                        gdata.update(task, samples, loss);

                        log_info() << "<<< processed [" << gdata.count() << "] backward samples in " << timer.elapsed() << ".";
                }

                log_info();
        }

        // OK
        log_info() << done;
        return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "ops.h"
#include "common.h"
#include "sim.h"
#include "asmjit/asmjit.h"
#include <cassert>
#include <search.h>

using namespace asmjit;

typedef void Block(void *cookie, int32_t *registers);

struct jit_state {
    void *nested_run_data;
    void *sim_state;
    JitRuntime *runtime;
    int run_count_threshold;
};

struct ops_state {
    struct jit_state *js;
    struct run_ops ops;
    void *nested_ops_data;
    void *basic_blocks;
    struct basic_block *curr_bb;
};

struct basic_block {
    int run_count;
    unsigned complete;
    int32_t base;
    uint32_t len;
    Block *compiled;
    int32_t *cache;
};

extern "C" void jit_init(struct jit_state **state)
{
    struct jit_state *s = *state = new jit_state;
    s->runtime = new JitRuntime;
    s->run_count_threshold = 10; // arbitrary, reconfigurable
}

extern "C" void jit_fini(struct jit_state *state)
{
    delete state->runtime;
    delete state;
}

// XXX permit fetch to express failure
static int32_t fetch(void *cookie, int32_t addr)
{
    struct sim_state *s = (struct sim_state*)cookie;
    int32_t data;
    s->dispatch_op(s, OP_DATA_READ, addr, (uint32_t*)&data);
    return data;
}

static void store(void *cookie, int32_t addr, int32_t value)
{
    struct sim_state *s = (struct sim_state*)cookie;
    s->dispatch_op(s, OP_WRITE, addr, (uint32_t*)&value);
}

static const FuncPrototype store_proto = FuncBuilder3<void   , void *, int32_t, int32_t>();
static const FuncPrototype fetch_proto = FuncBuilder2<int32_t, void *, int32_t         >();

static inline void create_store(X86Compiler &cc, X86GpVar &cookie, X86GpVar &addr, X86GpVar &data)
{
    X86CallNode *call = cc.call(imm_ptr((void*)store), kFuncConvHost, store_proto);
    call->setArg(0, cookie);
    call->setArg(1, addr);
    call->setArg(2, data);
}

static inline void create_fetch(X86Compiler &cc, X86GpVar &cookie, X86GpVar &addr, X86GpVar &data)
{
    X86CallNode *call = cc.call(imm_ptr((void*)fetch), kFuncConvHost, fetch_proto);
    call->setArg(0, cookie);
    call->setArg(1, addr);
    call->setRet(0, data);
}

static void buildOp(X86Compiler &cc, int op, X86GpVar &T, X86GpVar &A, X86GpVar &B, X86GpVar &C)
{
    switch (op) {
        case OP_ADD             : cc.add (A, B);    break;
        case OP_SUBTRACT        : cc.sub (A, B);    break;
        case OP_BITWISE_ANDN    : cc.not_(B);       /* FALLTHROUGH */
        case OP_BITWISE_AND     : cc.and_(A, B);    break;
        case OP_BITWISE_ORN     : cc.not_(B);       /* FALLTHROUGH */
        case OP_BITWISE_OR      : cc.or_ (A, B);    break;
        case OP_BITWISE_XOR     : cc.xor_(A, B);    break;
        case OP_MULTIPLY        : cc.imul(A, B);    break;

        case OP_SHIFT_RIGHT_LOGIC:
            cc.shr   (A, B);
            cc.and_  (B, Imm(~31));
            cc.mov   (T, Imm(0));
            cc.cmovnz(A, T);            // zeros if shift-amount is larger than 31
            break;
        case OP_SHIFT_RIGHT_ARITH:
            cc.mov   (T, B);
            cc.and_  (T, Imm(~31));
            cc.mov   (T, 31);
            cc.cmovnz(B, T);            // convert to a shift by 31 if > 31
            cc.sar   (A, B);
            break;
        case OP_SHIFT_LEFT:
            cc.sal   (A, B);
            cc.and_  (B, Imm(~31));
            cc.mov   (T, Imm(0));
            cc.cmovnz(A, T);            // zeros if shift-amount is larger than 31
            break;

        case OP_PACK:
            cc.shl (A, Imm(12));
            cc.and_(B, Imm(0xfff));
            cc.or_ (A, B);
            break;

        case OP_TEST_BIT:
            cc.bt (A, B);
            cc.mov(A, Imm(0));
            cc.sbb(A, A);
            break;

        case OP_COMPARE_LT: /* FALLTHROUGH */
        case OP_COMPARE_EQ: /* FALLTHROUGH */
        case OP_COMPARE_GE:
            cc.mov(T, Imm(-1));
            cc.cmp(A, B);
            cc.mov(A, Imm(0)); // don't use xor, it clears the flags we need
            switch (op) {
                case OP_COMPARE_LT: cc.cmovl (A, T); break;
                case OP_COMPARE_EQ: cc.cmove (A, T); break;
                case OP_COMPARE_GE: cc.cmovge(A, T); break;
            }
            break;

        default:
            assert(!"Bad op");
    }
}

static int buildInstruction(X86Compiler &cc, X86GpVar &ck, X86GpVar &regs,
        const int32_t &instruction, int32_t offset)
{
    X86GpVar *a = NULL, *b = NULL, *c = NULL;
    X86GpVar tmp(cc, kVarTypeInt32, "tmp"),
               x(cc, kVarTypeInt32, "x"),
               y(cc, kVarTypeInt32, "y"),
               i(cc, kVarTypeInt32, "i");

    union insn_or_data::insn &u = *(union insn_or_data::insn *)&instruction;
    struct insn_or_data::insn::instruction_type012 &t = u.type012;
    struct insn_or_data::insn::instruction_type3   &v = u.type3;
    int op = t.op;

#define Reg(N) (X86Mem(regs, 4*(N), 0))

    if (t.x) {
        cc.mov(x, Reg(t.x));
        if (t.x == 15)
            cc.add(x, Imm(offset + 1));
    } else {
        cc.xor_(x, x);
    }

    if (t.p == 3) {
        a = &x;
        cc.add(*a, Imm(SEXTEND32(MEDIUM_IMMEDIATE_BITWIDTH,v.imm)));
    } else {
        if (t.y) {
            cc.mov(y, Reg(t.y));
            if (t.y == 15)
                cc.add(y, Imm(offset + 1));
        } else {
            cc.xor_(y, y);
        }
        cc.mov(i, Imm(SEXTEND32(SMALL_IMMEDIATE_BITWIDTH,t.imm)));

        switch (t.p) {
            case 0: a = &x; b = &y; c = &i; break;
            case 1: a = &x; b = &i; c = &y; break;
            case 2: a = &i; b = &x; c = &y; break;
        }

        buildOp(cc, op, tmp, *a, *b, *c);
        cc.add(*a, *c);
    }

    // TODO don't store registers until we need to
    // TODO don't do operations that are identity operations with *a
    // TODO don't load registers unless necessary

    switch (t.dd) {
        case 0:                                if (t.z) cc.mov(Reg(t.z),  *a); break;
        case 1: cc.mov(tmp, Reg(t.z));         create_store(cc, ck,  *a, tmp); break;
        case 2: cc.mov(tmp, Reg(t.z));         create_store(cc, ck,  tmp, *a); break;
        case 3: create_fetch(cc, ck, *a, tmp); if (t.z) cc.mov(Reg(t.z), tmp); break;
    }

    return t.z == 15;
}

extern "C" Block *jit_gen_block(void *cookie, int len, int32_t *instructions)
{
    struct jit_state *js = (struct jit_state*)cookie;
    X86Compiler c(js->runtime);

    c.addFunc(kFuncConvHost, FuncBuilder2<void, void*, int32_t*>());

    X86GpVar ck  (c, kVarTypeUIntPtr, "cookie");
    X86GpVar regs(c, kVarTypeUIntPtr, "regs");
    c.setArg(0, ck);
    c.setArg(1, regs);

    for (int i = 0; i < len; i++)
        buildInstruction(c, ck, regs, instructions[i], i);

    c.endFunc();

    return (Block*)c.make();
}

static int bb_by_base(const void *a_, const void *b_)
{
    struct basic_block *a = (struct basic_block*)a_,
                       *b = (struct basic_block*)b_;

    return a->base - b->base;
}

static int pre_insn_hook(struct sim_state *s, struct element *i, void *ud)
{
    struct ops_state *o = (struct ops_state*)ud;
    if (!o->curr_bb) {
        struct basic_block nb = { 0, 0, i->insn.reladdr, 0, NULL, NULL };
        struct basic_block **f = (struct basic_block**)tsearch(&nb, &o->basic_blocks, bb_by_base);
        if (*f == &nb) {
            *f = (struct basic_block *)malloc(sizeof **f);
            **f = nb;
        }
        o->curr_bb = *f;
    }

    struct basic_block &bb = *o->curr_bb;
    if (bb.compiled)
        return 1; // indicate to jit_run_sim that JIT should be used

    if (bb.run_count == o->js->run_count_threshold) {
        // Cache the instructions we receive so they are ready for compilation
        if (!bb.cache)
            bb.cache = new int32_t[bb.len];
        bb.cache[(uint32_t)i->insn.reladdr - (uint32_t)bb.base] = i->insn.u.word;
    } else if (bb.run_count > o->js->run_count_threshold) {
        assert(bb.complete);
        bb.compiled = jit_gen_block(o->js, bb.len, bb.cache);
        delete [] bb.cache;
        return 1; // indicate to jit_run_sim that JIT should be used
    }

    return o->ops.pre_insn(s, i, o->nested_ops_data);
}

static int post_insn_hook(struct sim_state *s, struct element *i, void *ud)
{
    struct ops_state *o = (struct ops_state*)ud;

    int dd = i->insn.u.typeany.dd;
    if ((dd == 0 || dd == 3) && i->insn.u.typeany.z == 0xf) { // P is being updated
        struct basic_block &bb = *o->curr_bb;
        bb.len = (uint32_t)i->insn.reladdr - (uint32_t)bb.base + 1;
        bb.complete = 1;
        bb.run_count++;
        o->curr_bb = NULL;
        o->ops.post_insn(s, i, o->nested_ops_data); // allow hook to run one last time
        return 1;
    }

    return o->ops.post_insn(s, i, o->nested_ops_data);
}

extern "C" int jit_run_sim(struct sim_state *s, struct run_ops *ops, void **run_data, void *ops_data)
{
    struct jit_state *js;
    jit_init(&js);
    *run_data = js;
    js->sim_state = s;

    const void *val = NULL;
    if (param_get(s->conf.params, "tsim.jit.run_count_threshold", 1, &val)) {
        char *next;
        int v = strtol((char*)val, &next, 0);
        if (next != val && *next == '\0' && v > 1)
            js->run_count_threshold = v;
    }

    struct ops_state ops_state = { 0 }, *o = &ops_state;
    o->js = js;
    o->ops.pre_insn = ops->pre_insn;
    o->ops.post_insn = ops->post_insn;
    o->nested_ops_data = ops_data;

    struct run_ops wrappers = { 0 };
    wrappers.pre_insn = pre_insn_hook;
    wrappers.post_insn = post_insn_hook;

    typedef int dispatch_cycle(struct sim_state *s);
    dispatch_cycle *pump = (dispatch_cycle*)dlsym(RTLD_DEFAULT, "devices_dispatch_cycle");
    sim_runner *interp = (sim_runner*)dlsym(RTLD_DEFAULT, "interp_run_sim");
    if (!interp || !pump)
        fatal(PRINT_ERRNO, "Failed to find interpreter");

    int rc = 0;
    do {
        if (o->curr_bb && o->curr_bb->compiled) {
            o->curr_bb->compiled(s, s->machine.regs);
            s->insns_executed += o->curr_bb->len;
            o->curr_bb->run_count++;
            o->curr_bb = NULL;
        }
        rc = interp(s, &wrappers, &js->nested_run_data, o);
        pump(s); // no longer a "cycle" but periodic
    } while (rc >= 0);

    jit_fini(js);
    return 0;
}

<commit_msg>Keep around one compiler for life of JIT<commit_after>#include "ops.h"
#include "common.h"
#include "sim.h"
#include "asmjit/asmjit.h"
#include <cassert>
#include <search.h>

using namespace asmjit;

typedef void Block(void *cookie, int32_t *registers);

struct jit_state {
    void *nested_run_data;
    void *sim_state;
    JitRuntime *runtime;
    int run_count_threshold;
    X86Compiler *cc;
};

struct ops_state {
    struct jit_state *js;
    struct run_ops ops;
    void *nested_ops_data;
    void *basic_blocks;
    struct basic_block *curr_bb;
};

struct basic_block {
    int run_count;
    unsigned complete;
    int32_t base;
    uint32_t len;
    Block *compiled;
    int32_t *cache;
};

extern "C" void jit_init(struct jit_state **state)
{
    struct jit_state *s = *state = new jit_state;
    s->runtime = new JitRuntime;
    s->run_count_threshold = 10; // arbitrary, reconfigurable
    s->cc = new X86Compiler(s->runtime);
}

extern "C" void jit_fini(struct jit_state *state)
{
    delete state->cc;
    delete state->runtime;
    delete state;
}

// XXX permit fetch to express failure
static int32_t fetch(void *cookie, int32_t addr)
{
    struct sim_state *s = (struct sim_state*)cookie;
    int32_t data;
    s->dispatch_op(s, OP_DATA_READ, addr, (uint32_t*)&data);
    return data;
}

static void store(void *cookie, int32_t addr, int32_t value)
{
    struct sim_state *s = (struct sim_state*)cookie;
    s->dispatch_op(s, OP_WRITE, addr, (uint32_t*)&value);
}

static const FuncPrototype store_proto = FuncBuilder3<void   , void *, int32_t, int32_t>();
static const FuncPrototype fetch_proto = FuncBuilder2<int32_t, void *, int32_t         >();

static inline void create_store(X86Compiler &cc, X86GpVar &cookie, X86GpVar &addr, X86GpVar &data)
{
    X86CallNode *call = cc.call(imm_ptr((void*)store), kFuncConvHost, store_proto);
    call->setArg(0, cookie);
    call->setArg(1, addr);
    call->setArg(2, data);
}

static inline void create_fetch(X86Compiler &cc, X86GpVar &cookie, X86GpVar &addr, X86GpVar &data)
{
    X86CallNode *call = cc.call(imm_ptr((void*)fetch), kFuncConvHost, fetch_proto);
    call->setArg(0, cookie);
    call->setArg(1, addr);
    call->setRet(0, data);
}

static void buildOp(X86Compiler &cc, int op, X86GpVar &T, X86GpVar &A, X86GpVar &B, X86GpVar &C)
{
    switch (op) {
        case OP_ADD             : cc.add (A, B);    break;
        case OP_SUBTRACT        : cc.sub (A, B);    break;
        case OP_BITWISE_ANDN    : cc.not_(B);       /* FALLTHROUGH */
        case OP_BITWISE_AND     : cc.and_(A, B);    break;
        case OP_BITWISE_ORN     : cc.not_(B);       /* FALLTHROUGH */
        case OP_BITWISE_OR      : cc.or_ (A, B);    break;
        case OP_BITWISE_XOR     : cc.xor_(A, B);    break;
        case OP_MULTIPLY        : cc.imul(A, B);    break;

        case OP_SHIFT_RIGHT_LOGIC:
            cc.shr   (A, B);
            cc.and_  (B, Imm(~31));
            cc.mov   (T, Imm(0));
            cc.cmovnz(A, T);            // zeros if shift-amount is larger than 31
            break;
        case OP_SHIFT_RIGHT_ARITH:
            cc.mov   (T, B);
            cc.and_  (T, Imm(~31));
            cc.mov   (T, 31);
            cc.cmovnz(B, T);            // convert to a shift by 31 if > 31
            cc.sar   (A, B);
            break;
        case OP_SHIFT_LEFT:
            cc.sal   (A, B);
            cc.and_  (B, Imm(~31));
            cc.mov   (T, Imm(0));
            cc.cmovnz(A, T);            // zeros if shift-amount is larger than 31
            break;

        case OP_PACK:
            cc.shl (A, Imm(12));
            cc.and_(B, Imm(0xfff));
            cc.or_ (A, B);
            break;

        case OP_TEST_BIT:
            cc.bt (A, B);
            cc.mov(A, Imm(0));
            cc.sbb(A, A);
            break;

        case OP_COMPARE_LT: /* FALLTHROUGH */
        case OP_COMPARE_EQ: /* FALLTHROUGH */
        case OP_COMPARE_GE:
            cc.mov(T, Imm(-1));
            cc.cmp(A, B);
            cc.mov(A, Imm(0)); // don't use xor, it clears the flags we need
            switch (op) {
                case OP_COMPARE_LT: cc.cmovl (A, T); break;
                case OP_COMPARE_EQ: cc.cmove (A, T); break;
                case OP_COMPARE_GE: cc.cmovge(A, T); break;
            }
            break;

        default:
            assert(!"Bad op");
    }
}

static int buildInstruction(X86Compiler &cc, X86GpVar &ck, X86GpVar &regs,
        const int32_t &instruction, int32_t offset)
{
    X86GpVar *a = NULL, *b = NULL, *c = NULL;
    X86GpVar tmp(cc, kVarTypeInt32, "tmp"),
               x(cc, kVarTypeInt32, "x"),
               y(cc, kVarTypeInt32, "y"),
               i(cc, kVarTypeInt32, "i");

    union insn_or_data::insn &u = *(union insn_or_data::insn *)&instruction;
    struct insn_or_data::insn::instruction_type012 &t = u.type012;
    struct insn_or_data::insn::instruction_type3   &v = u.type3;
    int op = t.op;

#define Reg(N) (X86Mem(regs, 4*(N), 0))

    if (t.x) {
        cc.mov(x, Reg(t.x));
        if (t.x == 15)
            cc.add(x, Imm(offset + 1));
    } else {
        cc.xor_(x, x);
    }

    if (t.p == 3) {
        a = &x;
        cc.add(*a, Imm(SEXTEND32(MEDIUM_IMMEDIATE_BITWIDTH,v.imm)));
    } else {
        if (t.y) {
            cc.mov(y, Reg(t.y));
            if (t.y == 15)
                cc.add(y, Imm(offset + 1));
        } else {
            cc.xor_(y, y);
        }
        cc.mov(i, Imm(SEXTEND32(SMALL_IMMEDIATE_BITWIDTH,t.imm)));

        switch (t.p) {
            case 0: a = &x; b = &y; c = &i; break;
            case 1: a = &x; b = &i; c = &y; break;
            case 2: a = &i; b = &x; c = &y; break;
        }

        buildOp(cc, op, tmp, *a, *b, *c);
        cc.add(*a, *c);
    }

    // TODO don't store registers until we need to
    // TODO don't do operations that are identity operations with *a
    // TODO don't load registers unless necessary

    switch (t.dd) {
        case 0:                                if (t.z) cc.mov(Reg(t.z),  *a); break;
        case 1: cc.mov(tmp, Reg(t.z));         create_store(cc, ck,  *a, tmp); break;
        case 2: cc.mov(tmp, Reg(t.z));         create_store(cc, ck,  tmp, *a); break;
        case 3: create_fetch(cc, ck, *a, tmp); if (t.z) cc.mov(Reg(t.z), tmp); break;
    }

    return t.z == 15;
}

extern "C" Block *jit_gen_block(void *cookie, int len, int32_t *instructions)
{
    struct jit_state *js = (struct jit_state*)cookie;
    X86Compiler &c = *js->cc;

    c.addFunc(kFuncConvHost, FuncBuilder2<void, void*, int32_t*>());

    X86GpVar ck  (c, kVarTypeUIntPtr, "cookie");
    X86GpVar regs(c, kVarTypeUIntPtr, "regs");
    c.setArg(0, ck);
    c.setArg(1, regs);

    for (int i = 0; i < len; i++)
        buildInstruction(c, ck, regs, instructions[i], i);

    c.endFunc();

    return (Block*)c.make();
}

static int bb_by_base(const void *a_, const void *b_)
{
    struct basic_block *a = (struct basic_block*)a_,
                       *b = (struct basic_block*)b_;

    return a->base - b->base;
}

static int pre_insn_hook(struct sim_state *s, struct element *i, void *ud)
{
    struct ops_state *o = (struct ops_state*)ud;
    if (!o->curr_bb) {
        struct basic_block nb = { 0, 0, i->insn.reladdr, 0, NULL, NULL };
        struct basic_block **f = (struct basic_block**)tsearch(&nb, &o->basic_blocks, bb_by_base);
        if (*f == &nb) {
            *f = (struct basic_block *)malloc(sizeof **f);
            **f = nb;
        }
        o->curr_bb = *f;
    }

    struct basic_block &bb = *o->curr_bb;
    if (bb.compiled)
        return 1; // indicate to jit_run_sim that JIT should be used

    if (bb.run_count == o->js->run_count_threshold) {
        // Cache the instructions we receive so they are ready for compilation
        if (!bb.cache)
            bb.cache = new int32_t[bb.len];
        bb.cache[(uint32_t)i->insn.reladdr - (uint32_t)bb.base] = i->insn.u.word;
    } else if (bb.run_count > o->js->run_count_threshold) {
        assert(bb.complete);
        bb.compiled = jit_gen_block(o->js, bb.len, bb.cache);
        delete [] bb.cache;
        return 1; // indicate to jit_run_sim that JIT should be used
    }

    return o->ops.pre_insn(s, i, o->nested_ops_data);
}

static int post_insn_hook(struct sim_state *s, struct element *i, void *ud)
{
    struct ops_state *o = (struct ops_state*)ud;

    int dd = i->insn.u.typeany.dd;
    if ((dd == 0 || dd == 3) && i->insn.u.typeany.z == 0xf) { // P is being updated
        struct basic_block &bb = *o->curr_bb;
        bb.len = (uint32_t)i->insn.reladdr - (uint32_t)bb.base + 1;
        bb.complete = 1;
        bb.run_count++;
        o->curr_bb = NULL;
        o->ops.post_insn(s, i, o->nested_ops_data); // allow hook to run one last time
        return 1;
    }

    return o->ops.post_insn(s, i, o->nested_ops_data);
}

extern "C" int jit_run_sim(struct sim_state *s, struct run_ops *ops, void **run_data, void *ops_data)
{
    struct jit_state *js;
    jit_init(&js);
    *run_data = js;
    js->sim_state = s;

    const void *val = NULL;
    if (param_get(s->conf.params, "tsim.jit.run_count_threshold", 1, &val)) {
        char *next;
        int v = strtol((char*)val, &next, 0);
        if (next != val && *next == '\0' && v > 1)
            js->run_count_threshold = v;
    }

    struct ops_state ops_state = { 0 }, *o = &ops_state;
    o->js = js;
    o->ops.pre_insn = ops->pre_insn;
    o->ops.post_insn = ops->post_insn;
    o->nested_ops_data = ops_data;

    struct run_ops wrappers = { 0 };
    wrappers.pre_insn = pre_insn_hook;
    wrappers.post_insn = post_insn_hook;

    typedef int dispatch_cycle(struct sim_state *s);
    dispatch_cycle *pump = (dispatch_cycle*)dlsym(RTLD_DEFAULT, "devices_dispatch_cycle");
    sim_runner *interp = (sim_runner*)dlsym(RTLD_DEFAULT, "interp_run_sim");
    if (!interp || !pump)
        fatal(PRINT_ERRNO, "Failed to find interpreter");

    int rc = 0;
    do {
        if (o->curr_bb && o->curr_bb->compiled) {
            o->curr_bb->compiled(s, s->machine.regs);
            s->insns_executed += o->curr_bb->len;
            o->curr_bb->run_count++;
            o->curr_bb = NULL;
        }
        rc = interp(s, &wrappers, &js->nested_run_data, o);
        pump(s); // no longer a "cycle" but periodic
    } while (rc >= 0);

    jit_fini(js);
    return 0;
}

<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@gmail.com>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "sparse.h"

template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& ref)
{
  typedef typename SparseMatrixType::Index Index;

  const Index rows = ref.rows();
  const Index cols = ref.cols();
  typedef typename SparseMatrixType::Scalar Scalar;
  enum { Flags = SparseMatrixType::Flags };

  double density = std::max(8./(rows*cols), 0.01);
  typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
  typedef Matrix<Scalar,Dynamic,1> DenseVector;
  Scalar eps = 1e-6;

  SparseMatrixType m(rows, cols);
  DenseMatrix refMat = DenseMatrix::Zero(rows, cols);
  DenseVector vec1 = DenseVector::Random(rows);
  Scalar s1 = internal::random<Scalar>();

  std::vector<Vector2i> zeroCoords;
  std::vector<Vector2i> nonzeroCoords;
  initSparse<Scalar>(density, refMat, m, 0, &zeroCoords, &nonzeroCoords);

  if (zeroCoords.size()==0 || nonzeroCoords.size()==0)
    return;

  // test coeff and coeffRef
  for (int i=0; i<(int)zeroCoords.size(); ++i)
  {
    VERIFY_IS_MUCH_SMALLER_THAN( m.coeff(zeroCoords[i].x(),zeroCoords[i].y()), eps );
    if(internal::is_same<SparseMatrixType,SparseMatrix<Scalar,Flags> >::value)
      VERIFY_RAISES_ASSERT( m.coeffRef(zeroCoords[0].x(),zeroCoords[0].y()) = 5 );
  }
  VERIFY_IS_APPROX(m, refMat);

  m.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
  refMat.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);

  VERIFY_IS_APPROX(m, refMat);
  /*
  // test InnerIterators and Block expressions
  for (int t=0; t<10; ++t)
  {
    int j = internal::random<int>(0,cols-1);
    int i = internal::random<int>(0,rows-1);
    int w = internal::random<int>(1,cols-j-1);
    int h = internal::random<int>(1,rows-i-1);

//     VERIFY_IS_APPROX(m.block(i,j,h,w), refMat.block(i,j,h,w));
    for(int c=0; c<w; c++)
    {
      VERIFY_IS_APPROX(m.block(i,j,h,w).col(c), refMat.block(i,j,h,w).col(c));
      for(int r=0; r<h; r++)
      {
//         VERIFY_IS_APPROX(m.block(i,j,h,w).col(c).coeff(r), refMat.block(i,j,h,w).col(c).coeff(r));
      }
    }
//     for(int r=0; r<h; r++)
//     {
//       VERIFY_IS_APPROX(m.block(i,j,h,w).row(r), refMat.block(i,j,h,w).row(r));
//       for(int c=0; c<w; c++)
//       {
//         VERIFY_IS_APPROX(m.block(i,j,h,w).row(r).coeff(c), refMat.block(i,j,h,w).row(r).coeff(c));
//       }
//     }
  }

  for(int c=0; c<cols; c++)
  {
    VERIFY_IS_APPROX(m.col(c) + m.col(c), (m + m).col(c));
    VERIFY_IS_APPROX(m.col(c) + m.col(c), refMat.col(c) + refMat.col(c));
  }

  for(int r=0; r<rows; r++)
  {
    VERIFY_IS_APPROX(m.row(r) + m.row(r), (m + m).row(r));
    VERIFY_IS_APPROX(m.row(r) + m.row(r), refMat.row(r) + refMat.row(r));
  }
  */

    // test insert (inner random)
    {
      DenseMatrix m1(rows,cols);
      m1.setZero();
      SparseMatrixType m2(rows,cols);
      m2.reserve(10);
      for (int j=0; j<cols; ++j)
      {
        for (int k=0; k<rows/2; ++k)
        {
          int i = internal::random<int>(0,rows-1);
          if (m1.coeff(i,j)==Scalar(0))
            m2.insert(i,j) = m1(i,j) = internal::random<Scalar>();
        }
      }
      m2.finalize();
      VERIFY_IS_APPROX(m2,m1);
    }

    // test insert (fully random)
    {
      DenseMatrix m1(rows,cols);
      m1.setZero();
      SparseMatrixType m2(rows,cols);
      m2.reserve(10);
      for (int k=0; k<rows*cols; ++k)
      {
        int i = internal::random<int>(0,rows-1);
        int j = internal::random<int>(0,cols-1);
        if (m1.coeff(i,j)==Scalar(0))
          m2.insert(i,j) = m1(i,j) = internal::random<Scalar>();
      }
      m2.finalize();
      VERIFY_IS_APPROX(m2,m1);
    }

  // test basic computations
  {
    DenseMatrix refM1 = DenseMatrix::Zero(rows, rows);
    DenseMatrix refM2 = DenseMatrix::Zero(rows, rows);
    DenseMatrix refM3 = DenseMatrix::Zero(rows, rows);
    DenseMatrix refM4 = DenseMatrix::Zero(rows, rows);
    SparseMatrixType m1(rows, rows);
    SparseMatrixType m2(rows, rows);
    SparseMatrixType m3(rows, rows);
    SparseMatrixType m4(rows, rows);
    initSparse<Scalar>(density, refM1, m1);
    initSparse<Scalar>(density, refM2, m2);
    initSparse<Scalar>(density, refM3, m3);
    initSparse<Scalar>(density, refM4, m4);

    VERIFY_IS_APPROX(m1+m2, refM1+refM2);
    VERIFY_IS_APPROX(m1+m2+m3, refM1+refM2+refM3);
    VERIFY_IS_APPROX(m3.cwiseProduct(m1+m2), refM3.cwiseProduct(refM1+refM2));
    VERIFY_IS_APPROX(m1*s1-m2, refM1*s1-refM2);

    VERIFY_IS_APPROX(m1*=s1, refM1*=s1);
    VERIFY_IS_APPROX(m1/=s1, refM1/=s1);

    VERIFY_IS_APPROX(m1+=m2, refM1+=refM2);
    VERIFY_IS_APPROX(m1-=m2, refM1-=refM2);

    VERIFY_IS_APPROX(m1.col(0).dot(refM2.row(0)), refM1.col(0).dot(refM2.row(0)));

    refM4.setRandom();
    // sparse cwise* dense
    VERIFY_IS_APPROX(m3.cwiseProduct(refM4), refM3.cwiseProduct(refM4));
//     VERIFY_IS_APPROX(m3.cwise()/refM4, refM3.cwise()/refM4);
  }

  // test transpose
  {
    DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
    SparseMatrixType m2(rows, rows);
    initSparse<Scalar>(density, refMat2, m2);
    VERIFY_IS_APPROX(m2.transpose().eval(), refMat2.transpose().eval());
    VERIFY_IS_APPROX(m2.transpose(), refMat2.transpose());

    VERIFY_IS_APPROX(SparseMatrixType(m2.adjoint()), refMat2.adjoint());
  }

  // test innerVector()
  {
    DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
    SparseMatrixType m2(rows, rows);
    initSparse<Scalar>(density, refMat2, m2);
    int j0 = internal::random(0,rows-1);
    int j1 = internal::random(0,rows-1);
    VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.col(j0));
    VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.col(j0)+refMat2.col(j1));
    //m2.innerVector(j0) = 2*m2.innerVector(j1);
    //refMat2.col(j0) = 2*refMat2.col(j1);
    //VERIFY_IS_APPROX(m2, refMat2);
  }

  // test innerVectors()
  {
    DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
    SparseMatrixType m2(rows, rows);
    initSparse<Scalar>(density, refMat2, m2);
    int j0 = internal::random(0,rows-2);
    int j1 = internal::random(0,rows-2);
    int n0 = internal::random<int>(1,rows-std::max(j0,j1));
    VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(0,j0,rows,n0));
    VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0),
                     refMat2.block(0,j0,rows,n0)+refMat2.block(0,j1,rows,n0));
    //m2.innerVectors(j0,n0) = m2.innerVectors(j0,n0) + m2.innerVectors(j1,n0);
    //refMat2.block(0,j0,rows,n0) = refMat2.block(0,j0,rows,n0) + refMat2.block(0,j1,rows,n0);
  }

  // test prune
  {
    SparseMatrixType m2(rows, rows);
    DenseMatrix refM2(rows, rows);
    refM2.setZero();
    int countFalseNonZero = 0;
    int countTrueNonZero = 0;
    for (int j=0; j<m2.outerSize(); ++j)
    {
      m2.startVec(j);
      for (int i=0; i<m2.innerSize(); ++i)
      {
        float x = internal::random<float>(0,1);
        if (x<0.1)
        {
          // do nothing
        }
        else if (x<0.5)
        {
          countFalseNonZero++;
          m2.insertBackByOuterInner(j,i) = Scalar(0);
        }
        else
        {
          countTrueNonZero++;
          m2.insertBackByOuterInner(j,i) = refM2(i,j) = Scalar(1);
        }
      }
    }
    m2.finalize();
    VERIFY(countFalseNonZero+countTrueNonZero == m2.nonZeros());
    VERIFY_IS_APPROX(m2, refM2);
    m2.prune(1);
    VERIFY(countTrueNonZero==m2.nonZeros());
    VERIFY_IS_APPROX(m2, refM2);
  }

  // test sparseView
  {
    DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
    SparseMatrixType m2(rows, rows);
    VERIFY_IS_APPROX(m2.eval(), refMat2.sparseView().eval());
  }
}

void test_sparse_basic()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( sparse_basic(SparseMatrix<double>(8, 8)) );
    CALL_SUBTEST_2( sparse_basic(SparseMatrix<std::complex<double> >(16, 16)) );
    CALL_SUBTEST_1( sparse_basic(SparseMatrix<double>(33, 33)) );

    CALL_SUBTEST_3( sparse_basic(DynamicSparseMatrix<double>(8, 8)) );
  }
}
<commit_msg>Additional fix to enforce the compiler to use the correct prunning method.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@gmail.com>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "sparse.h"

template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& ref)
{
  typedef typename SparseMatrixType::Index Index;

  const Index rows = ref.rows();
  const Index cols = ref.cols();
  typedef typename SparseMatrixType::Scalar Scalar;
  enum { Flags = SparseMatrixType::Flags };

  double density = std::max(8./(rows*cols), 0.01);
  typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
  typedef Matrix<Scalar,Dynamic,1> DenseVector;
  Scalar eps = 1e-6;

  SparseMatrixType m(rows, cols);
  DenseMatrix refMat = DenseMatrix::Zero(rows, cols);
  DenseVector vec1 = DenseVector::Random(rows);
  Scalar s1 = internal::random<Scalar>();

  std::vector<Vector2i> zeroCoords;
  std::vector<Vector2i> nonzeroCoords;
  initSparse<Scalar>(density, refMat, m, 0, &zeroCoords, &nonzeroCoords);

  if (zeroCoords.size()==0 || nonzeroCoords.size()==0)
    return;

  // test coeff and coeffRef
  for (int i=0; i<(int)zeroCoords.size(); ++i)
  {
    VERIFY_IS_MUCH_SMALLER_THAN( m.coeff(zeroCoords[i].x(),zeroCoords[i].y()), eps );
    if(internal::is_same<SparseMatrixType,SparseMatrix<Scalar,Flags> >::value)
      VERIFY_RAISES_ASSERT( m.coeffRef(zeroCoords[0].x(),zeroCoords[0].y()) = 5 );
  }
  VERIFY_IS_APPROX(m, refMat);

  m.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
  refMat.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);

  VERIFY_IS_APPROX(m, refMat);
  /*
  // test InnerIterators and Block expressions
  for (int t=0; t<10; ++t)
  {
    int j = internal::random<int>(0,cols-1);
    int i = internal::random<int>(0,rows-1);
    int w = internal::random<int>(1,cols-j-1);
    int h = internal::random<int>(1,rows-i-1);

//     VERIFY_IS_APPROX(m.block(i,j,h,w), refMat.block(i,j,h,w));
    for(int c=0; c<w; c++)
    {
      VERIFY_IS_APPROX(m.block(i,j,h,w).col(c), refMat.block(i,j,h,w).col(c));
      for(int r=0; r<h; r++)
      {
//         VERIFY_IS_APPROX(m.block(i,j,h,w).col(c).coeff(r), refMat.block(i,j,h,w).col(c).coeff(r));
      }
    }
//     for(int r=0; r<h; r++)
//     {
//       VERIFY_IS_APPROX(m.block(i,j,h,w).row(r), refMat.block(i,j,h,w).row(r));
//       for(int c=0; c<w; c++)
//       {
//         VERIFY_IS_APPROX(m.block(i,j,h,w).row(r).coeff(c), refMat.block(i,j,h,w).row(r).coeff(c));
//       }
//     }
  }

  for(int c=0; c<cols; c++)
  {
    VERIFY_IS_APPROX(m.col(c) + m.col(c), (m + m).col(c));
    VERIFY_IS_APPROX(m.col(c) + m.col(c), refMat.col(c) + refMat.col(c));
  }

  for(int r=0; r<rows; r++)
  {
    VERIFY_IS_APPROX(m.row(r) + m.row(r), (m + m).row(r));
    VERIFY_IS_APPROX(m.row(r) + m.row(r), refMat.row(r) + refMat.row(r));
  }
  */

    // test insert (inner random)
    {
      DenseMatrix m1(rows,cols);
      m1.setZero();
      SparseMatrixType m2(rows,cols);
      m2.reserve(10);
      for (int j=0; j<cols; ++j)
      {
        for (int k=0; k<rows/2; ++k)
        {
          int i = internal::random<int>(0,rows-1);
          if (m1.coeff(i,j)==Scalar(0))
            m2.insert(i,j) = m1(i,j) = internal::random<Scalar>();
        }
      }
      m2.finalize();
      VERIFY_IS_APPROX(m2,m1);
    }

    // test insert (fully random)
    {
      DenseMatrix m1(rows,cols);
      m1.setZero();
      SparseMatrixType m2(rows,cols);
      m2.reserve(10);
      for (int k=0; k<rows*cols; ++k)
      {
        int i = internal::random<int>(0,rows-1);
        int j = internal::random<int>(0,cols-1);
        if (m1.coeff(i,j)==Scalar(0))
          m2.insert(i,j) = m1(i,j) = internal::random<Scalar>();
      }
      m2.finalize();
      VERIFY_IS_APPROX(m2,m1);
    }

  // test basic computations
  {
    DenseMatrix refM1 = DenseMatrix::Zero(rows, rows);
    DenseMatrix refM2 = DenseMatrix::Zero(rows, rows);
    DenseMatrix refM3 = DenseMatrix::Zero(rows, rows);
    DenseMatrix refM4 = DenseMatrix::Zero(rows, rows);
    SparseMatrixType m1(rows, rows);
    SparseMatrixType m2(rows, rows);
    SparseMatrixType m3(rows, rows);
    SparseMatrixType m4(rows, rows);
    initSparse<Scalar>(density, refM1, m1);
    initSparse<Scalar>(density, refM2, m2);
    initSparse<Scalar>(density, refM3, m3);
    initSparse<Scalar>(density, refM4, m4);

    VERIFY_IS_APPROX(m1+m2, refM1+refM2);
    VERIFY_IS_APPROX(m1+m2+m3, refM1+refM2+refM3);
    VERIFY_IS_APPROX(m3.cwiseProduct(m1+m2), refM3.cwiseProduct(refM1+refM2));
    VERIFY_IS_APPROX(m1*s1-m2, refM1*s1-refM2);

    VERIFY_IS_APPROX(m1*=s1, refM1*=s1);
    VERIFY_IS_APPROX(m1/=s1, refM1/=s1);

    VERIFY_IS_APPROX(m1+=m2, refM1+=refM2);
    VERIFY_IS_APPROX(m1-=m2, refM1-=refM2);

    VERIFY_IS_APPROX(m1.col(0).dot(refM2.row(0)), refM1.col(0).dot(refM2.row(0)));

    refM4.setRandom();
    // sparse cwise* dense
    VERIFY_IS_APPROX(m3.cwiseProduct(refM4), refM3.cwiseProduct(refM4));
//     VERIFY_IS_APPROX(m3.cwise()/refM4, refM3.cwise()/refM4);
  }

  // test transpose
  {
    DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
    SparseMatrixType m2(rows, rows);
    initSparse<Scalar>(density, refMat2, m2);
    VERIFY_IS_APPROX(m2.transpose().eval(), refMat2.transpose().eval());
    VERIFY_IS_APPROX(m2.transpose(), refMat2.transpose());

    VERIFY_IS_APPROX(SparseMatrixType(m2.adjoint()), refMat2.adjoint());
  }

  // test innerVector()
  {
    DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
    SparseMatrixType m2(rows, rows);
    initSparse<Scalar>(density, refMat2, m2);
    int j0 = internal::random(0,rows-1);
    int j1 = internal::random(0,rows-1);
    VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.col(j0));
    VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.col(j0)+refMat2.col(j1));
    //m2.innerVector(j0) = 2*m2.innerVector(j1);
    //refMat2.col(j0) = 2*refMat2.col(j1);
    //VERIFY_IS_APPROX(m2, refMat2);
  }

  // test innerVectors()
  {
    DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
    SparseMatrixType m2(rows, rows);
    initSparse<Scalar>(density, refMat2, m2);
    int j0 = internal::random(0,rows-2);
    int j1 = internal::random(0,rows-2);
    int n0 = internal::random<int>(1,rows-std::max(j0,j1));
    VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(0,j0,rows,n0));
    VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0),
                     refMat2.block(0,j0,rows,n0)+refMat2.block(0,j1,rows,n0));
    //m2.innerVectors(j0,n0) = m2.innerVectors(j0,n0) + m2.innerVectors(j1,n0);
    //refMat2.block(0,j0,rows,n0) = refMat2.block(0,j0,rows,n0) + refMat2.block(0,j1,rows,n0);
  }

  // test prune
  {
    SparseMatrixType m2(rows, rows);
    DenseMatrix refM2(rows, rows);
    refM2.setZero();
    int countFalseNonZero = 0;
    int countTrueNonZero = 0;
    for (int j=0; j<m2.outerSize(); ++j)
    {
      m2.startVec(j);
      for (int i=0; i<m2.innerSize(); ++i)
      {
        float x = internal::random<float>(0,1);
        if (x<0.1)
        {
          // do nothing
        }
        else if (x<0.5)
        {
          countFalseNonZero++;
          m2.insertBackByOuterInner(j,i) = Scalar(0);
        }
        else
        {
          countTrueNonZero++;
          m2.insertBackByOuterInner(j,i) = refM2(i,j) = Scalar(1);
        }
      }
    }
    m2.finalize();
    VERIFY(countFalseNonZero+countTrueNonZero == m2.nonZeros());
    VERIFY_IS_APPROX(m2, refM2);
    m2.prune(Scalar(1));
    VERIFY(countTrueNonZero==m2.nonZeros());
    VERIFY_IS_APPROX(m2, refM2);
  }

  // test sparseView
  {
    DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
    SparseMatrixType m2(rows, rows);
    VERIFY_IS_APPROX(m2.eval(), refMat2.sparseView().eval());
  }
}

void test_sparse_basic()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( sparse_basic(SparseMatrix<double>(8, 8)) );
    CALL_SUBTEST_2( sparse_basic(SparseMatrix<std::complex<double> >(16, 16)) );
    CALL_SUBTEST_1( sparse_basic(SparseMatrix<double>(33, 33)) );

    CALL_SUBTEST_3( sparse_basic(DynamicSparseMatrix<double>(8, 8)) );
  }
}
<|endoftext|>


<commit_before>/*
    Calendar access for KDE Alarm Daemon.

    This file is part of the KDE alarm daemon.
    Copyright (c) 2001 David Jarvie <software@astrojar.org.uk>

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

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <kstandarddirs.h>
#include <ksimpleconfig.h>
#include <kio/netaccess.h>
#include <kdebug.h>

#include "adcalendarbase.h"

ADCalendarBase::EventsMap ADCalendarBase::eventsHandled_;

ADCalendarBase::ADCalendarBase(const QString& url, const QCString& appname, Type type)
  : mUrlString(url),
    mAppName(appname),
    mActionType(type),
    mRcIndex(-1),
    mLoaded(false),
    mUnregistered(false)
{
  if (mAppName == "korgac")
  {
    KConfig cfg( locate( "config", "korganizerrc" ) );
    cfg.setGroup( "Time & Date" );
    QString tz = cfg.readEntry( "TimeZoneId" );
    kdDebug(5900) << "ADCalendarBase(): tz: " << tz << endl;
    setTimeZoneId( cfg.readEntry( "TimeZoneId" ) );
  }
}

/*
 * Load the calendar file.
 */
bool ADCalendarBase::loadFile_(const QCString& appName)
{
  mLoaded = false;
  KURL url(mUrlString);
  QString tmpFile;
  if (KIO::NetAccess::download(url, tmpFile))
  {
    kdDebug(5900) << "--- Downloaded to " << tmpFile << endl;
    mLoaded = load(tmpFile);
    KIO::NetAccess::removeTempFile(tmpFile);
    if (!mLoaded)
      kdDebug(5900) << "ADCalendarBase::loadFile_(): Error loading calendar file '" << tmpFile << "'\n";
    else
    {
      // Remove all now non-existent events from the handled list
      for (EventsMap::Iterator it = eventsHandled_.begin();  it != eventsHandled_.end();  )
      {
        if (it.data().calendarURL == mUrlString  &&  !event(it.key()))
        {
          // Event belonged to this calendar, but can't find it any more
          EventsMap::Iterator i = it;
          ++it;                      // prevent iterator becoming invalid with remove()
          eventsHandled_.remove(i);
        }
        else
          ++it;
      }
    }
  }
  else if (!appName.isEmpty()) {
#if TODO_handle_download_error
    KMessageBox::error(0L, i18n("Cannot download calendar from\n%1.")
                           .arg(url.prettyURL()), appName);
#endif
  }
  return mLoaded;
}

void ADCalendarBase::dump() const
{
  kdDebug(5900) << "  <calendar>" << endl;
  kdDebug(5900) << "    <url>" << urlString() << "</url>" << endl;
  kdDebug(5900) << "    <appname>" << appName() << "</appname>" << endl;
  if ( loaded() ) kdDebug(5900) << "    <loaded/>" << endl;
  kdDebug(5900) << "    <actiontype>" << int(actionType()) << "</actiontype>" << endl;
  if (enabled() ) kdDebug(5900) << "    <enabled/>" << endl;
  else kdDebug(5900) << "    <disabled/>" << endl;
  if (available()) kdDebug(5900) << "    <available/>" << endl;
  kdDebug(5900) << "  </calendar>" << endl;
}
<commit_msg>Reinstate previous change<commit_after>/*
    Calendar access for KDE Alarm Daemon.

    This file is part of the KDE alarm daemon.
    Copyright (c) 2001 David Jarvie <software@astrojar.org.uk>

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

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <unistd.h>
#include <time.h>

#include <kstandarddirs.h>
#include <ksimpleconfig.h>
#include <kio/netaccess.h>
#include <kdebug.h>

#include "adcalendarbase.h"

ADCalendarBase::EventsMap ADCalendarBase::eventsHandled_;

ADCalendarBase::ADCalendarBase(const QString& url, const QCString& appname, Type type)
  : mUrlString(url),
    mAppName(appname),
    mActionType(type),
    mRcIndex(-1),
    mLoaded(false),
    mUnregistered(false)
{
  if (mAppName == "korgac")
  {
    KConfig cfg( locate( "config", "korganizerrc" ) );
    cfg.setGroup( "Time & Date" );
    QString tz = cfg.readEntry( "TimeZoneId", "" );
    kdDebug(5900) << "ADCalendarBase(): tz: " << tz << endl;
    if( tz.isEmpty() ) {
      // Set a reasonable default timezone is none
      // was found in the config file
      // see koprefs.cpp in korganizer
      QString zone;
      char zonefilebuf[100];
      int len = readlink("/etc/localtime",zonefilebuf,100);
      if (len > 0 && len < 100) {
	zonefilebuf[len] = '\0';
	zone = zonefilebuf;
	zone = zone.mid(zone.find("zoneinfo/") + 9);
      } else {
	tzset();
	zone = tzname[0];
      }
      tz = zone;
    }
    setTimeZoneId( tz );
  }
}

/*
 * Load the calendar file.
 */
bool ADCalendarBase::loadFile_(const QCString& appName)
{
  mLoaded = false;
  KURL url(mUrlString);
  QString tmpFile;
  if (KIO::NetAccess::download(url, tmpFile))
  {
    kdDebug(5900) << "--- Downloaded to " << tmpFile << endl;
    mLoaded = load(tmpFile);
    KIO::NetAccess::removeTempFile(tmpFile);
    if (!mLoaded)
      kdDebug(5900) << "ADCalendarBase::loadFile_(): Error loading calendar file '" << tmpFile << "'\n";
    else
    {
      // Remove all now non-existent events from the handled list
      for (EventsMap::Iterator it = eventsHandled_.begin();  it != eventsHandled_.end();  )
      {
        if (it.data().calendarURL == mUrlString  &&  !event(it.key()))
        {
          // Event belonged to this calendar, but can't find it any more
          EventsMap::Iterator i = it;
          ++it;                      // prevent iterator becoming invalid with remove()
          eventsHandled_.remove(i);
        }
        else
          ++it;
      }
    }
  }
  else if (!appName.isEmpty()) {
#if TODO_handle_download_error
    KMessageBox::error(0L, i18n("Cannot download calendar from\n%1.")
                           .arg(url.prettyURL()), appName);
#endif
  }
  return mLoaded;
}

void ADCalendarBase::dump() const
{
  kdDebug(5900) << "  <calendar>" << endl;
  kdDebug(5900) << "    <url>" << urlString() << "</url>" << endl;
  kdDebug(5900) << "    <appname>" << appName() << "</appname>" << endl;
  if ( loaded() ) kdDebug(5900) << "    <loaded/>" << endl;
  kdDebug(5900) << "    <actiontype>" << int(actionType()) << "</actiontype>" << endl;
  if (enabled() ) kdDebug(5900) << "    <enabled/>" << endl;
  else kdDebug(5900) << "    <disabled/>" << endl;
  if (available()) kdDebug(5900) << "    <available/>" << endl;
  kdDebug(5900) << "  </calendar>" << endl;
}
<|endoftext|>


<commit_before>#include "task_manager.hpp"

#include <gtest/gtest.h>

TEST(TaskManager, IdentityTask) {
//  TaskDistribution::TaskManager task_manager;
//  auto task = task_manager.new_identity_task(1);
}
<commit_msg>[reorganization] Added test for task creation.<commit_after>#include "task_manager.hpp"

#include <gtest/gtest.h>

TEST(TaskManager, IdentityTask) {
  TaskDistribution::TaskManager task_manager;
  auto task = task_manager.new_identity_task(1);
}
<|endoftext|>


<commit_before>#include "SigFig.h"
#include <algorithm>
#include <cmath>

using namespace std;

SigFig SigFig::unit() const
{
	return SigFig(pow(10, _precision), _precision);
}

short SigFig::signum() const
{
	if (this->value() == 0)
		return 0;
	return this->value() > 0 ? 1 : -1;
}

int SigFig::sigfigs() const
{
	int leading_place=floor(log10(abs(_value)));
	return max(0, leading_place-_precision+1);
}

///
// Return the closest value that represents the exact portion of this significant figure.
double SigFig::value() const
{
	double estimated_value = fmod(_value, pow(10, _precision));
	double greatest_digit = abs(floor(
		estimated_value / pow(10, _precision - 1)
	));
	double best_value = _value - estimated_value;
	if (greatest_digit >= 5)
		best_value += (_value > 0 ? 1 : -1) * pow(10, _precision);
	return best_value;
}

///
// Determine whether two significant figures are equal.
//
// Equivalent values will have an equal "exact" portion and an
// equal precision.
//
// Trivially equal:
// 10.0 == 10.0
//
// Equal with unequal fuzz:
// 10.0 == 10.1
//
// Unequal, due to unequal exact portions:
// 10.0 == 11.0
//
// Unequal, due to unequal precision:
// 10.0 != 10.00
bool SigFig::operator==(const SigFig& other) const
{
	if (_precision != other._precision)
		return false;
	return abs(_value - other._value) < pow(10, _precision);
}

bool SigFig::operator!=(const SigFig& other) const
{
	return !(*this == other);
}

void SigFig::_add(SigFig& out, const SigFig& a, const SigFig& b)
{
	// While this looks like we're giving our value "maximum" precision,
	// we're actually losing precision since we're pushing the precision
	// to a bigger value.
	out._value = a._value + b._value;
	out._precision = max(a._precision, b._precision);
}

SigFig SigFig::operator+(const SigFig& other) const
{
	SigFig rv;
	SigFig::_add(rv, *this, other);
	return rv;
}

const SigFig& SigFig::operator+=(const SigFig& other)
{
	SigFig::_add(*this, *this, other);
	return *this;
}

void SigFig::_subtract(SigFig& out, const SigFig& a, const SigFig& b)
{
	out._value = a._value - b._value;
	out._precision = max(a._precision, b._precision);
}

SigFig SigFig::operator-(const SigFig& other) const
{
	SigFig rv;
	SigFig::_subtract(rv, *this, other);
	return rv;
}

const SigFig& SigFig::operator-=(const SigFig& other)
{
	SigFig::_subtract(*this, *this, other);
	return *this;
}

SigFig& SigFig::operator++()
{
	SigFig u=this->unit();
	*this += u;
	return *this;
}

SigFig SigFig::operator++(int) const
{
	SigFig u=this->unit();
	return *this + u;
}

SigFig& SigFig::operator--()
{
	SigFig u=this->unit();
	*this -= u;
	return *this;
}

SigFig SigFig::operator--(int) const
{
	SigFig u=this->unit();
	return *this - u;
}

void SigFig::_multiply(SigFig& out, const SigFig& a, const SigFig& b)
{
	int sigfigs = min(a.sigfigs(), b.sigfigs());
	out._value = a._value * b._value;
	int leading_place=floor(log10(abs(out._value)));
	out._precision = leading_place - sigfigs + 1;
}

SigFig SigFig::operator*(const SigFig& other) const
{
	SigFig rv;
	SigFig::_multiply(rv, *this, other);
	return rv;
}

const SigFig& SigFig::operator*=(const SigFig& other)
{
	SigFig::_multiply(*this, *this, other);
	return *this;
}

bool SigFig::operator<(const SigFig& other) const
{
	return (*this - other).signum() < 0;
}

bool SigFig::operator>(const SigFig& other) const
{
	return (*this - other).signum() > 0;
}
<commit_msg>Rearranged functions in SigFig<commit_after>#include "SigFig.h"
#include <algorithm>
#include <cmath>

using namespace std;

SigFig SigFig::unit() const
{
	return SigFig(pow(10, _precision), _precision);
}

short SigFig::signum() const
{
	if (this->value() == 0)
		return 0;
	return this->value() > 0 ? 1 : -1;
}

int SigFig::sigfigs() const
{
	int leading_place=floor(log10(abs(_value)));
	return max(0, leading_place-_precision+1);
}

///
// Return the closest value that represents the exact portion of this significant figure.
double SigFig::value() const
{
	double estimated_value = fmod(_value, pow(10, _precision));
	double greatest_digit = abs(floor(
		estimated_value / pow(10, _precision - 1)
	));
	double best_value = _value - estimated_value;
	if (greatest_digit >= 5)
		best_value += (_value > 0 ? 1 : -1) * pow(10, _precision);
	return best_value;
}

///
// Determine whether two significant figures are equal.
//
// Equivalent values will have an equal "exact" portion and an
// equal precision.
//
// Trivially equal:
// 10.0 == 10.0
//
// Equal with unequal fuzz:
// 10.0 == 10.1
//
// Unequal, due to unequal exact portions:
// 10.0 == 11.0
//
// Unequal, due to unequal precision:
// 10.0 != 10.00
bool SigFig::operator==(const SigFig& other) const
{
	if (_precision != other._precision)
		return false;
	return abs(_value - other._value) < pow(10, _precision);
}

bool SigFig::operator!=(const SigFig& other) const
{
	return !(*this == other);
}

bool SigFig::operator<(const SigFig& other) const
{
	return (*this - other).signum() < 0;
}

bool SigFig::operator>(const SigFig& other) const
{
	return (*this - other).signum() > 0;
}

void SigFig::_add(SigFig& out, const SigFig& a, const SigFig& b)
{
	// While this looks like we're giving our value "maximum" precision,
	// we're actually losing precision since we're pushing the precision
	// to a bigger value.
	out._value = a._value + b._value;
	out._precision = max(a._precision, b._precision);
}

SigFig SigFig::operator+(const SigFig& other) const
{
	SigFig rv;
	SigFig::_add(rv, *this, other);
	return rv;
}

const SigFig& SigFig::operator+=(const SigFig& other)
{
	SigFig::_add(*this, *this, other);
	return *this;
}

void SigFig::_subtract(SigFig& out, const SigFig& a, const SigFig& b)
{
	out._value = a._value - b._value;
	out._precision = max(a._precision, b._precision);
}

SigFig SigFig::operator-(const SigFig& other) const
{
	SigFig rv;
	SigFig::_subtract(rv, *this, other);
	return rv;
}

const SigFig& SigFig::operator-=(const SigFig& other)
{
	SigFig::_subtract(*this, *this, other);
	return *this;
}

void SigFig::_multiply(SigFig& out, const SigFig& a, const SigFig& b)
{
	int sigfigs = min(a.sigfigs(), b.sigfigs());
	out._value = a._value * b._value;
	int leading_place=floor(log10(abs(out._value)));
	out._precision = leading_place - sigfigs + 1;
}

SigFig SigFig::operator*(const SigFig& other) const
{
	SigFig rv;
	SigFig::_multiply(rv, *this, other);
	return rv;
}

const SigFig& SigFig::operator*=(const SigFig& other)
{
	SigFig::_multiply(*this, *this, other);
	return *this;
}

SigFig& SigFig::operator++()
{
	SigFig::_add(*this, *this, this->unit());
	return *this;
}

SigFig SigFig::operator++(int) const
{
	SigFig rv;
	SigFig::_add(rv, *this, this->unit());
	return rv;
}

SigFig& SigFig::operator--()
{
	SigFig::_subtract(*this, *this, this->unit());
	return *this;
}

SigFig SigFig::operator--(int) const
{
	SigFig rv;
	SigFig::_subtract(rv, *this, this->unit());
	return rv;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/extensions/metadata_transfer.hpp"
#include "libtorrent/extensions/ut_metadata.hpp"
#include "libtorrent/extensions/lt_trackers.hpp"

using boost::tuples::ignore;

int test_main()
{
	using namespace libtorrent;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48130, 49000), "0.0.0.0", 0);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49130, 50000), "0.0.0.0", 0);
	ses1.add_extension(create_lt_trackers_plugin);
	ses2.add_extension(create_lt_trackers_plugin);

	add_torrent_params atp;
	atp.info_hash = sha1_hash("12345678901234567890");
	atp.save_path = "./";
	torrent_handle tor1 = ses1.add_torrent(atp);
	atp.tracker_url = "http://test.non-existent.com/announce";
	torrent_handle tor2 = ses2.add_torrent(atp);
	tor2.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), ses1.listen_port()));

	for (int i = 0; i < 130; ++i)
	{
		// make sure this function can be called on
		// torrents without metadata
		print_alerts(ses1, "ses1", false, true);
		print_alerts(ses2, "ses2", false, true);

		if (tor1.trackers().size() == 1) break;
		test_sleep(1000);
	}

	TEST_CHECK(tor1.trackers().size() == 1);
}

<commit_msg>fix tracker test<commit_after>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/extensions/metadata_transfer.hpp"
#include "libtorrent/extensions/ut_metadata.hpp"
#include "libtorrent/extensions/lt_trackers.hpp"

using boost::tuples::ignore;

int test_main()
{
	using namespace libtorrent;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48130, 49000), "0.0.0.0", 0);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49130, 50000), "0.0.0.0", 0);
	ses1.add_extension(create_lt_trackers_plugin);
	ses2.add_extension(create_lt_trackers_plugin);

	add_torrent_params atp;
	atp.info_hash = sha1_hash("12345678901234567890");
	atp.save_path = "./";
	torrent_handle tor1 = ses1.add_torrent(atp);
	atp.tracker_url = "http://test.non-existent.com/announce";
	torrent_handle tor2 = ses2.add_torrent(atp);
	tor2.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), ses1.listen_port()));

	for (int i = 0; i < 130; ++i)
	{
		// make sure this function can be called on
		// torrents without metadata
		print_alerts(ses1, "ses1", false, true);
		print_alerts(ses2, "ses2", false, true);

		if (tor1.trackers().size() == 1) break;
		test_sleep(1000);
	}

	TEST_CHECK(tor1.trackers().size() == 1);
	return 0;
}

<|endoftext|>


<commit_before>#include "Spritemap.h"
#include "Logging.h"

namespace ECSE
{

Spritemap::Spritemap()
    : callback(nullptr), m_texture(nullptr), m_animSet(nullptr), m_currentAnim(nullptr),
    m_currentTime(sf::Time::Zero), m_currentFrame(0)
{

}

Spritemap::Spritemap(const sf::Texture& texture)
    : Spritemap()
{
    setTexture(texture);
}

Spritemap::Spritemap(const sf::Texture& texture, const AnimationSet& animSet)
    : Spritemap(texture)
{
    setAnimationSet(animSet);
    setIndex(0);
}

bool Spritemap::hasAnimation(std::string name) const
{
    auto *newAnim = m_animSet->getAnimation(name);
    return newAnim != nullptr;
}

void Spritemap::playAnimation(std::string name, bool reset)
{
    if (!m_animSet)
    {
        LOG(WARNING) << "Tried to play animation \"" + name + "\" on a Spritemap with no animations!";
    }

    const Animation *newAnim = m_animSet->getAnimation(name);

    if (newAnim == nullptr)
    {
        LOG(WARNING) << "Animation " << name << " does not exist!";
    }

    // Already playing
    if (newAnim == m_currentAnim && reset)
    {
        setIndex(0, true);
        return;
    }

    // Start playing
    m_currentAnim = newAnim;
    m_currentTime = sf::Time::Zero;
    setIndex(0, false);
    m_playing = true;
}

void Spritemap::stop()
{
    m_playing = false;
    m_currentAnim = nullptr;
}

void Spritemap::update(sf::Time deltaTime)
{
    if (!m_playing || !m_currentAnim) return;

    size_t frameCount = m_currentAnim->frames.size();
    sf::Time frameTime = m_currentAnim->frameTime;

    // Calculate new frame
    m_currentTime += deltaTime;

    // If frame time is 0, we just want the first frame
    if (frameTime == sf::seconds(0))
    {
        m_currentFrame = 0;
        setIndex(m_currentAnim->frames[m_currentFrame]);
        return;
    }

    if (m_currentTime > frameTime)
    {
        size_t frameIncrease = static_cast<size_t>(m_currentTime / frameTime);
        m_currentFrame += frameIncrease;

        // Reset time with remainder
        m_currentTime = m_currentTime % frameTime;

        if (m_currentFrame >= frameCount)
        {
            // Call back if there's a callback function
            if (callback) callback();

            // Loop
            if (m_currentAnim->looping) {
                m_currentFrame = m_currentFrame % frameCount;
            }
            else
            {
                m_currentFrame = frameCount - 1;
                m_playing = false;
            }
        }

        setIndex(m_currentAnim->frames[m_currentFrame]);
    }
}

void Spritemap::setTexture(const sf::Texture& texture)
{
    m_texture = &texture;

    if (!m_animSet)
    {
        setIndex(0);
    }

    updateGrid();
}

void Spritemap::setAnimationSet(const AnimationSet& animSet)
{
    m_animSet = &animSet;
    m_frameSize = sf::Vector2f(static_cast<float>(animSet.frameSize.x),
                               static_cast<float>(animSet.frameSize.y));

    updateGrid();
}

void Spritemap::setIndex(size_t newFrame, bool stop)
{
    m_currentIndex = newFrame;

    sf::FloatRect rect = getIndexRect(m_currentIndex);

    m_vertices[0].position = sf::Vector2f(0.f, 0.f);
    m_vertices[1].position = sf::Vector2f(0.f, rect.height);
    m_vertices[2].position = sf::Vector2f(rect.width, 0.f);
    m_vertices[3].position = sf::Vector2f(rect.width, rect.height);

    m_vertices[0].texCoords = sf::Vector2f(rect.left, rect.top);
    m_vertices[1].texCoords = sf::Vector2f(rect.left, rect.top + rect.height);
    m_vertices[2].texCoords = sf::Vector2f(rect.left + rect.width, rect.top);
    m_vertices[3].texCoords = sf::Vector2f(rect.left + rect.width, rect.top + rect.height);

    if (stop)
    {
        m_currentTime = sf::Time::Zero;
        m_playing = false;
    }
}

void Spritemap::setColor(const sf::Color& color)
{
    m_vertices[0].color = color;
    m_vertices[1].color = color;
    m_vertices[2].color = color;
    m_vertices[3].color = color;
}

const sf::Texture* Spritemap::getTexture() const
{
    return m_texture;
}

const AnimationSet* Spritemap::getAnimationSet() const
{
    return m_animSet;
}

const sf::Color& Spritemap::getColor() const
{
    return m_vertices[0].color;
}

sf::FloatRect Spritemap::getLocalBounds() const
{
    return getIndexRect(m_currentIndex);
}

sf::FloatRect Spritemap::getGlobalBounds() const
{
    return getTransform().transformRect(getLocalBounds());
}

sf::FloatRect Spritemap::getIndexRect(size_t frame) const
{
    if (m_frameGrid.x == 0 || m_frameGrid.y == 0)
    {
        return sf::FloatRect(sf::Vector2f(),
                             sf::Vector2f(m_texture->getSize()));
    }

    sf::Vector2f frameOffset = sf::Vector2f(
        static_cast<float>(frame % m_frameGrid.x),
        static_cast<float>(frame / m_frameGrid.x)
        );

    frameOffset.x *= m_frameSize.x;
    frameOffset.y *= m_frameSize.y;

    return sf::FloatRect(frameOffset, m_frameSize);
}

void Spritemap::updateGrid()
{
    // No data to work with
    if (!m_texture || m_frameSize.x == 0 || m_frameSize.y == 0) return;

    sf::Vector2u textureSize = m_texture->getSize();

    if (static_cast<size_t>(m_frameSize.x) > textureSize.x ||
        static_cast<size_t>(m_frameSize.y) > textureSize.y)
    {
        LOG(WARNING) << "Texture not big enough for provided frame width";
    }

    m_frameGrid = sf::Vector2u(
        textureSize.x / static_cast<size_t>(m_frameSize.x),
        textureSize.y / static_cast<size_t>(m_frameSize.y)
        );
}

void Spritemap::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
    if (m_texture)
    {
        states.transform *= getTransform();
        states.texture = m_texture;
        target.draw(m_vertices, 4, sf::TrianglesStrip, states);
    }
}

}
<commit_msg>Fix animations not resetting properly<commit_after>#include "Spritemap.h"
#include "Logging.h"

namespace ECSE
{

Spritemap::Spritemap()
    : callback(nullptr), m_texture(nullptr), m_animSet(nullptr), m_currentAnim(nullptr),
    m_currentTime(sf::Time::Zero), m_currentFrame(0)
{

}

Spritemap::Spritemap(const sf::Texture& texture)
    : Spritemap()
{
    setTexture(texture);
}

Spritemap::Spritemap(const sf::Texture& texture, const AnimationSet& animSet)
    : Spritemap(texture)
{
    setAnimationSet(animSet);
    setIndex(0);
}

bool Spritemap::hasAnimation(std::string name) const
{
    auto *newAnim = m_animSet->getAnimation(name);
    return newAnim != nullptr;
}

void Spritemap::playAnimation(std::string name, bool reset)
{
    if (!m_animSet)
    {
        LOG(WARNING) << "Tried to play animation \"" + name + "\" on a Spritemap with no animations!";
    }

    const Animation *newAnim = m_animSet->getAnimation(name);

    if (newAnim == nullptr)
    {
        LOG(WARNING) << "Animation " << name << " does not exist!";
    }

    // Already playing
    if (newAnim == m_currentAnim && !reset)
    {
        return;
    }

    // Start playing
    m_currentAnim = newAnim;
    m_currentTime = sf::Time::Zero;
    m_currentFrame = 0;
    setIndex(0, false);
    m_playing = true;
}

void Spritemap::stop()
{
    m_playing = false;
    m_currentAnim = nullptr;
}

void Spritemap::update(sf::Time deltaTime)
{
    if (!m_playing || !m_currentAnim) return;

    size_t frameCount = m_currentAnim->frames.size();
    sf::Time frameTime = m_currentAnim->frameTime;

    // Calculate new frame
    m_currentTime += deltaTime;

    // If frame time is 0, we just want the first frame
    if (frameTime == sf::seconds(0))
    {
        m_currentFrame = 0;
        setIndex(m_currentAnim->frames[m_currentFrame]);
        return;
    }

    if (m_currentTime > frameTime)
    {
        size_t frameIncrease = static_cast<size_t>(m_currentTime / frameTime);
        m_currentFrame += frameIncrease;

        // Reset time with remainder
        m_currentTime = m_currentTime % frameTime;

        if (m_currentFrame >= frameCount)
        {
            // Call back if there's a callback function
            if (callback) callback();

            // Loop
            if (m_currentAnim->looping) {
                m_currentFrame = m_currentFrame % frameCount;
            }
            else
            {
                m_currentFrame = frameCount - 1;
                m_playing = false;
            }
        }

        setIndex(m_currentAnim->frames[m_currentFrame]);
    }
}

void Spritemap::setTexture(const sf::Texture& texture)
{
    m_texture = &texture;

    if (!m_animSet)
    {
        setIndex(0);
    }

    updateGrid();
}

void Spritemap::setAnimationSet(const AnimationSet& animSet)
{
    m_animSet = &animSet;
    m_frameSize = sf::Vector2f(static_cast<float>(animSet.frameSize.x),
                               static_cast<float>(animSet.frameSize.y));

    updateGrid();
}

void Spritemap::setIndex(size_t newFrame, bool stop)
{
    m_currentIndex = newFrame;

    sf::FloatRect rect = getIndexRect(m_currentIndex);

    m_vertices[0].position = sf::Vector2f(0.f, 0.f);
    m_vertices[1].position = sf::Vector2f(0.f, rect.height);
    m_vertices[2].position = sf::Vector2f(rect.width, 0.f);
    m_vertices[3].position = sf::Vector2f(rect.width, rect.height);

    m_vertices[0].texCoords = sf::Vector2f(rect.left, rect.top);
    m_vertices[1].texCoords = sf::Vector2f(rect.left, rect.top + rect.height);
    m_vertices[2].texCoords = sf::Vector2f(rect.left + rect.width, rect.top);
    m_vertices[3].texCoords = sf::Vector2f(rect.left + rect.width, rect.top + rect.height);

    if (stop)
    {
        m_currentTime = sf::Time::Zero;
        m_playing = false;
    }
}

void Spritemap::setColor(const sf::Color& color)
{
    m_vertices[0].color = color;
    m_vertices[1].color = color;
    m_vertices[2].color = color;
    m_vertices[3].color = color;
}

const sf::Texture* Spritemap::getTexture() const
{
    return m_texture;
}

const AnimationSet* Spritemap::getAnimationSet() const
{
    return m_animSet;
}

const sf::Color& Spritemap::getColor() const
{
    return m_vertices[0].color;
}

sf::FloatRect Spritemap::getLocalBounds() const
{
    return getIndexRect(m_currentIndex);
}

sf::FloatRect Spritemap::getGlobalBounds() const
{
    return getTransform().transformRect(getLocalBounds());
}

sf::FloatRect Spritemap::getIndexRect(size_t frame) const
{
    if (m_frameGrid.x == 0 || m_frameGrid.y == 0)
    {
        return sf::FloatRect(sf::Vector2f(),
                             sf::Vector2f(m_texture->getSize()));
    }

    sf::Vector2f frameOffset = sf::Vector2f(
        static_cast<float>(frame % m_frameGrid.x),
        static_cast<float>(frame / m_frameGrid.x)
        );

    frameOffset.x *= m_frameSize.x;
    frameOffset.y *= m_frameSize.y;

    return sf::FloatRect(frameOffset, m_frameSize);
}

void Spritemap::updateGrid()
{
    // No data to work with
    if (!m_texture || m_frameSize.x == 0 || m_frameSize.y == 0) return;

    sf::Vector2u textureSize = m_texture->getSize();

    if (static_cast<size_t>(m_frameSize.x) > textureSize.x ||
        static_cast<size_t>(m_frameSize.y) > textureSize.y)
    {
        LOG(WARNING) << "Texture not big enough for provided frame width";
    }

    m_frameGrid = sf::Vector2u(
        textureSize.x / static_cast<size_t>(m_frameSize.x),
        textureSize.y / static_cast<size_t>(m_frameSize.y)
        );
}

void Spritemap::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
    if (m_texture)
    {
        states.transform *= getTransform();
        states.texture = m_texture;
        target.draw(m_vertices, 4, sf::TrianglesStrip, states);
    }
}

}
<|endoftext|>