<commit_before>/*++
Copyright (c) 2016 Microsoft Corporation

Module Name:

    bv_bounds_tactic.cpp

Abstract:

    Contextual bounds simplification tactic.

Author:

    Nikolaj Bjorner (nbjorner) 2016-2-12

--*/

#include "bv_bounds_tactic.h"
#include "ctx_simplify_tactic.h"
#include "bv_decl_plugin.h"
#include "ast_pp.h"

static rational uMaxInt(unsigned sz) {
    return rational::power_of_two(sz) - rational::one();
}

namespace {

struct interval {
    // l < h: [l, h]
    // l > h: [0, h] U [l, UMAX_INT]
    rational l, h;
    unsigned sz;

    explicit interval() : l(0), h(0), sz(0) {}
    interval(const rational& l, const rational& h, unsigned sz) : l(l), h(h), sz(sz) {
        SASSERT(invariant());
    }

    bool invariant() const {
        return !l.is_neg() && !h.is_neg() && l <= uMaxInt(sz) && h <= uMaxInt(sz);
    }

    bool is_full() const { return l.is_zero() && h == uMaxInt(sz); }
    bool is_wrapped() const { return l > h; }

    bool operator==(const interval& b) const {
        SASSERT(sz == b.sz);
        return l == b.l && h == b.h;
    }

    bool implies(const interval& b) const {
        if (b.is_full())
            return true;
        if (is_full())
            return false;

        if (is_wrapped()) {
            // l >= b.l >= b.h >= h
            return b.is_wrapped() && h <= b.h && l >= b.l;
        } else if (b.is_wrapped()) {
            // b.l > b.h >= h >= l
            // h >= l >= b.l > b.h
            return h <= b.h || l >= b.l;
        } else {
            //
            return l >= b.l && h <= b.h;
        }
    }

    /// return false if intersection is unsat
    bool intersect(const interval& b, interval& result) const {
        if (is_full() || (l == b.l && h == b.h)) {
            result = b;
            return true;
        }
        if (b.is_full()) {
            result = *this;
            return true;
        }

        if (is_wrapped()) {
            if (b.is_wrapped()) {
                if (h >= b.l) {
                    result = b;
                } else if (b.h >= l) {
                    result = *this;
                } else {
                    result = interval(std::max(l, b.l), std::min(h, b.h), sz);
                }
            } else {
                return b.intersect(*this, result);
            }
        } else if (b.is_wrapped()) {
            // ... b.h ... l ... h ... b.l ..
            if (h < b.l && l > b.h) {
                return false;
            }
            // ... l ... b.l ... h ...
            if (h >= b.l && l <= b.h) {
                result = b;
            } else if (h >= b.l) {
                result = interval(b.l, h, sz);
            } else {
                // ... l .. b.h .. h .. b.l ...
                SASSERT(l <= b.h);
                result = interval(l, std::min(h, b.h), sz);
            }
        } else {
            if (l > b.h || h < b.l)
                return false;

            // 0 .. l.. l' ... h ... h'
            result = interval(std::max(l, b.l), std::min(h, b.h), sz);
        }
        return true;
    }

    /// return false if negation is empty
    bool negate(interval& result) const {
        if (is_full())
            return false;
        if (l.is_zero()) {
            result = interval(h + rational::one(), uMaxInt(sz), sz);
        } else if (uMaxInt(sz) == h) {
            result = interval(rational::zero(), l - rational::one(), sz);
        } else {
            result = interval(h + rational::one(), l - rational::one(), sz);
        }
        return true;
    }
};

std::ostream& operator<<(std::ostream& o, const interval& I) {
    o << "[" << I.l << ", " << I.h << "]";
    return o;
}

class bv_bounds_simplifier : public ctx_simplify_tactic::simplifier {
    ast_manager&                     m;
    bv_util                          m_bv;
    vector<obj_map<expr, interval> > m_scopes;
    obj_map<expr, interval>         *m_bound;

    bool is_bound(expr *e, expr*& v, interval& b) {
        rational n;
        expr *lhs, *rhs;
        unsigned sz;

        if (m_bv.is_bv_ule(e, lhs, rhs)) {
            if (m_bv.is_numeral(lhs, n, sz)) { // C ule x <=> x uge C
                b = interval(n, uMaxInt(sz), sz);
                v = rhs;
                return true;
            }
            if (m_bv.is_numeral(rhs, n, sz)) { // x ule C
                b = interval(rational::zero(), n, sz);
                v = lhs;
                return true;
            }
        } else if (m_bv.is_bv_sle(e, lhs, rhs)) {
            if (m_bv.is_numeral(lhs, n, sz)) { // C sle x <=> x sge C
                b = interval(n, rational::power_of_two(sz-1) - rational::one(), sz);
                v = rhs;
                return true;
            }
            if (m_bv.is_numeral(rhs, n, sz)) { // x sle C
                b = interval(rational::power_of_two(sz-1), n, sz);
                v = lhs;
                return true;
            }
        } else if (m.is_eq(e, lhs, rhs)) {
            if (m_bv.is_numeral(lhs, n, sz)) {
                b = interval(n, n, sz);
                v = rhs;
                return true;
            }
            if (m_bv.is_numeral(rhs, n, sz)) {
                b = interval(n, n, sz);
                v = lhs;
                return true;
            }
        }
        return false;
    }

public:

    bv_bounds_simplifier(ast_manager& m) : m(m), m_bv(m) {
        m_scopes.push_back(obj_map<expr, interval>());
        m_bound = &m_scopes.back();
    }

    virtual ~bv_bounds_simplifier() {}

    virtual void assert_expr(expr * t, bool sign) {
        while (m.is_not(t, t)) {
            sign = !sign;
        }

        interval b;
        expr* t1;
        if (is_bound(t, t1, b)) {
            if (sign)
                VERIFY(b.negate(b));

            push();
            TRACE("bv", tout << (sign?"(not ":"") << mk_pp(t, m) << (sign ? ")" : "") << ": " << mk_pp(t1, m) << " in " << b << "\n";);
            interval& r = m_bound->insert_if_not_there2(t1, b)->get_data().m_value;
            VERIFY(r.intersect(b, r));
        }
    }

    virtual bool simplify(expr* t, expr_ref& result) {
        expr* t1;
        interval b, ctx, intr;
        result = 0;
        if (!is_bound(t, t1, b))
            return false;

        if (m_bound->find(t1, ctx)) {
            if (!b.intersect(ctx, intr)) {
                result = m.mk_false();
            } else if (intr == b) {
                // no improvement in range; do nothing
            } else if (intr.l == intr.h) {
                result = m.mk_eq(t1, m_bv.mk_numeral(intr.l, m.get_sort(t1)));
            } else if (ctx.implies(b)) {
                result = m.mk_true();
            }
        }

        CTRACE("bv", result != 0, tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << result << "\n";);
        return result != 0;
    }

    virtual void push() {
        TRACE("bv", tout << "push\n";);
        m_scopes.push_back(*m_bound);
        m_bound = &m_scopes.back();
    }

    virtual void pop(unsigned num_scopes) {
        TRACE("bv", tout << "pop: " << num_scopes << "\n";);
        m_scopes.shrink(m_scopes.size() - num_scopes);
        m_bound = &m_scopes.back();
    }

    virtual simplifier * translate(ast_manager & m) {
        return alloc(bv_bounds_simplifier, m);
    }

    virtual unsigned scope_level() const {
        return m_scopes.size() - 1;
    }
};

}

tactic * mk_bv_bounds_tactic(ast_manager & m, params_ref const & p) {
    return clean(alloc(ctx_simplify_tactic, m, alloc(bv_bounds_simplifier, m), p));
}
<commit_msg>bv_bounds: simplify negated expressions as well<commit_after>/*++
Copyright (c) 2016 Microsoft Corporation

Module Name:

    bv_bounds_tactic.cpp

Abstract:

    Contextual bounds simplification tactic.

Author:

    Nikolaj Bjorner (nbjorner) 2016-2-12

--*/

#include "bv_bounds_tactic.h"
#include "ctx_simplify_tactic.h"
#include "bv_decl_plugin.h"
#include "ast_pp.h"

static rational uMaxInt(unsigned sz) {
    return rational::power_of_two(sz) - rational::one();
}

namespace {

struct interval {
    // l < h: [l, h]
    // l > h: [0, h] U [l, UMAX_INT]
    rational l, h;
    unsigned sz;

    explicit interval() : l(0), h(0), sz(0) {}
    interval(const rational& l, const rational& h, unsigned sz) : l(l), h(h), sz(sz) {
        SASSERT(invariant());
    }

    bool invariant() const {
        return !l.is_neg() && !h.is_neg() && l <= uMaxInt(sz) && h <= uMaxInt(sz);
    }

    bool is_full() const { return l.is_zero() && h == uMaxInt(sz); }
    bool is_wrapped() const { return l > h; }

    bool operator==(const interval& b) const {
        SASSERT(sz == b.sz);
        return l == b.l && h == b.h;
    }
    bool operator!=(const interval& b) const { return !(*this == b); }

    bool implies(const interval& b) const {
        if (b.is_full())
            return true;
        if (is_full())
            return false;

        if (is_wrapped()) {
            // l >= b.l >= b.h >= h
            return b.is_wrapped() && h <= b.h && l >= b.l;
        } else if (b.is_wrapped()) {
            // b.l > b.h >= h >= l
            // h >= l >= b.l > b.h
            return h <= b.h || l >= b.l;
        } else {
            //
            return l >= b.l && h <= b.h;
        }
    }

    /// return false if intersection is unsat
    bool intersect(const interval& b, interval& result) const {
        if (is_full() || (l == b.l && h == b.h)) {
            result = b;
            return true;
        }
        if (b.is_full()) {
            result = *this;
            return true;
        }

        if (is_wrapped()) {
            if (b.is_wrapped()) {
                if (h >= b.l) {
                    result = b;
                } else if (b.h >= l) {
                    result = *this;
                } else {
                    result = interval(std::max(l, b.l), std::min(h, b.h), sz);
                }
            } else {
                return b.intersect(*this, result);
            }
        } else if (b.is_wrapped()) {
            // ... b.h ... l ... h ... b.l ..
            if (h < b.l && l > b.h) {
                return false;
            }
            // ... l ... b.l ... h ...
            if (h >= b.l && l <= b.h) {
                result = b;
            } else if (h >= b.l) {
                result = interval(b.l, h, sz);
            } else {
                // ... l .. b.h .. h .. b.l ...
                SASSERT(l <= b.h);
                result = interval(l, std::min(h, b.h), sz);
            }
        } else {
            if (l > b.h || h < b.l)
                return false;

            // 0 .. l.. l' ... h ... h'
            result = interval(std::max(l, b.l), std::min(h, b.h), sz);
        }
        return true;
    }

    /// return false if negation is empty
    bool negate(interval& result) const {
        if (is_full())
            return false;
        if (l.is_zero()) {
            result = interval(h + rational::one(), uMaxInt(sz), sz);
        } else if (uMaxInt(sz) == h) {
            result = interval(rational::zero(), l - rational::one(), sz);
        } else {
            result = interval(h + rational::one(), l - rational::one(), sz);
        }
        return true;
    }
};

std::ostream& operator<<(std::ostream& o, const interval& I) {
    o << "[" << I.l << ", " << I.h << "]";
    return o;
}

class bv_bounds_simplifier : public ctx_simplify_tactic::simplifier {
    ast_manager&                     m;
    bv_util                          m_bv;
    vector<obj_map<expr, interval> > m_scopes;
    obj_map<expr, interval>         *m_bound;

    bool is_bound(expr *e, expr*& v, interval& b) {
        rational n;
        expr *lhs, *rhs;
        unsigned sz;

        if (m_bv.is_bv_ule(e, lhs, rhs)) {
            if (m_bv.is_numeral(lhs, n, sz)) { // C ule x <=> x uge C
                b = interval(n, uMaxInt(sz), sz);
                v = rhs;
                return true;
            }
            if (m_bv.is_numeral(rhs, n, sz)) { // x ule C
                b = interval(rational::zero(), n, sz);
                v = lhs;
                return true;
            }
        } else if (m_bv.is_bv_sle(e, lhs, rhs)) {
            if (m_bv.is_numeral(lhs, n, sz)) { // C sle x <=> x sge C
                b = interval(n, rational::power_of_two(sz-1) - rational::one(), sz);
                v = rhs;
                return true;
            }
            if (m_bv.is_numeral(rhs, n, sz)) { // x sle C
                b = interval(rational::power_of_two(sz-1), n, sz);
                v = lhs;
                return true;
            }
        } else if (m.is_eq(e, lhs, rhs)) {
            if (m_bv.is_numeral(lhs, n, sz)) {
                b = interval(n, n, sz);
                v = rhs;
                return true;
            }
            if (m_bv.is_numeral(rhs, n, sz)) {
                b = interval(n, n, sz);
                v = lhs;
                return true;
            }
        } else if (m.is_not(e, lhs)) {
            if (is_bound(lhs, v, b))
                return b.negate(b);
        }
        return false;
    }

public:

    bv_bounds_simplifier(ast_manager& m) : m(m), m_bv(m) {
        m_scopes.push_back(obj_map<expr, interval>());
        m_bound = &m_scopes.back();
    }

    virtual ~bv_bounds_simplifier() {}

    virtual void assert_expr(expr * t, bool sign) {
        while (m.is_not(t, t)) {
            sign = !sign;
        }

        interval b;
        expr* t1;
        if (is_bound(t, t1, b)) {
            if (sign)
                VERIFY(b.negate(b));

            push();
            TRACE("bv", tout << (sign?"(not ":"") << mk_pp(t, m) << (sign ? ")" : "") << ": " << mk_pp(t1, m) << " in " << b << "\n";);
            interval& r = m_bound->insert_if_not_there2(t1, b)->get_data().m_value;
            VERIFY(r.intersect(b, r));
        }
    }

    virtual bool simplify(expr* t, expr_ref& result) {
        expr* t1;
        interval b, ctx, intr;
        result = 0;
        if (!is_bound(t, t1, b))
            return false;

        if (m_bound->find(t1, ctx)) {
            if (!b.intersect(ctx, intr)) {
                result = m.mk_false();
            } else if (intr.l == intr.h && intr != b) {
                result = m.mk_eq(t1, m_bv.mk_numeral(intr.l, m.get_sort(t1)));
            } else if (ctx.implies(b)) {
                result = m.mk_true();
            }
        }

        CTRACE("bv", result != 0, tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << result << "\n";);
        return result != 0;
    }

    virtual void push() {
        TRACE("bv", tout << "push\n";);
        m_scopes.push_back(*m_bound);
        m_bound = &m_scopes.back();
    }

    virtual void pop(unsigned num_scopes) {
        TRACE("bv", tout << "pop: " << num_scopes << "\n";);
        m_scopes.shrink(m_scopes.size() - num_scopes);
        m_bound = &m_scopes.back();
    }

    virtual simplifier * translate(ast_manager & m) {
        return alloc(bv_bounds_simplifier, m);
    }

    virtual unsigned scope_level() const {
        return m_scopes.size() - 1;
    }
};

}

tactic * mk_bv_bounds_tactic(ast_manager & m, params_ref const & p) {
    return clean(alloc(ctx_simplify_tactic, m, alloc(bv_bounds_simplifier, m), p));
}
<|endoftext|>


<commit_before><commit_msg>Fix to address a Boost.Filesystem exception being thrown on TLCC (glory). For some reason, a "bogus" directory is in the $PATH (by default) leading to a workdir test failure.  This commit adds a try/catch block to perform the analysis driver search (aka "which") even when $PATH contains directories that cannot be searched.<commit_after><|endoftext|>


<commit_before>#include <yuni/yuni.h>
#include <yuni/core/string.h>
#include <yuni/io/file.h>
#include <yuni/core/system/environment.h>
#include "nany/nany.h"
#include <memory>

using namespace Yuni;

#define likely(X)    YUNI_LIKELY(X)
#define unlikely(X)  YUNI_UNLIKELY(X)

//! Arbitrary maximum length (in bytes) of an input source
constexpr static size_t sourceMaxLength = 1024 * 1024 * 1024;
constexpr static int exitFailure = -42;

namespace std {

template<> struct default_delete<nyproject_t> final {
	void operator () (nyproject_t* ptr) { nyproject_unref(ptr); }
};

template<> struct default_delete<nybuild_t> final {
	inline void operator () (nybuild_t* ptr) { nybuild_unref(ptr); }
};

template<> struct default_delete<nyprogram_t> final {
	inline void operator () (nyprogram_t* ptr) { nyprogram_unref(ptr); }
};

} // namespace std

namespace { // anonymous

//! Create a new nany project
std::unique_ptr<nyproject_t> createProject(const nyrun_cf_t* const runcf) {
	nyproject_cf_t cf;
	if (runcf) {
		memcpy(&(cf), &(runcf->project), sizeof(nyproject_cf_t));
		memcpy(&(cf.allocator), &(runcf->allocator), sizeof(nyallocator_t));
	}
	else
		nyproject_cf_init(&cf);
	return std::unique_ptr<nyproject_t> {nyproject_create(&cf)};
}

std::unique_ptr<nyprogram_t> build(const nyrun_cf_t* const runcf, nyproject_t* project) {
	if (unlikely(!project))
		return nullptr;
	nybuild_cf_t cf;
	bool verbose;
	if (runcf) {
		verbose = (runcf->verbose != nyfalse);
		memcpy(&(cf),           &(runcf->build),     sizeof(nybuild_cf_t));
		memcpy(&(cf.allocator), &(runcf->allocator), sizeof(nyallocator_t));
		memcpy(&(cf.console),   &(runcf->console),   sizeof(nyconsole_t));
	}
	else {
		verbose = false;
		nybuild_cf_init(&cf, project);
	}
	auto build = std::unique_ptr<nybuild_t> {nybuild_prepare(project, &cf)};
	auto bStatus = nybuild(build.get());
	if (bStatus == nyfalse) {
		// an error has occured
		nybool_t addHeader = (verbose) ? nytrue : nyfalse;
		nybuild_print_report_to_console(build.get(), addHeader);
		return nullptr;
	}
	if (unlikely(verbose))
		nybuild_print_report_to_console(build.get(), nytrue);
	nyprogram_cf_t pcf;
	if (runcf) {
		memcpy(&(pcf),           &(runcf->program),   sizeof(nyprogram_cf_t));
		memcpy(&(pcf.allocator), &(runcf->allocator), sizeof(nyallocator_t));
		memcpy(&(pcf.console),   &(runcf->console),   sizeof(nyconsole_t));
	}
	else
		nyprogram_cf_init(&pcf, &cf);
	return std::unique_ptr<nyprogram_t>(nyprogram_prepare(build.get(), &pcf));
}

//! Try to compile the input script filename
std::unique_ptr<nyprogram_t> compileFile(const nyrun_cf_t* cf, const AnyString& argv0, String& file) {
	auto project = createProject(cf);
	if (!project)
		return nullptr;
	IO::Canonicalize(file, argv0);
	auto r = nyproject_add_source_from_file_n(project.get(), file.c_str(), file.size());
	if (r != nyfalse)
		return build(cf, project.get());
	return nullptr;
}

//! Try to compile a list of input files
std::unique_ptr<nyprogram_t> compileFilelist(const nyrun_cf_t* cf, const char** list, uint32_t count) {
	auto project = createProject(cf);
	if (!project)
		return nullptr;
	String filename;
	filename.reserve(1024);
	for (uint32_t i = 0; i != count; ++i) {
		IO::Canonicalize(filename, list[i]);
		auto r = nyproject_add_source_from_file_n(project.get(), filename.c_str(), filename.size());
		if (YUNI_UNLIKELY(r == nyfalse))
			return nullptr;
	}
	return build(cf, project.get());
}

//! Try to compile the input source
std::unique_ptr<nyprogram_t> compileSource(const nyrun_cf_t* cf, const AnyString& source) {
	auto project = createProject(cf);
	if (!project)
		return nullptr;
	auto r = nyproject_add_source_n(project.get(), source.c_str(), source.size());
	if (r != nyfalse)
		return build(cf, project.get());
	return nullptr;
}

int run(nyprogram_t* const program, const char* argv0, uint32_t argc, const char** argv) {
	int exitstatus = exitFailure;
	if (argc == 0 or argv == nullptr) {
		const char* nargv[] = { argv0, nullptr };
		exitstatus = nyprogram_main(program, 1u, nargv);
	}
	else {
		auto** nargv = (const char**)::malloc((argc + 1 + 1) * sizeof(const char**));
		if (nargv) {
			nargv[0] = argv0;
			for (uint32_t i = 0; i != argc; ++i)
				nargv[i + 1] = argv[i];
			nargv[argc + 1] = nullptr;
			exitstatus = nyprogram_main(program, argc, nargv);
			free(nargv);
		}
	}
	return exitstatus;
}

} // anonymous namespace

extern "C" int nyrun_n(const nyrun_cf_t* cf, const char* source, size_t length, uint32_t argc,
					   const char** argv) {
	if (source and length != 0 and length < sourceMaxLength) { // arbitrary
		auto program = compileSource(cf, AnyString{source, (uint32_t) length});
		if (!!program)
			return run(program.get(), "a.out", argc, argv);
	}
	return exitFailure;
}

extern "C" int nyrun(const nyrun_cf_t* cf, const char* source, uint32_t argc, const char** argv) {
	size_t length = (source) ? strlen(source) : 0;
	if (source and length != 0 and length < sourceMaxLength) { // arbitrary
		auto program = compileSource(cf, AnyString{source, (uint32_t) length});
		if (!!program)
			return run(program.get(), "a.out", argc, argv);
	}
	return exitFailure;
}

extern "C" int nyrun_file_n(const nyrun_cf_t* cf, const char* file, size_t length, uint32_t argc,
							const char** argv) {
	if (file and length != 0 and length < 32768) {
		String filename;
		auto program = compileFile(cf, AnyString{file, static_cast<uint32_t>(length)}, filename);
		if (!!program)
			return run(program.get(), filename.c_str(), argc, argv);
	}
	return exitFailure;
}

extern "C" int nyrun_file(const nyrun_cf_t* cf, const char* file, uint32_t argc, const char** argv) {
	size_t length = (file) ? strlen(file) : 0;
	if (file and length != 0 and length < 32768) {
		String filename;
		auto program = compileFile(cf, AnyString{file, static_cast<uint32_t>(length)}, filename);
		if (!!program)
			return run(program.get(), filename.c_str(), argc, argv);
	}
	return exitFailure;
}

extern "C" int nyrun_filelist(const nyrun_cf_t* cf, const char** files, uint32_t file_count, uint32_t argc,
							  const char** argv) {
	if (files and file_count != 0) {
		auto program = compileFilelist(cf, files, file_count);
		if (!!program)
			return run(program.get(), "a,out", argc, argv);
	}
	return exitFailure;
}

extern "C" void nyrun_cf_init(nyrun_cf_t* cf) {
	if (cf) {
		// reset the whole struct
		memset(cf, 0x0, sizeof(nyrun_cf_t));
		size_t limit = static_cast<size_t>(System::Environment::ReadAsUInt64("NANY_MEMORY_LIMIT"));
		if (0 == limit)
			nany_memalloc_set_default(&(cf->allocator));
		else
			nany_memalloc_set_with_limit(&(cf->allocator), limit);
		cf->build.entrypoint.size  = 4;
		cf->build.entrypoint.c_str = "main";
		cf->program.entrypoint = cf->build.entrypoint;
		// default output
		nyconsole_cf_set_stdcout(&(cf->console));
	}
}

extern "C" void nyrun_cf_release(const nyrun_cf_t* cf) {
	if (cf) {
		if (cf->console.release)
			cf->console.release(&(cf->console));
		if (cf->allocator.release)
			cf->allocator.release(&(cf->allocator));
	}
}
<commit_msg>c-api: fix exception handling<commit_after>#include <yuni/yuni.h>
#include <yuni/core/string.h>
#include <yuni/io/file.h>
#include <yuni/core/system/environment.h>
#include "nany/nany.h"
#include <memory>

using namespace Yuni;

#define likely(X)    YUNI_LIKELY(X)
#define unlikely(X)  YUNI_UNLIKELY(X)

//! Arbitrary maximum length (in bytes) of an input source
constexpr static size_t sourceMaxLength = 1024 * 1024 * 1024;
constexpr static int exitFailure = -42;

namespace std {

template<> struct default_delete<nyproject_t> final {
	void operator () (nyproject_t* ptr) { nyproject_unref(ptr); }
};

template<> struct default_delete<nybuild_t> final {
	inline void operator () (nybuild_t* ptr) { nybuild_unref(ptr); }
};

template<> struct default_delete<nyprogram_t> final {
	inline void operator () (nyprogram_t* ptr) { nyprogram_unref(ptr); }
};

} // namespace std

namespace { // anonymous

template<class T>
inline std::unique_ptr<T> make_unique_from_ptr(T* pointer) {
	if (unlikely(!pointer))
		throw std::runtime_error("failed");
	return std::unique_ptr<T>{pointer};
}

//! Create a new nany project
std::unique_ptr<nyproject_t> createProject(const nyrun_cf_t* const runcf) {
	nyproject_cf_t cf;
	if (runcf) {
		memcpy(&(cf), &(runcf->project), sizeof(nyproject_cf_t));
		memcpy(&(cf.allocator), &(runcf->allocator), sizeof(nyallocator_t));
	}
	else
		nyproject_cf_init(&cf);
	return make_unique_from_ptr<nyproject_t>(nyproject_create(&cf));
}

std::unique_ptr<nyprogram_t> build(const nyrun_cf_t* const runcf, std::unique_ptr<nyproject_t> project) {
	if (unlikely(!project))
		return nullptr;
	nybuild_cf_t cf;
	bool verbose;
	if (runcf) {
		verbose = (runcf->verbose != nyfalse);
		memcpy(&(cf),           &(runcf->build),     sizeof(nybuild_cf_t));
		memcpy(&(cf.allocator), &(runcf->allocator), sizeof(nyallocator_t));
		memcpy(&(cf.console),   &(runcf->console),   sizeof(nyconsole_t));
	}
	else {
		verbose = false;
		nybuild_cf_init(&cf, project.get());
	}
	auto buildinfo = make_unique_from_ptr<nybuild_t>(nybuild_prepare(project.get(), &cf));
	auto bStatus = nybuild(buildinfo.get());
	if (unlikely(bStatus == nyfalse)) {
		nybool_t addHeader = (verbose) ? nytrue : nyfalse;
		nybuild_print_report_to_console(buildinfo.get(), addHeader);
		throw std::runtime_error("failed to build");
	}
	if (unlikely(verbose))
		nybuild_print_report_to_console(buildinfo.get(), nytrue);
	nyprogram_cf_t pcf;
	if (runcf) {
		memcpy(&(pcf),           &(runcf->program),   sizeof(nyprogram_cf_t));
		memcpy(&(pcf.allocator), &(runcf->allocator), sizeof(nyallocator_t));
		memcpy(&(pcf.console),   &(runcf->console),   sizeof(nyconsole_t));
	}
	else
		nyprogram_cf_init(&pcf, &cf);
	return make_unique_from_ptr<nyprogram_t>(nyprogram_prepare(buildinfo.get(), &pcf));
}

//! Try to compile the input script filename
std::unique_ptr<nyprogram_t> compileFile(const nyrun_cf_t* cf, const AnyString& argv0, String& file) {
	auto project = createProject(cf);
	IO::Canonicalize(file, argv0);
	auto r = nyproject_add_source_from_file_n(project.get(), file.c_str(), file.size());
	if (r == nyfalse)
		throw std::runtime_error("failed to add source");
	return build(cf, std::move(project));
}

//! Try to compile a list of input files
std::unique_ptr<nyprogram_t> compileFilelist(const nyrun_cf_t* cf, const char** list, uint32_t count) {
	auto project = createProject(cf);
	String filename;
	filename.reserve(1024);
	for (uint32_t i = 0; i != count; ++i) {
		IO::Canonicalize(filename, list[i]);
		auto r = nyproject_add_source_from_file_n(project.get(), filename.c_str(), filename.size());
		if (YUNI_UNLIKELY(r == nyfalse))
			throw std::runtime_error("failed to add source");
	}
	return build(cf, std::move(project));
}

//! Try to compile the input source
std::unique_ptr<nyprogram_t> compileSource(const nyrun_cf_t* cf, const AnyString& source) {
	auto project = createProject(cf);
	auto r = nyproject_add_source_n(project.get(), source.c_str(), source.size());
	if (r == nyfalse)
		throw std::runtime_error("failed to add source");
	return build(cf, std::move(project));
}

int run(nyprogram_t* const program, const char* argv0, uint32_t argc, const char** argv) {
	int exitstatus = exitFailure;
	if (argc == 0 or argv == nullptr) {
		const char* nargv[] = { argv0, nullptr };
		exitstatus = nyprogram_main(program, 1u, nargv);
	}
	else {
		auto** nargv = (const char**)::malloc((argc + 1 + 1) * sizeof(const char**));
		if (nargv) {
			nargv[0] = argv0;
			for (uint32_t i = 0; i != argc; ++i)
				nargv[i + 1] = argv[i];
			nargv[argc + 1] = nullptr;
			exitstatus = nyprogram_main(program, argc, nargv);
			free(nargv);
		}
	}
	return exitstatus;
}

} // anonymous namespace

extern "C" int nyrun_n(const nyrun_cf_t* cf, const char* source, size_t length, uint32_t argc,
					   const char** argv) {
	if (source and length != 0 and length < sourceMaxLength) { // arbitrary
		try {
			auto program = compileSource(cf, AnyString{source, (uint32_t) length});
			if (!!program)
				return run(program.get(), "a.out", argc, argv);
		}
		catch (...) {}
	}
	return exitFailure;
}

extern "C" int nyrun(const nyrun_cf_t* cf, const char* source, uint32_t argc, const char** argv) {
	size_t length = (source) ? strlen(source) : 0;
	if (source and length != 0 and length < sourceMaxLength) { // arbitrary
		try {
			auto program = compileSource(cf, AnyString{source, (uint32_t) length});
			if (!!program)
				return run(program.get(), "a.out", argc, argv);
		}
		catch (...) {}
	}
	return exitFailure;
}

extern "C" int nyrun_file_n(const nyrun_cf_t* cf, const char* file, size_t length, uint32_t argc,
							const char** argv) {
	if (file and length != 0 and length < 32768) {
		try {
			String filename;
			auto program = compileFile(cf, AnyString{file, static_cast<uint32_t>(length)}, filename);
			if (!!program)
				return run(program.get(), filename.c_str(), argc, argv);
		}
		catch (...) {}
	}
	return exitFailure;
}

extern "C" int nyrun_file(const nyrun_cf_t* cf, const char* file, uint32_t argc, const char** argv) {
	size_t length = (file) ? strlen(file) : 0;
	if (file and length != 0 and length < 32768) {
		try {
			String filename;
			auto program = compileFile(cf, AnyString{file, static_cast<uint32_t>(length)}, filename);
			if (!!program)
				return run(program.get(), filename.c_str(), argc, argv);
		}
		catch (...) {}
	}
	return exitFailure;
}

extern "C" int nyrun_filelist(const nyrun_cf_t* cf, const char** files, uint32_t file_count, uint32_t argc,
							  const char** argv) {
	if (files and file_count != 0) {
		try {
			auto program = compileFilelist(cf, files, file_count);
			if (!!program)
				return run(program.get(), "a,out", argc, argv);
		}
		catch (...) {}
	}
	return exitFailure;
}

extern "C" void nyrun_cf_init(nyrun_cf_t* cf) {
	if (cf) {
		// reset the whole struct
		memset(cf, 0x0, sizeof(nyrun_cf_t));
		size_t limit = static_cast<size_t>(System::Environment::ReadAsUInt64("NANY_MEMORY_LIMIT"));
		if (0 == limit)
			nany_memalloc_set_default(&(cf->allocator));
		else
			nany_memalloc_set_with_limit(&(cf->allocator), limit);
		cf->build.entrypoint.size  = 4;
		cf->build.entrypoint.c_str = "main";
		cf->program.entrypoint = cf->build.entrypoint;
		// default output
		nyconsole_cf_set_stdcout(&(cf->console));
	}
}

extern "C" void nyrun_cf_release(const nyrun_cf_t* cf) {
	if (cf) {
		if (cf->console.release)
			cf->console.release(&(cf->console));
		if (cf->allocator.release)
			cf->allocator.release(&(cf->allocator));
	}
}
<|endoftext|>


<commit_before>#include "MatrixIntegrationTest.h"
#include "Utilities.h"
#include "matrix/MatrixHelper.h"
#include "matrix/MatrixElf.h"
#include "matrix/smp/SMPMatrixElf.h"
#include "common/SchedulerFactory.h"

#include <string>
#include <fstream>
#include <future>
#include <boost/lexical_cast.hpp>
#include <sys/wait.h>
#include <signal.h>

using namespace std;

const int           TIMEOUT_SECONDS = 10;
const int           NUM_NODES       = 8;
const char* const   CONF_FILENAME   = "test_config.cfg";
const char* const   INPUT_FILENAME  = "example_data/matrix/small_input.bin";
const char* const   OUTPUT_FILENAME = "small_output.bin";
const char* const   MPIRUN_PATH     = MPIEXEC; // defined by CMake file

TEST_F(MatrixIntegrationTest, TestSmallInputSMPSchedulingOffline)
{
    MatrixIntegrationTest::executeWith("matrix");
}

TEST_F(MatrixIntegrationTest, TestSmallInputSMPSchedulingOnline)
{
    MatrixIntegrationTest::executeWith("matrix_online", "row-wise");
}

void MatrixIntegrationTest::executeWith(
    const char* matrixCategory,
    const char* scheduling)
{
    MatrixIntegrationTest::setupConfigFile();
    pid_t pid = MatrixIntegrationTest::spawnChildProcess(matrixCategory, scheduling);

    auto future = async(std::launch::async, [pid]() -> bool
    {
        int status;
        waitpid(pid, &status, 0);
        return WIFEXITED(status) && (WEXITSTATUS(status) == 0);
    });
    auto status = future.wait_for(std::chrono::seconds(TIMEOUT_SECONDS));

    if(status != future_status::ready)
    {
        kill(pid, SIGKILL);
        future.wait();
        FAIL() << "Process timed out";
    }

    ASSERT_TRUE(future.get()) << "Process not exited normally";

    Matrix<float> expectedMatrix, actualMatrix;
    std::tie(expectedMatrix, actualMatrix) = MatrixIntegrationTest::readMatrices();

    EXPECT_TRUE(AreMatricesEquals(expectedMatrix, actualMatrix));
}

void MatrixIntegrationTest::TearDown()
{
    remove(OUTPUT_FILENAME);
    remove(CONF_FILENAME);
}

void MatrixIntegrationTest::setupConfigFile()
{
    ofstream config(CONF_FILENAME);
    for (int i=0; i<NUM_NODES; ++i)
        config << 1 << endl;
}

pid_t MatrixIntegrationTest::spawnChildProcess(
    const char* matrixCategory,
    const char* scheduling)
{
    string schedulingStrategy(scheduling);
    pid_t pid = fork();
    if(pid == 0) // child process
    {
        bool usesOnlineScheduling = schedulingStrategy != "";
        execl(MPIRUN_PATH,
            MPIRUN_PATH,
            "-n", boost::lexical_cast<string>(NUM_NODES).c_str(),
            "--tag-output",
            "build/src/main/dwarf_mine",
            "-m", "smp",
            "-n", "1",
            "-w", "0",
            "-q",
            "-i", INPUT_FILENAME,
            "-o", OUTPUT_FILENAME,
            "--import_configuration", CONF_FILENAME,
            "-c", matrixCategory,
            (usesOnlineScheduling ? "--mpi_thread_multiple" : ""),
            (schedulingStrategy != "" ? "-s" : ""),
            (schedulingStrategy != "" ? scheduling : ""),
            nullptr
        );
        exit(-1);
    }
    return pid;
}

std::tuple<Matrix<float>, Matrix<float>> MatrixIntegrationTest::readMatrices()
{
    ifstream input("small_input.bin", ios_base::binary);
    auto inputMatrices = MatrixHelper::readMatrixPairFrom(input);
    auto actualMatrix = MatrixHelper::readMatrixFrom("small_output.bin");

    auto leftMatrix = inputMatrices.first;
    auto rightMatrix = inputMatrices.second;

    SMPMatrixElf elf;
    auto expectedMatrix = elf.multiply(leftMatrix, rightMatrix);
    return make_tuple<Matrix<float>, Matrix<float>>(move(expectedMatrix), move(actualMatrix));
}
<commit_msg>Using filename constants everywhere in MatrixIntegrationTest<commit_after>#include "MatrixIntegrationTest.h"
#include "Utilities.h"
#include "matrix/MatrixHelper.h"
#include "matrix/MatrixElf.h"
#include "matrix/smp/SMPMatrixElf.h"
#include "common/SchedulerFactory.h"

#include <string>
#include <fstream>
#include <future>
#include <boost/lexical_cast.hpp>
#include <sys/wait.h>
#include <signal.h>

using namespace std;

const int           TIMEOUT_SECONDS = 10;
const int           NUM_NODES       = 8;
const char* const   CONF_FILENAME   = "test_config.cfg";
const char* const   INPUT_FILENAME  = "example_data/matrix/small_input.bin";
const char* const   OUTPUT_FILENAME = "small_output.bin";
const char* const   MPIRUN_PATH     = MPIEXEC; // defined by CMake file
const char* const   EXECUTABLE_PATH = "build/src/main/dwarf_mine";

TEST_F(MatrixIntegrationTest, TestSmallInputSMPSchedulingOffline)
{
    MatrixIntegrationTest::executeWith("matrix");
}

TEST_F(MatrixIntegrationTest, TestSmallInputSMPSchedulingOnline)
{
    MatrixIntegrationTest::executeWith("matrix_online", "row-wise");
}

void MatrixIntegrationTest::executeWith(
    const char* matrixCategory,
    const char* scheduling)
{
    MatrixIntegrationTest::setupConfigFile();
    pid_t pid = MatrixIntegrationTest::spawnChildProcess(matrixCategory, scheduling);

    auto future = async(std::launch::async, [pid]() -> bool
    {
        int status;
        waitpid(pid, &status, 0);
        return WIFEXITED(status) && (WEXITSTATUS(status) == 0);
    });
    auto status = future.wait_for(std::chrono::seconds(TIMEOUT_SECONDS));

    if(status != future_status::ready)
    {
        kill(pid, SIGKILL);
        future.wait();
        FAIL() << "Process timed out";
    }

    ASSERT_TRUE(future.get()) << "Process not exited normally";

    Matrix<float> expectedMatrix, actualMatrix;
    std::tie(expectedMatrix, actualMatrix) = MatrixIntegrationTest::readMatrices();

    EXPECT_TRUE(AreMatricesEquals(expectedMatrix, actualMatrix));
}

void MatrixIntegrationTest::TearDown()
{
    remove(OUTPUT_FILENAME);
    remove(CONF_FILENAME);
}

void MatrixIntegrationTest::setupConfigFile()
{
    ofstream config(CONF_FILENAME);
    for (int i=0; i<NUM_NODES; ++i)
        config << 1.0/NUM_NODES << endl;
}

pid_t MatrixIntegrationTest::spawnChildProcess(
    const char* matrixCategory,
    const char* scheduling)
{
    string schedulingStrategy(scheduling);
    pid_t pid = fork();
    if(pid == 0) // child process
    {
        bool usesOnlineScheduling = schedulingStrategy != "";
        execl(MPIRUN_PATH,
            MPIRUN_PATH,
            "-n", boost::lexical_cast<string>(NUM_NODES).c_str(),
            "--tag-output",
            EXECUTABLE_PATH,
            "-m", "smp",
            "-n", "1",
            "-w", "0",
            "-q",
            "-i", INPUT_FILENAME,
            "-o", OUTPUT_FILENAME,
            "--import_configuration", CONF_FILENAME,
            "-c", matrixCategory,
            (usesOnlineScheduling ? "--mpi_thread_multiple" : ""),
            (schedulingStrategy != "" ? "-s" : ""),
            (schedulingStrategy != "" ? scheduling : ""),
            nullptr
        );
        exit(-1);
    }
    return pid;
}

std::tuple<Matrix<float>, Matrix<float>> MatrixIntegrationTest::readMatrices()
{
    ifstream input(INPUT_FILENAME, ios_base::binary);
    auto inputMatrices = MatrixHelper::readMatrixPairFrom(input);
    auto actualMatrix = MatrixHelper::readMatrixFrom(OUTPUT_FILENAME);

    auto leftMatrix = inputMatrices.first;
    auto rightMatrix = inputMatrices.second;

    SMPMatrixElf elf;
    auto expectedMatrix = elf.multiply(leftMatrix, rightMatrix);
    return make_tuple<Matrix<float>, Matrix<float>>(move(expectedMatrix), move(actualMatrix));
}
<|endoftext|>


<commit_before>#include <modules/graph2d/processors/plot2d.h>

#include <modules/plotting/utils/axisutils.h>
#include <modules/opengl/texture/textureutils.h>
#include <inviwo/core/util/raiiutils.h>
#include <inviwo/core/algorithm/boundingbox.h>
#include <inviwo/core/rendering/meshdrawerfactory.h>

#include <modules/opengl/texture/textureutils.h>
#include <modules/opengl/shader/shaderutils.h>
#include <modules/opengl/openglutils.h>

#include <modules/opengl/openglutils.h>
#include <inviwo/core/datastructures/coordinatetransformer.h>
#include <modules/opengl/texture/textureutils.h>

namespace inviwo {

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo Plot2dProcessor::processorInfo_{
    "org.inviwo.Plot2D",    // Class identifier
    "Plot2D",                 // Display name
    "Plotting",               // Category
    CodeState::Stable,        // Code state
    "Plotting",           // Tags
};

const ProcessorInfo Plot2dProcessor::getProcessorInfo() const { return processorInfo_; }

Plot2dProcessor::Plot2dProcessor()
    : Processor()
    , inport_("inport")
    , imageInport_("imageInport")
    , outport_("outport")
    , xAxis_("xAxis", "X Axis")
    , yAxis_("yAxis", "Y Axis")
	, position_("position", "Position", vec3(0), vec3(-25), vec3(25), vec3(0.01))
	, size_("size", "Size", vec2(3), vec2(0.01), vec2(25), vec2(0.01))
    , camera_("camera", "Camera")
	, camera2d_{ InviwoApplication::getPtr()->getCameraFactory()->create("OrthographicCamera") }
    , trackball_(&camera_)
	, axisRenderers_({ {xAxis_, yAxis_} })
	, xAxisSelection_("xAxisSelection", "X Axis")
	, yAxisSelection_("yAxisSelection", "Y Axis")
	, toggle3d_("toggle3d", "Render in 3D space")
	, lineMesh_( std::make_shared<BasicMesh>() )
	, meshDrawer_( std::unique_ptr<MeshDrawer>() )
	, shader_("linerenderer.vert", "linerenderer.geom", "linerenderer.frag", false)
    {

	shader_.onReload([this]() { invalidate(InvalidationLevel::InvalidResources); });

	MeshDrawerFactory* factory = InviwoApplication::getPtr()->getMeshDrawerFactory();
	meshDrawer_ = std::move(factory->create(lineMesh_.get()));

	// Setup ports
    imageInport_.setOptional(true);
    addPort(inport_);
    addPort(imageInport_);
    addPort(outport_);

	// Add properties
	addProperty(toggle3d_);
	addProperty(position_);
	addProperty(size_);
	addProperties(xAxisSelection_, yAxisSelection_);
	addProperties(xAxis_, yAxis_);
	addProperty(camera_);
	addProperty(trackball_);

	// Set up property default values
	toggle3d_.set(false);
	camera_.setVisible(false);
	camera_.setCollapsed(true);
	trackball_.setVisible(false);
	trackball_.setCollapsed(true);

	// Initialize the 2d camera.
	camera2d_->setLookFrom(vec3(0, 0, 100));
	camera2d_->setLookTo(vec3(0, 0, 0));
	camera2d_->setLookUp(vec3(0, 1, 0));
	camera2d_->setFarPlaneDist(200);
	camera2d_->setNearPlaneDist(1);

	// Axis default values.
	xAxis_.setCaption("x");
	yAxis_.setCaption("y");
	yAxis_.orientation_.setSelectedDisplayName("Vertical");

	for (auto axis : { &xAxis_, &yAxis_ }) {
		axis->captionSettings_.offset_.set(0.7f);
		axis->captionSettings_.position_.set(0.5f);
		axis->labelSettings_.offset_.set(0.7f);

		axis->majorTicks_.tickLength_.set(0.3f);
		axis->majorTicks_.tickWidth_.set(1.5f);
		axis->majorTicks_.style_.set(plot::TickStyle::Outside);
		axis->majorTicks_.setCurrentStateAsDefault();

		axis->minorTicks_.tickLength_.set(0.15f);
		axis->minorTicks_.tickWidth_.set(1.3f);
		axis->minorTicks_.style_.set(plot::TickStyle::Outside);
		axis->minorTicks_.setCurrentStateAsDefault();

		axis->setCollapsed(true);
		axis->orientation_.setVisible(false);
		axis->placement_.setVisible(false);
		axis->flipped_.setVisible(false);
	}

	// Event callbacks
	toggle3d_.onChange([this] {
		position_.setVisible(toggle3d_.get());
		size_.setVisible(toggle3d_.get());
		camera_.setVisible(toggle3d_.get());
		trackball_.setVisible(toggle3d_.get());
		updateDimensions();
	});
	size_.onChange([this] { updateDimensions(); });
	position_.onChange([this] { updateDimensions(); });

	inport_.onChange([this] {
		reloadDatasets();
		updatePlotData(); });
	xAxisSelection_.onChange([this] { updatePlotData(); });
	yAxisSelection_.onChange([this] { updatePlotData(); });
	xAxis_.range_.onChange([this] { updatePlotData(); });
	yAxis_.range_.onChange([this] { updatePlotData(); });
	xAxis_.useDataRange_.onChange([this] { updatePlotData(); });
	yAxis_.useDataRange_.onChange([this] { updatePlotData(); });
}

void Plot2dProcessor::initializeResources() {
	LogInfo("Initializing resources plot2d");

	shader_[ShaderType::Geometry]->addShaderDefine("ENABLE_ADJACENCY", "0");
	//shader_[ShaderType::Fragment]->addShaderDefine("ENABLE_ROUND_DEPTH_PROFILE");

	// See createLineStripMesh()
	shader_[ShaderType::Vertex]->addInDeclaration("in_" + toString(BufferType::PositionAttrib),
		static_cast<int>(BufferType::PositionAttrib),
		"vec3");
	shader_[ShaderType::Vertex]->addInDeclaration("in_" + toString(BufferType::ColorAttrib),
		static_cast<int>(BufferType::ColorAttrib),
		"vec4");
	shader_[ShaderType::Vertex]->addInDeclaration("in_" + toString(BufferType::TexcoordAttrib),
		static_cast<int>(BufferType::TexcoordAttrib),
		"vec2");
	shader_.build();
	shader_.activate();
	shader_.setUniform("antialiasing", 0.0f);
	shader_.setUniform("miterLimit", 1.0f);
	shader_.deactivate();
}

void Plot2dProcessor::process() {
	LogInfo("Process start");
	if (imageInport_.isReady()) {
		utilgl::activateTargetAndCopySource(outport_, imageInport_, ImageType::ColorDepth);
	}
	else {
		utilgl::activateAndClearTarget(outport_, ImageType::ColorDepth);
	}
	const size2_t dims = outport_.getDimensions();
	if (!toggle3d_.get() && oldDims_ != dims) updateDimensions();

	// Save a pointer to the camera that will be used
	Camera* activeCamera;
	if (toggle3d_.get())
		activeCamera = &camera_.get();
	else
		activeCamera = camera2d_.get();

	vec3 xVector(1, 0, 0);
	vec3 yVector(0, 1, 0);

	if (toggle3d_.get()) {
		// Set the normal of the graph plane to point towards camera.
		yVector = glm::normalize( camera_.getLookUp() );
		xVector = glm::normalize( glm::cross(yVector, camera_.getLookFrom() - camera_.getLookTo()) );
		lineMesh_->setBasis(Matrix<3U, float>(
			xVector * graphDims_[0],
			yVector * graphDims_[1],
			vec3(0, 0, 1)));
	}

	// Render lines.
	shader_.activate();
	utilgl::setShaderUniforms(shader_, *meshDrawer_->getMesh(), "geometry");
	utilgl::setShaderUniforms(shader_, *activeCamera, "camera");
	shader_.setUniform("screenDim", vec2(outport_.getDimensions()));
	shader_.setUniform("lineWidth", 2);
	meshDrawer_->draw();
	shader_.deactivate();

	// Render x and y axis
	axisRenderers_[0].render(activeCamera, dims, origin_, origin_ + xVector * graphDims_[0], yVector);
	axisRenderers_[1].render(activeCamera, dims, origin_, origin_ + yVector * graphDims_[1], xVector);

	utilgl::deactivateCurrentTarget();
}

void Plot2dProcessor::reloadDatasets() {
	if (!inport_.hasData()) {
		xAxisSelection_.clearOptions();
		yAxisSelection_.clearOptions();
		return;
	}
	const std::shared_ptr<const DataFrame> dataframe = inport_.getData();
	// Update column selection properties
	std::vector<OptionPropertyStringOption> options;
	for (const auto& column : *dataframe) {
		options.emplace_back(column->getHeader(), column->getHeader(), column->getHeader());
	}

	xAxisSelection_.replaceOptions(options);
	yAxisSelection_.replaceOptions(options);
	xAxisSelection_.setCurrentStateAsDefault();
	yAxisSelection_.setCurrentStateAsDefault();
}

void Plot2dProcessor::updateDimensions() {
	if (toggle3d_.get()) {
		origin_ = position_.get();
		graphDims_ = size_.get();
	}
	else {
		const size2_t dims = outport_.getDimensions();
		const float aspect = (float)dims[0] / (float)dims[1];
		const float scale = (double)dims[0] / 512;
		const float width = 50 * scale;
		const float height = width / aspect;
		const float padding = 50 * width / (double)dims[0];

		oldDims_ = dims;
		origin_ = vec3(-width / 2 + padding, -height / 2 + padding, 0);
		graphDims_ = vec2(width - 2 * padding, height - 2 * padding);
		// Update 2d camera to fit new dimensions.
		static_cast<OrthographicCamera*>(camera2d_.get())->setFrustum({ -width / 2.0f, +width / 2.0f, -width / 2.0f / aspect, +width / 2.0f / aspect });
	}
	// Scale and offset line mesh to align with axises.
	lineMesh_->setBasis(Matrix<3U, float>(graphDims_[0], 0, 0, 0, graphDims_[1], 0, 0, 0, 1));
	lineMesh_->setOffset(origin_);
}

void Plot2dProcessor::updatePlotData() {
	// Reset line mesh
	lineMesh_ = std::make_shared<BasicMesh>();
	meshDrawer_ = std::move(InviwoApplication::getPtr()->getMeshDrawerFactory()->create(lineMesh_.get()));

	if (!inport_.hasData()) return;

	const std::shared_ptr<const DataFrame> dataframe = inport_.getData();
	const std::shared_ptr<const Column> xCol = dataframe->getColumn(xAxisSelection_.getSelectedIndex());
	const std::shared_ptr<const Column> yCol = dataframe->getColumn(yAxisSelection_.getSelectedIndex());
	size_t nValues = xCol->getSize();

	if (xCol->getSize() < 2 || yCol->getSize() < 2 || yCol->getSize() != xCol->getSize()) return;

	// Set ranges for x and y axis
	if (xAxis_.getUseDataRange()) {
		dvec2 xrange(xCol->getAsDouble(0), xCol->getAsDouble(0));
		for (size_t i = 1; i < nValues; ++i) {
			double v = xCol->getAsDouble(i);
			if (v < xrange[0]) xrange[0] = v;
			if (v > xrange[1]) xrange[1] = v;
		}
		xAxis_.range_.set(xrange);
	}

	if (yAxis_.getUseDataRange()) {
		dvec2 yrange(yCol->getAsDouble(0), yCol->getAsDouble(0));
		for (size_t i = 1; i < nValues; ++i) {
			if (xCol->getAsDouble(i) < xAxis_.getRange()[0] || xCol->getAsDouble(i) > xAxis_.getRange()[1]) {
				continue;
			}
			double v = yCol->getAsDouble(i);
			if (v < yrange[0]) yrange[0] = v;
			if (v > yrange[1]) yrange[1] = v;
		}
		if (yrange[0] == yrange[1]) yrange[1] += 1;
		yAxis_.range_.set(yrange);
	}

	const double offsetX = -xAxis_.getRange()[0];
	const double offsetY = -yAxis_.getRange()[0];
	const double scaleX = 1.0f / (xAxis_.getRange()[1] - xAxis_.getRange()[0]);
	const double scaleY = 1.0f / (yAxis_.getRange()[1] - yAxis_.getRange()[0]);

	std::shared_ptr<IndexBufferRAM> indices = lineMesh_->addIndexBuffer(DrawType::Lines, ConnectivityType::None);
	vec4 color(0.5, 0.3, 0.8, 1);

	auto getPoint = [xCol, yCol, offsetX, offsetY, scaleX, scaleY](const size_t index) {
		return vec3((xCol->getAsDouble(index) + offsetX)*scaleX, (yCol->getAsDouble(index) + offsetY)*scaleY, 0);
	};
	//// Add point from dataframe to line mesh
	for (size_t i = 0; i < nValues - 1; ++i) {
		const vec3 p1((xCol->getAsDouble(i) + offsetX)*scaleX, (yCol->getAsDouble(i) + offsetY)*scaleY, 0);
		const vec3 p2((xCol->getAsDouble(i+1) + offsetX)*scaleX, (yCol->getAsDouble(i+1) + offsetY)*scaleY, 0);
		if (p1.x < 0 || p1.x > 1) continue;
		if (p2.x < 0 || p2.x > 1) continue;
		indices->add(lineMesh_->addVertex(p1, p1, p1, color));
		indices->add(lineMesh_->addVertex(p2, p2, p2, color));
	}

	// Update the dimensions of the mesh.
	updateDimensions();

}

} // namespace<commit_msg>added point interpolation inside bounds<commit_after>#include <modules/graph2d/processors/plot2d.h>

#include <modules/plotting/utils/axisutils.h>
#include <modules/opengl/texture/textureutils.h>
#include <inviwo/core/util/raiiutils.h>
#include <inviwo/core/algorithm/boundingbox.h>
#include <inviwo/core/rendering/meshdrawerfactory.h>

#include <modules/opengl/texture/textureutils.h>
#include <modules/opengl/shader/shaderutils.h>
#include <modules/opengl/openglutils.h>

#include <modules/opengl/openglutils.h>
#include <inviwo/core/datastructures/coordinatetransformer.h>
#include <modules/opengl/texture/textureutils.h>

namespace inviwo {

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo Plot2dProcessor::processorInfo_{
    "org.inviwo.Plot2D",    // Class identifier
    "Plot2D",                 // Display name
    "Plotting",               // Category
    CodeState::Stable,        // Code state
    "Plotting",           // Tags
};

const ProcessorInfo Plot2dProcessor::getProcessorInfo() const { return processorInfo_; }

Plot2dProcessor::Plot2dProcessor()
    : Processor()
    , inport_("inport")
    , imageInport_("imageInport")
    , outport_("outport")
    , xAxis_("xAxis", "X Axis")
    , yAxis_("yAxis", "Y Axis")
	, position_("position", "Position", vec3(0), vec3(-25), vec3(25), vec3(0.01))
	, size_("size", "Size", vec2(3), vec2(0.01), vec2(25), vec2(0.01))
    , camera_("camera", "Camera")
	, camera2d_{ InviwoApplication::getPtr()->getCameraFactory()->create("OrthographicCamera") }
    , trackball_(&camera_)
	, axisRenderers_({ {xAxis_, yAxis_} })
	, xAxisSelection_("xAxisSelection", "X Axis")
	, yAxisSelection_("yAxisSelection", "Y Axis")
	, toggle3d_("toggle3d", "Render in 3D space")
	, lineMesh_( std::make_shared<BasicMesh>() )
	, meshDrawer_( std::unique_ptr<MeshDrawer>() )
	, shader_("linerenderer.vert", "linerenderer.geom", "linerenderer.frag", false)
    {

	shader_.onReload([this]() { invalidate(InvalidationLevel::InvalidResources); });

	MeshDrawerFactory* factory = InviwoApplication::getPtr()->getMeshDrawerFactory();
	meshDrawer_ = std::move(factory->create(lineMesh_.get()));

	// Setup ports
    imageInport_.setOptional(true);
    addPort(inport_);
    addPort(imageInport_);
    addPort(outport_);

	// Add properties
	addProperty(toggle3d_);
	addProperty(position_);
	addProperty(size_);
	addProperties(xAxisSelection_, yAxisSelection_);
	addProperties(xAxis_, yAxis_);
	addProperty(camera_);
	addProperty(trackball_);

	// Set up property default values
	toggle3d_.set(false);
	camera_.setVisible(false);
	camera_.setCollapsed(true);
	trackball_.setVisible(false);
	trackball_.setCollapsed(true);

	// Initialize the 2d camera.
	camera2d_->setLookFrom(vec3(0, 0, 100));
	camera2d_->setLookTo(vec3(0, 0, 0));
	camera2d_->setLookUp(vec3(0, 1, 0));
	camera2d_->setFarPlaneDist(200);
	camera2d_->setNearPlaneDist(1);

	// Axis default values.
	xAxis_.setCaption("x");
	yAxis_.setCaption("y");
	yAxis_.orientation_.setSelectedDisplayName("Vertical");

	for (auto axis : { &xAxis_, &yAxis_ }) {
		axis->captionSettings_.offset_.set(0.7f);
		axis->captionSettings_.position_.set(0.5f);
		axis->labelSettings_.offset_.set(0.7f);

		axis->majorTicks_.tickLength_.set(0.3f);
		axis->majorTicks_.tickWidth_.set(1.5f);
		axis->majorTicks_.style_.set(plot::TickStyle::Outside);
		axis->majorTicks_.setCurrentStateAsDefault();

		axis->minorTicks_.tickLength_.set(0.15f);
		axis->minorTicks_.tickWidth_.set(1.3f);
		axis->minorTicks_.style_.set(plot::TickStyle::Outside);
		axis->minorTicks_.setCurrentStateAsDefault();

		axis->setCollapsed(true);
		//axis->orientation_.setVisible(false);
		//axis->placement_.setVisible(false);
		//axis->flipped_.setVisible(false);
	}

	// Event callbacks
	toggle3d_.onChange([this] {
		position_.setVisible(toggle3d_.get());
		size_.setVisible(toggle3d_.get());
		camera_.setVisible(toggle3d_.get());
		trackball_.setVisible(toggle3d_.get());
		updateDimensions();
	});
	size_.onChange([this] { updateDimensions(); });
	position_.onChange([this] { updateDimensions(); });

	inport_.onChange([this] {
		reloadDatasets();
		updatePlotData(); });
	xAxisSelection_.onChange([this] { updatePlotData(); });
	yAxisSelection_.onChange([this] { updatePlotData(); });
	xAxis_.range_.onChange([this] { updatePlotData(); });
	yAxis_.range_.onChange([this] { updatePlotData(); });
	xAxis_.useDataRange_.onChange([this] { updatePlotData(); });
	yAxis_.useDataRange_.onChange([this] { updatePlotData(); });
}

void Plot2dProcessor::initializeResources() {
	LogInfo("Initializing resources plot2d");

	shader_[ShaderType::Geometry]->addShaderDefine("ENABLE_ADJACENCY", "0");
	//shader_[ShaderType::Fragment]->addShaderDefine("ENABLE_ROUND_DEPTH_PROFILE");

	// See createLineStripMesh()
	shader_[ShaderType::Vertex]->addInDeclaration("in_" + toString(BufferType::PositionAttrib),
		static_cast<int>(BufferType::PositionAttrib),
		"vec3");
	shader_[ShaderType::Vertex]->addInDeclaration("in_" + toString(BufferType::ColorAttrib),
		static_cast<int>(BufferType::ColorAttrib),
		"vec4");
	shader_[ShaderType::Vertex]->addInDeclaration("in_" + toString(BufferType::TexcoordAttrib),
		static_cast<int>(BufferType::TexcoordAttrib),
		"vec2");
	shader_.build();
	shader_.activate();
	shader_.setUniform("antialiasing", 0.0f);
	shader_.setUniform("miterLimit", 1.0f);
	shader_.deactivate();
}

void Plot2dProcessor::process() {
	LogInfo("Process start");
	if (imageInport_.isReady()) {
		utilgl::activateTargetAndCopySource(outport_, imageInport_, ImageType::ColorDepth);
	}
	else {
		utilgl::activateAndClearTarget(outport_, ImageType::ColorDepth);
	}
	const size2_t dims = outport_.getDimensions();
	if (!toggle3d_.get() && oldDims_ != dims) updateDimensions();

	// Save a pointer to the camera that will be used
	Camera* activeCamera;
	if (toggle3d_.get())
		activeCamera = &camera_.get();
	else
		activeCamera = camera2d_.get();

	vec3 xVector(1, 0, 0);
	vec3 yVector(0, 1, 0);

	if (toggle3d_.get()) {
		// Set the normal of the graph plane to point towards camera.
		yVector = glm::normalize( camera_.getLookUp() );
		xVector = glm::normalize( glm::cross(yVector, camera_.getLookFrom() - camera_.getLookTo()) );
		lineMesh_->setBasis(Matrix<3U, float>(
			xVector * graphDims_[0],
			yVector * graphDims_[1],
			vec3(0, 0, 1)));
	}

	// Render lines.
	shader_.activate();
	utilgl::setShaderUniforms(shader_, *meshDrawer_->getMesh(), "geometry");
	utilgl::setShaderUniforms(shader_, *activeCamera, "camera");
	shader_.setUniform("screenDim", vec2(outport_.getDimensions()));
	shader_.setUniform("lineWidth", 2);
	meshDrawer_->draw();
	shader_.deactivate();

	// Render x and y axis
	axisRenderers_[0].render(activeCamera, dims, origin_, origin_ + xVector * graphDims_[0], yVector);
	axisRenderers_[1].render(activeCamera, dims, origin_, origin_ + yVector * graphDims_[1], xVector);

	utilgl::deactivateCurrentTarget();
}

void Plot2dProcessor::reloadDatasets() {
	if (!inport_.hasData()) {
		xAxisSelection_.clearOptions();
		yAxisSelection_.clearOptions();
		return;
	}
	const std::shared_ptr<const DataFrame> dataframe = inport_.getData();
	// Update column selection properties
	std::vector<OptionPropertyStringOption> options;
	for (const auto& column : *dataframe) {
		options.emplace_back(column->getHeader(), column->getHeader(), column->getHeader());
	}

	xAxisSelection_.replaceOptions(options);
	yAxisSelection_.replaceOptions(options);
	xAxisSelection_.setCurrentStateAsDefault();
	yAxisSelection_.setCurrentStateAsDefault();
}

void Plot2dProcessor::updateDimensions() {
	if (toggle3d_.get()) {
		origin_ = position_.get();
		graphDims_ = size_.get();
	}
	else {
		const size2_t dims = outport_.getDimensions();
		const float aspect = (float)dims[0] / (float)dims[1];
		const float scale = (double)dims[0] / 512;
		const float width = 50 * scale;
		const float height = width / aspect;
		const float padding = 50 * width / (double)dims[0];

		oldDims_ = dims;
		origin_ = vec3(-width / 2 + padding, -height / 2 + padding, 0);
		graphDims_ = vec2(width - 2 * padding, height - 2 * padding);
		// Update 2d camera to fit new dimensions.
		static_cast<OrthographicCamera*>(camera2d_.get())->setFrustum({ -width / 2.0f, +width / 2.0f, -width / 2.0f / aspect, +width / 2.0f / aspect });
	}
	// Scale and offset line mesh to align with axises.
	lineMesh_->setBasis(Matrix<3U, float>(graphDims_[0], 0, 0, 0, graphDims_[1], 0, 0, 0, 1));
	lineMesh_->setOffset(origin_);
}

void Plot2dProcessor::updatePlotData() {
	// Reset line mesh
	lineMesh_ = std::make_shared<BasicMesh>();
	meshDrawer_ = std::move(InviwoApplication::getPtr()->getMeshDrawerFactory()->create(lineMesh_.get()));

	if (!inport_.hasData()) return;

	const std::shared_ptr<const DataFrame> dataframe = inport_.getData();
	const std::shared_ptr<const Column> xCol = dataframe->getColumn(xAxisSelection_.getSelectedIndex());
	const std::shared_ptr<const Column> yCol = dataframe->getColumn(yAxisSelection_.getSelectedIndex());
	size_t nValues = xCol->getSize();

	if (xCol->getSize() < 2 || yCol->getSize() < 2 || yCol->getSize() != xCol->getSize()) return;

	// Set ranges for x and y axis
	if (xAxis_.getUseDataRange()) {
		dvec2 xrange(xCol->getAsDouble(0), xCol->getAsDouble(0));
		for (size_t i = 1; i < nValues; ++i) {
			double v = xCol->getAsDouble(i);
			if (v < xrange[0]) xrange[0] = v;
			if (v > xrange[1]) xrange[1] = v;
		}
		xAxis_.range_.set(xrange);
	}

	if (yAxis_.getUseDataRange()) {
		dvec2 yrange(yCol->getAsDouble(0), yCol->getAsDouble(0));
		for (size_t i = 1; i < nValues; ++i) {
			if (xCol->getAsDouble(i) < xAxis_.getRange()[0] || xCol->getAsDouble(i) > xAxis_.getRange()[1]) {
				continue;
			}
			double v = yCol->getAsDouble(i);
			if (v < yrange[0]) yrange[0] = v;
			if (v > yrange[1]) yrange[1] = v;
		}
		if (yrange[0] == yrange[1]) yrange[1] += 1;
		yAxis_.range_.set(yrange);
	}

	const double offsetX = -xAxis_.getRange()[0];
	const double offsetY = -yAxis_.getRange()[0];
	const double scaleX = 1.0f / (xAxis_.getRange()[1] - xAxis_.getRange()[0]);
	const double scaleY = 1.0f / (yAxis_.getRange()[1] - yAxis_.getRange()[0]);

	std::shared_ptr<IndexBufferRAM> indices = lineMesh_->addIndexBuffer(DrawType::Lines, ConnectivityType::None);
	vec4 color(0.5, 0.3, 0.8, 1);

	auto inBounds = [](const vec3 p) {
		// Is point inside the bounds of the graph
		return (p.x >= 0 && p.x <= 1 && p.y >= 0 && p.y <= 1);
	};

	auto boundIntersection = [this](const vec3& p1, const vec3& p2) {
		// Return the point on the edge of the bounding rectangle of the graph
		// given the line segment p1->p2. p1 is inside the bounds.
		const vec3 v = p2 - p1;
		float t = 1;
		for (const float n : { -p1.x / v.x, (1 - p1.x) / v.x, -p1.y / v.y, (1 - p1.y) / v.y })
			if (n > 0 && n < t) t = n;
		if (t == 1) t = 0;
		LogInfo("Interpolation: "
			<< p1 << "\n"
			<< p2 << "\n"
			<< v << "\n"
			<< t);
		return p1 + t * v;
	};

	// Add point from dataframe to line mesh
	for (size_t i = 0; i < nValues - 1; ++i) {
		// Get points from columns and scale them to be in the value range [0,1]
		vec3 p1((xCol->getAsDouble(i) + offsetX)*scaleX, (yCol->getAsDouble(i) + offsetY)*scaleY, 0);
		vec3 p2((xCol->getAsDouble(i + 1) + offsetX)*scaleX, (yCol->getAsDouble(i + 1) + offsetY)*scaleY, 0);

		if ( !inBounds(p1) && !inBounds(p2) ) continue;
		// If one of the points inside bounds, interpolate the edge intersection point
		else if ( !inBounds(p2) ) p2 = boundIntersection(p1, p2);
		else if ( !inBounds(p1) ) p1 = boundIntersection(p2, p1);

		indices->add(lineMesh_->addVertex(p1, p1, p1, color));
		indices->add(lineMesh_->addVertex(p2, p2, p2, color));
	}

	// Update the dimensions of the mesh.
	updateDimensions();

}

} // namespace<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

//---------------------------------------------------------------------
//
//  This test program is used, in conjunction with a set of test data files,
//  to verify support for different character encodings in XML.
//
//---------------------------------------------------------------------

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/framework/XMLBuffer.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLException.hpp>

#include <xercesc/sax/SAXException.hpp>
#include <xercesc/sax/ErrorHandler.hpp>
#include <xercesc/sax/SAXParseException.hpp>

#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/dom/DOM.hpp>
#include <stdio.h>

static int gTestsFailed = 0;
static int gTestsRun    = 0;
static XercesDOMParser* parser = 0;

//-----------------------------------------------------------------------
//
//  ErrorHandler.   The DOM Parser will report any parsing errors by means
//                  of call-backs to the methods of this class.
//                  This is just necessary boilerplate, as far as this
//                  program is concerned.
//
//-----------------------------------------------------------------------

class  ParseErrorHandler: public ErrorHandler
{
public:
    void warning(const SAXParseException& e);
    void error(const SAXParseException& e);
    void fatalError(const SAXParseException& e);
    void resetErrors() {};

};

void ParseErrorHandler::error(const SAXParseException& e)
{
    fprintf(stderr, "\nError at file \"%s\", line %d, char %d:  %s\n",
        XMLString::transcode(e.getSystemId()), e.getLineNumber(),
        e.getColumnNumber(), XMLString::transcode(e.getMessage()));
    throw e;

};

void ParseErrorHandler::fatalError(const SAXParseException& e)
{
    fprintf(stderr, "\nFatal Error at file \"%s\", line %d, char %d:  %s\n",
        XMLString::transcode(e.getSystemId()), e.getLineNumber(),
        e.getColumnNumber(), XMLString::transcode(e.getMessage()));
    throw e;
};

void ParseErrorHandler::warning(const SAXParseException& e)
{
    fprintf(stderr, "\nWarning at file \"%s\", line %d, char %d:  %s\n",
        XMLString::transcode(e.getSystemId()), e.getLineNumber(),
        e.getColumnNumber(), XMLString::transcode(e.getMessage()));
    throw e;

};

//------------------------------------------------------------------------
//
//   parseFile  - a simpler to use function for just parsing an XML file
//                and getting the DOM Document back.
//
//------------------------------------------------------------------------
static DOMDocument* parseFile(char *fileName)
{
    ParseErrorHandler eh;
    parser = new XercesDOMParser;
    parser->setDoValidation(false);
    parser->setErrorHandler(&eh);
    try
    {
        parser->parse(fileName);
    }

    catch (const XMLException& e )
    {
		fprintf(stderr, "Exception Occurred \"%s\".  \n",
			XMLString::transcode(e.getMessage()));
		fprintf(stderr, "File being parsed is \"%s\".\n", fileName);
        return 0;  // A null document.
    }

	catch (...)
	{
		fprintf(stderr, "Unexpected Exception thrown during parse of file \"%s\".\n",
		                 fileName);
		return 0;
	}
    return parser->getDocument();
}

//------------------------------------------------------------------------
//
//  writeUData - Write out a udata xml element for a XMLCh* contents.
//
//------------------------------------------------------------------------
static void writeUData(const XMLCh* s)
{
    unsigned int i;
    printf("<udata>\n");
    size_t len = XMLString::stringLen(s);
    for (i=0; i<len; i++)
    {
        if (i % 16 == 0)
            printf("\n");
        XMLCh c = s[i];
        printf("%4x ", c);
    }
    printf("\n</udata>\n");
};

//------------------------------------------------------------------------
//
//  eatWhiteSpace -  XMLCh*s are kind of short on utility functions :-(
//
//------------------------------------------------------------------------
static void eatWhiteSpace(XMLCh* s, unsigned int &i)
{
    while (i < XMLString::stringLen(s))
    {
    XMLCh c = s[i];
    if (!(c == 0x20 ||           // These are the official XML space characters,
        c == 0x09 ||             //   expressed as Unicode constants.
        c == 0x0A))
        break;
    i++;
    }
}

//------------------------------------------------------------------------
//
//   convertHexValue     if the XMLCh* contains a hex number at position i,
//                       convert it and return it, and update i to index the
//                       first char not in the string.
//                       return 0 if string[i] didn't have a hex digit.
//                       0 return is ambiguous, but it doesn't matter for XML,
//                       where 0 is not a valid character.
//
//------------------------------------------------------------------------
static int convertHexValue(XMLCh* s, unsigned int &i)
{
    int value = 0;

                                   // For reference, the digits  0-9 are Unicode 0x30-39
                                   //                the letters A-F are Unicode 0x41-0x46
                                   //                the letters a-f are Unicode 0x61-66
                                   // We can't use character literals - we might be
                                   //  building on an EBCDIC machine.
    while (i < XMLString::stringLen(s))
    {
        XMLCh c = s[i];
        if (c >= 0x61 && c <= 0x66)     // Uppercase a-f to A-F.
            c -= 0x20;

        if (c < 0x30 || c >0x46)        // Stop if not a hex digit
            break;
        if (c > 0x39 && c <0x41)
            break;

        value = value << 4;             // Append this digit to accumulating value
        if (c <= 0x39)
            value += c-0x30;
        else
            value += 0xA + c - 0x41;

        i++;
    }
    return value;
}

//------------------------------------------------------------------------
//
//  processTestFile   Given the file name of an encoding test xml file,
//                    run it.
//
//------------------------------------------------------------------------
static bool  processTestFile(const XMLCh* fileName)
{
    //
    //  Send the input file through the parse, create a DOM document for it.
    //
    char *cFileName = XMLString::transcode(fileName);
    DOMDocument* testDoc = parseFile(cFileName);
    if (testDoc == 0)
        return false;    // parse errors in the source xml.

    //
    //  Pull the "data" element out of the document.
    //
    XMLCh tempStr[4000];
    XMLString::transcode("data", tempStr, 3999);
    DOMNodeList* nl = testDoc->getElementsByTagName(tempStr);
    if (nl->getLength() != 1) {
        fprintf(stderr, "Test file \"%s\" must have exactly one \"data\" element.\n", cFileName);
        return false;
    };
    DOMNode* tmpNode = nl->item(0);
    DOMElement* data = (DOMElement*) tmpNode;

    //
    //  Build up a string containing the character data contents of the data element.
    //
    DOMNode* child;
    XMLBuffer elData;
    for (child=data->getFirstChild(); child != 0; child= child->getNextSibling())
    {
		if (child->getNodeType() == DOMNode::COMMENT_NODE)
			continue;
        if (! (child->getNodeType() == DOMNode::TEXT_NODE ||
               child->getNodeType() == DOMNode::CDATA_SECTION_NODE ||
               child->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE))
        {
               fprintf(stderr, "Test file \"%s\": data element contains unexpected children.",
                    cFileName);
               return false;
        }
        elData.append(((DOMCharacterData *)child)->getData());
    };

    //
    //  Pull the "udata" element out of the document
    //
    XMLString::transcode("udata", tempStr, 3999);
    nl = testDoc->getElementsByTagName(tempStr);
    if (nl->getLength() != 1) {
        fprintf(stderr, "Test file \"%s\" must have exactly one \"udata\" element.\n", cFileName);
        return false;
    };
    DOMNode* tmpNode1 = nl->item(0);
    DOMElement* udata = (DOMElement*) tmpNode1;

    //
    //  Build up a string containing the character data contents of the udata element.
    //  This will consist of a whole bunch hex numbers, still in string from
    //

    XMLBuffer rawUData;
    for (child=udata->getFirstChild(); child != 0; child= child->getNextSibling())
    {
        if (child->getNodeType() == DOMNode::COMMENT_NODE)
            continue;
        if (! (child->getNodeType() == DOMNode::TEXT_NODE ||
            child->getNodeType() == DOMNode::CDATA_SECTION_NODE ||
            child->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE))
        {
            fprintf(stderr, "Test file \"%s\": udata element contains unexpected children.",
                cFileName);
            return false;
        }
        rawUData.append(((DOMCharacterData *)child)->getData());
    };

    //
    // Convert the raw (hex numbers)  form of the udata to the corresponding string.
    //
    XMLBuffer uData;
    unsigned int rawIndex = 0;

    while (rawIndex < rawUData.getLen())
    {
        eatWhiteSpace(rawUData.getRawBuffer(), rawIndex);
        XMLCh c = convertHexValue(rawUData.getRawBuffer(), rawIndex);
        if (c > 0)
            uData.append(c);
        else
            if (rawIndex < rawUData.getLen())
            {
                fprintf(stderr, "Test file \"%s\": Bad hex number in udata element.  "
                    "Data character number %d\n", cFileName, uData.getLen());
                return false;
            }
    }

    //
    // Compare the two strings.
    //
    unsigned int i;
    for (i=0; i< elData.getLen(); i++)
    {
        XMLCh* elDataRaw = elData.getRawBuffer();
        XMLCh* uDataRaw = uData.getRawBuffer();
        if (i >= uData.getLen())
        {
            fprintf(stderr, "Test file \"%s\": udata element shorter than data at char number %d\n",
                cFileName, i);
            writeUData(elDataRaw);
            return false;
        }
        if (uDataRaw[i] != elDataRaw[i])
        {
            fprintf(stderr, "Test file \"%s\": comparison failure at character number %d\n",
                cFileName, i);
            writeUData(elDataRaw);
            return false;
        };
    }

    if (elData.getLen() != uData.getLen())
    {
        fprintf(stderr, "Test file \"%s\": udata element longer than data at char number %d\n",
            cFileName, i);
        writeUData(elData.getRawBuffer());
        return false;
    }

    delete [] cFileName;

    return true;
}

int main(int argc, char ** argv) {

   //
    // Initialize the Xerces-c environment
    //
	try
    {
        XMLPlatformUtils::Initialize();
    }

    catch (const XMLException& toCatch)
    {
        fprintf(stderr, "Error during initialization of xerces-c: %s\n",
            XMLString::transcode(toCatch.getMessage()));
         return 1;
    }

    //
    // Parse the command line, which should specify exactly one file, which is an
    //   xml file containing the list of test files to be processed.
    //
    if (argc != 2) {
        printf("usage: %s file_name \n"
               "   where file name is the xml file specifying the list of test files.", argv[0]);
        return 1;
    }
    DOMDocument* fileListDoc = parseFile(argv[1]);
    if (fileListDoc == 0) return 1;

    //
    // Iterate over the list of files, running each as a test.
    //
    XMLCh tempStr[4000];
    XMLString::transcode("testFile", tempStr, 3999);
    DOMNodeList* list = fileListDoc->getElementsByTagName(tempStr);
    int i;
    int numFiles = list->getLength();
    for (i=0; i<numFiles; i++)
    {
        ++gTestsRun;
        DOMNode* tmpNode3 = list->item(i);
        XMLString::transcode("name", tempStr, 3999);
        const XMLCh* fileName = ((DOMElement*) tmpNode3)->getAttribute(tempStr);
        if (processTestFile(fileName) == false)
            ++gTestsFailed;
    };

    //
    // We are done.  Print out a summary of the results
    //
    printf("Encoding Tests Results Summary: \n"
           "   %d encoding tests run.\n"
           "   %d tests passed,\n"
           "   %d tests failed\n", gTestsRun, gTestsRun-gTestsFailed, gTestsFailed);

   return 0;
};
<commit_msg>Clear memory leak in EncodingTest.cpp<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

//---------------------------------------------------------------------
//
//  This test program is used, in conjunction with a set of test data files,
//  to verify support for different character encodings in XML.
//
//---------------------------------------------------------------------

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/framework/XMLBuffer.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLException.hpp>

#include <xercesc/sax/SAXException.hpp>
#include <xercesc/sax/ErrorHandler.hpp>
#include <xercesc/sax/SAXParseException.hpp>

#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/dom/DOM.hpp>
#include <stdio.h>

static int gTestsFailed = 0;
static int gTestsRun    = 0;
static XercesDOMParser* parser = 0;

//-----------------------------------------------------------------------
//
//  ErrorHandler.   The DOM Parser will report any parsing errors by means
//                  of call-backs to the methods of this class.
//                  This is just necessary boilerplate, as far as this
//                  program is concerned.
//
//-----------------------------------------------------------------------

class  ParseErrorHandler: public ErrorHandler
{
public:
    void warning(const SAXParseException& e);
    void error(const SAXParseException& e);
    void fatalError(const SAXParseException& e);
    void resetErrors() {};

};

void ParseErrorHandler::error(const SAXParseException& e)
{
    char* systemId = XMLString::transcode(e.getSystemId());
    char* message = XMLString::transcode(e.getMessage());

    fprintf(stderr, "\nError at file \"%s\", line %d, char %d:  %s\n",
        systemId, e.getLineNumber(),
        e.getColumnNumber(), message);

    delete [] systemId;
    delete [] message;
    throw e;

};

void ParseErrorHandler::fatalError(const SAXParseException& e)
{
    char* systemId = XMLString::transcode(e.getSystemId());
    char* message = XMLString::transcode(e.getMessage());

    fprintf(stderr, "\nFatal Error at file \"%s\", line %d, char %d:  %s\n",
        systemId, e.getLineNumber(),
        e.getColumnNumber(), message);

    delete [] systemId;
    delete [] message;
    throw e;
};

void ParseErrorHandler::warning(const SAXParseException& e)
{
    char* systemId = XMLString::transcode(e.getSystemId());
    char* message = XMLString::transcode(e.getMessage());

    fprintf(stderr, "\nWarning at file \"%s\", line %d, char %d:  %s\n",
        systemId, e.getLineNumber(),
        e.getColumnNumber(), message);

    delete [] systemId;
    delete [] message;
    throw e;

};

//------------------------------------------------------------------------
//
//   parseFile  - a simpler to use function for just parsing an XML file
//                and getting the DOM Document back.
//
//------------------------------------------------------------------------
static DOMDocument* parseFile(char *fileName)
{
    ParseErrorHandler eh;
    if (!parser)
        parser = new XercesDOMParser;
    parser->setDoValidation(false);
    parser->setErrorHandler(&eh);
    try
    {
        parser->parse(fileName);
    }

    catch (const XMLException& e )
    {
		fprintf(stderr, "Exception Occurred \"%s\".  \n",
			XMLString::transcode(e.getMessage()));
		fprintf(stderr, "File being parsed is \"%s\".\n", fileName);
        return 0;  // A null document.
    }

	catch (...)
	{
		fprintf(stderr, "Unexpected Exception thrown during parse of file \"%s\".\n",
		                 fileName);
		return 0;
	}
    return parser->getDocument();
}

//------------------------------------------------------------------------
//
//  writeUData - Write out a udata xml element for a XMLCh* contents.
//
//------------------------------------------------------------------------
static void writeUData(const XMLCh* s)
{
    unsigned int i;
    printf("<udata>\n");
    size_t len = XMLString::stringLen(s);
    for (i=0; i<len; i++)
    {
        if (i % 16 == 0)
            printf("\n");
        XMLCh c = s[i];
        printf("%4x ", c);
    }
    printf("\n</udata>\n");
};

//------------------------------------------------------------------------
//
//  eatWhiteSpace -  XMLCh*s are kind of short on utility functions :-(
//
//------------------------------------------------------------------------
static void eatWhiteSpace(XMLCh* s, unsigned int &i)
{
    while (i < XMLString::stringLen(s))
    {
    XMLCh c = s[i];
    if (!(c == 0x20 ||           // These are the official XML space characters,
        c == 0x09 ||             //   expressed as Unicode constants.
        c == 0x0A))
        break;
    i++;
    }
}

//------------------------------------------------------------------------
//
//   convertHexValue     if the XMLCh* contains a hex number at position i,
//                       convert it and return it, and update i to index the
//                       first char not in the string.
//                       return 0 if string[i] didn't have a hex digit.
//                       0 return is ambiguous, but it doesn't matter for XML,
//                       where 0 is not a valid character.
//
//------------------------------------------------------------------------
static int convertHexValue(XMLCh* s, unsigned int &i)
{
    int value = 0;

                                   // For reference, the digits  0-9 are Unicode 0x30-39
                                   //                the letters A-F are Unicode 0x41-0x46
                                   //                the letters a-f are Unicode 0x61-66
                                   // We can't use character literals - we might be
                                   //  building on an EBCDIC machine.
    while (i < XMLString::stringLen(s))
    {
        XMLCh c = s[i];
        if (c >= 0x61 && c <= 0x66)     // Uppercase a-f to A-F.
            c -= 0x20;

        if (c < 0x30 || c >0x46)        // Stop if not a hex digit
            break;
        if (c > 0x39 && c <0x41)
            break;

        value = value << 4;             // Append this digit to accumulating value
        if (c <= 0x39)
            value += c-0x30;
        else
            value += 0xA + c - 0x41;

        i++;
    }
    return value;
}

//------------------------------------------------------------------------
//
//  processTestFile   Given the file name of an encoding test xml file,
//                    run it.
//
//------------------------------------------------------------------------
static bool  processTestFile(const XMLCh* fileName)
{
    //
    //  Send the input file through the parse, create a DOM document for it.
    //
    char cFileName[4000];
    XMLString::transcode(fileName, cFileName, 3999);
    DOMDocument* testDoc = parseFile(cFileName);
    if (testDoc == 0)
        return false;    // parse errors in the source xml.

    //
    //  Pull the "data" element out of the document.
    //
    XMLCh tempStr[4000];
    XMLString::transcode("data", tempStr, 3999);
    DOMNodeList* nl = testDoc->getElementsByTagName(tempStr);
    if (nl->getLength() != 1) {
        fprintf(stderr, "Test file \"%s\" must have exactly one \"data\" element.\n", cFileName);
        return false;
    };
    DOMNode* tmpNode = nl->item(0);
    DOMElement* data = (DOMElement*) tmpNode;

    //
    //  Build up a string containing the character data contents of the data element.
    //
    DOMNode* child;
    XMLBuffer elData;
    for (child=data->getFirstChild(); child != 0; child= child->getNextSibling())
    {
		if (child->getNodeType() == DOMNode::COMMENT_NODE)
			continue;
        if (! (child->getNodeType() == DOMNode::TEXT_NODE ||
               child->getNodeType() == DOMNode::CDATA_SECTION_NODE ||
               child->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE))
        {
               fprintf(stderr, "Test file \"%s\": data element contains unexpected children.",
                    cFileName);
               return false;
        }
        elData.append(((DOMCharacterData *)child)->getData());
    };

    //
    //  Pull the "udata" element out of the document
    //
    XMLString::transcode("udata", tempStr, 3999);
    nl = testDoc->getElementsByTagName(tempStr);
    if (nl->getLength() != 1) {
        fprintf(stderr, "Test file \"%s\" must have exactly one \"udata\" element.\n", cFileName);
        return false;
    };
    DOMNode* tmpNode1 = nl->item(0);
    DOMElement* udata = (DOMElement*) tmpNode1;

    //
    //  Build up a string containing the character data contents of the udata element.
    //  This will consist of a whole bunch hex numbers, still in string from
    //

    XMLBuffer rawUData;
    for (child=udata->getFirstChild(); child != 0; child= child->getNextSibling())
    {
        if (child->getNodeType() == DOMNode::COMMENT_NODE)
            continue;
        if (! (child->getNodeType() == DOMNode::TEXT_NODE ||
            child->getNodeType() == DOMNode::CDATA_SECTION_NODE ||
            child->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE))
        {
            fprintf(stderr, "Test file \"%s\": udata element contains unexpected children.",
                cFileName);
            return false;
        }
        rawUData.append(((DOMCharacterData *)child)->getData());
    };

    //
    // Convert the raw (hex numbers)  form of the udata to the corresponding string.
    //
    XMLBuffer uData;
    unsigned int rawIndex = 0;

    while (rawIndex < rawUData.getLen())
    {
        eatWhiteSpace(rawUData.getRawBuffer(), rawIndex);
        XMLCh c = convertHexValue(rawUData.getRawBuffer(), rawIndex);
        if (c > 0)
            uData.append(c);
        else
            if (rawIndex < rawUData.getLen())
            {
                fprintf(stderr, "Test file \"%s\": Bad hex number in udata element.  "
                    "Data character number %d\n", cFileName, uData.getLen());
                return false;
            }
    }

    //
    // Compare the two strings.
    //
    unsigned int i;
    for (i=0; i< elData.getLen(); i++)
    {
        XMLCh* elDataRaw = elData.getRawBuffer();
        XMLCh* uDataRaw = uData.getRawBuffer();
        if (i >= uData.getLen())
        {
            fprintf(stderr, "Test file \"%s\": udata element shorter than data at char number %d\n",
                cFileName, i);
            writeUData(elDataRaw);
            return false;
        }
        if (uDataRaw[i] != elDataRaw[i])
        {
            fprintf(stderr, "Test file \"%s\": comparison failure at character number %d\n",
                cFileName, i);
            writeUData(elDataRaw);
            return false;
        };
    }

    if (elData.getLen() != uData.getLen())
    {
        fprintf(stderr, "Test file \"%s\": udata element longer than data at char number %d\n",
            cFileName, i);
        writeUData(elData.getRawBuffer());
        return false;
    }

    return true;
}

int main(int argc, char ** argv) {

   //
    // Initialize the Xerces-c environment
    //
	try
    {
        XMLPlatformUtils::Initialize();
    }

    catch (const XMLException& toCatch)
    {
        fprintf(stderr, "Error during initialization of xerces-c: %s\n",
            XMLString::transcode(toCatch.getMessage()));
         return 1;
    }

    //
    // Parse the command line, which should specify exactly one file, which is an
    //   xml file containing the list of test files to be processed.
    //
    if (argc != 2) {
        printf("usage: %s file_name \n"
               "   where file name is the xml file specifying the list of test files.", argv[0]);
        return 1;
    }
    DOMDocument* fileListDoc = parseFile(argv[1]);
    if (fileListDoc == 0) return 1;

    //
    // Iterate over the list of files, running each as a test.
    //
    XMLCh tempStr[4000];
    XMLString::transcode("testFile", tempStr, 3999);
    DOMNodeList* list = fileListDoc->getElementsByTagName(tempStr);
    int i;
    int numFiles = list->getLength();
    for (i=0; i<numFiles; i++)
    {
        ++gTestsRun;
        DOMNode* tmpNode3 = list->item(i);
        XMLString::transcode("name", tempStr, 3999);
        const XMLCh* fileName = ((DOMElement*) tmpNode3)->getAttribute(tempStr);
        if (processTestFile(fileName) == false)
            ++gTestsFailed;
    };

    //
    // We are done.  Print out a summary of the results
    //
    printf("Encoding Tests Results Summary: \n"
           "   %d encoding tests run.\n"
           "   %d tests passed,\n"
           "   %d tests failed\n", gTestsRun, gTestsRun-gTestsFailed, gTestsFailed);

    delete parser;
    parser = 0;
   return 0;
};
<|endoftext|>


<commit_before>/*
 * Copyright 2009-2018 The VOTCA Development Team (http://www.votca.org)
 *
 * 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.
 *
 */

#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE bondedstatistics_test
#include <boost/test/unit_test.hpp>

#include <iostream>
#include <map>
#include <string>
#include "../csg_boltzmann/bondedstatistics.h"

using namespace std;
using namespace votca::csg;
using namespace votca::tools;

// used for rounding doubles so we can compare them
double round_(double v, int p) {
  v *= pow(10, p);
  v = round(v);
  v /= pow(10, p);
  return v;
}

BOOST_AUTO_TEST_SUITE(bondedstatistics_test)

BOOST_AUTO_TEST_CASE(test_bondedstatistics_constructor) {
  BondedStatistics bonded_statistics;
}

BOOST_AUTO_TEST_CASE(test_bondedstatistics_begin) {
  Topology top;
  // Create two bonded interactions
  string interaction_group = "covalent_bond";
  string interaction_group_compare = ":covalent_bond";
  auto bond1 = new IBond(0,1);
  bond1->setGroup(interaction_group);
  auto bond2 = new IBond(1,2);
  bond2->setGroup(interaction_group);

  top.AddBondedInteraction(bond1);
  top.AddBondedInteraction(bond2);

  BondedStatistics bonded_statistics;
  bonded_statistics.BeginCG(&top,nullptr);

  DataCollection<double>& data_collection = bonded_statistics.BondedValues();
  vector<DataCollection<double>::array *>& vector_of_arrays = data_collection.Data();
  BOOST_CHECK_EQUAL(vector_of_arrays.size(),2);
  BOOST_CHECK_EQUAL(vector_of_arrays.at(0)->getName(),interaction_group_compare);
  BOOST_CHECK_EQUAL(vector_of_arrays.at(1)->getName(),interaction_group_compare);
  // The arrays do not store any numbers at this point
  BOOST_CHECK_EQUAL(vector_of_arrays.at(0)->size(),0);
  BOOST_CHECK_EQUAL(vector_of_arrays.at(1)->size(),0);
  top.Cleanup();
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Added unit test for EvalConfiguration method<commit_after>/*
 * Copyright 2009-2018 The VOTCA Development Team (http://www.votca.org)
 *
 * 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.
 *
 */

#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE bondedstatistics_test
#include <boost/test/unit_test.hpp>

#include <iostream>
#include <map>
#include <string>
#include "../csg_boltzmann/bondedstatistics.h"

using namespace std;
using namespace votca::csg;
using namespace votca::tools;

// used for rounding doubles so we can compare them
double round_(double v, int p) {
  v *= pow(10, p);
  v = round(v);
  v /= pow(10, p);
  return v;
}

BOOST_AUTO_TEST_SUITE(bondedstatistics_test)

BOOST_AUTO_TEST_CASE(test_bondedstatistics_constructor) {
  BondedStatistics bonded_statistics;
}

BOOST_AUTO_TEST_CASE(test_bondedstatistics_begin) {
  Topology top;
  // Create two bonded interactions
  string interaction_group = "covalent_bond";
  string interaction_group_compare = ":covalent_bond";
  auto bond1 = new IBond(0,1);
  bond1->setGroup(interaction_group);
  auto bond2 = new IBond(1,2);
  bond2->setGroup(interaction_group);

  top.AddBondedInteraction(bond1);
  top.AddBondedInteraction(bond2);

  BondedStatistics bonded_statistics;
  bonded_statistics.BeginCG(&top,nullptr);

  DataCollection<double>& data_collection = bonded_statistics.BondedValues();
  vector<DataCollection<double>::array *>& vector_of_arrays = data_collection.Data();
  BOOST_CHECK_EQUAL(vector_of_arrays.size(),2);
  BOOST_CHECK_EQUAL(vector_of_arrays.at(0)->getName(),interaction_group_compare);
  BOOST_CHECK_EQUAL(vector_of_arrays.at(1)->getName(),interaction_group_compare);
  // The arrays do not store any numbers at this point
  BOOST_CHECK_EQUAL(vector_of_arrays.at(0)->size(),0);
  BOOST_CHECK_EQUAL(vector_of_arrays.at(1)->size(),0);
  top.Cleanup();
}

BOOST_AUTO_TEST_CASE(test_evalconfiguration_begin) {
  Topology top;

  // Setup topology class
  {
    // Set the system size
    double x1 = 10.0;
    double y1 = 0.0;
    double z1 = 0.0;

    double x2 = 0.0;
    double y2 = 10.0;
    double z2 = 0.0;

    double x3 = 0.0;
    double y3 = 0.0;
    double z3 = 10.0;

    vec v1(x1,y1,z1);
    vec v2(x2,y2,z2);
    vec v3(x3,y3,z3);

    matrix box(v1,v2,v3);
    top.setBox(box);

    // Create three beads
    byte_t symmetry = 1;

    string bead_type_name = "type1";
    auto bead_type_ptr = top.GetOrCreateBeadType(bead_type_name);

    int residue_number = 1;
    double mass = 1.1;
    double charge = 0.3;

    // Create 3 beads
    string bead_name = "bead_test";
    vec pos_bead1(5.0,3.0,5.0);
    auto bead_ptr = top.CreateBead(symmetry,
        bead_name,bead_type_ptr,residue_number,mass,charge);
    bead_ptr->setId(0);
    bead_ptr->setPos(pos_bead1);

    string bead_name2 = "bead_test2";
    vec pos_bead2(5.0,4.0,5.0);
    auto bead_ptr2 = top.CreateBead(symmetry,
        bead_name2,bead_type_ptr,residue_number,mass,charge);
    bead_ptr2->setId(1);
    bead_ptr2->setPos(pos_bead2);

    string bead_name3 = "bead_test3";
    vec pos_bead3(5.0,6.0,5.0);
    auto bead_ptr3 = top.CreateBead(symmetry,
        bead_name3,bead_type_ptr,residue_number,mass,charge);
    bead_ptr2->setId(2);
    bead_ptr3->setPos(pos_bead3);

    // Create two bonded interactions
    string interaction_group = "covalent_bond";
    auto bond1 = new IBond(0,1);
    bond1->setGroup(interaction_group);
    auto bond2 = new IBond(1,2);
    bond2->setGroup(interaction_group);

    top.AddBondedInteraction(bond1);
    top.AddBondedInteraction(bond2);
  }

  BondedStatistics bonded_statistics;
  bonded_statistics.BeginCG(&top,nullptr);

  // Calling EvalConfiguration on IBond structures will store the distances
  // between the beads in the BondedStatitics class
  bonded_statistics.EvalConfiguration(&top,nullptr);

  DataCollection<double>& data_collection = bonded_statistics.BondedValues();
  vector<DataCollection<double>::array *>& vector_of_arrays = data_collection.Data();

  // Distance between bead 0 and bead 1
  BOOST_CHECK_EQUAL(vector_of_arrays.at(0)->at(0),1.0);
  // Distance between bead 1 and bead 2
  BOOST_CHECK_EQUAL(vector_of_arrays.at(1)->at(0),2.0);

  top.Cleanup();
}
BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include "loadgr.h"

void Loadgr::Synchronizing_loadgr() {
	titlegr = LoadGraph("Graph/title.png");
	startgr = LoadGraph("Graph/start.png");
	exitgr = LoadGraph("Graph/exitgr.png");
}<commit_msg>画像のロードを非同期読み込みに変更<commit_after>#include "loadgr.h"

void Loadgr::Synchronizing_loadgr() {
	SetUseASyncLoadFlag(true);
	titlegr = LoadGraph("Graph/title.png");
	startgr = LoadGraph("Graph/start.png");
	exitgr = LoadGraph("Graph/exitgr.png");
	SetUseASyncLoadFlag(false);
}<|endoftext|>