<commit_before>#include "BRDFile.h"

#include "utf8.h"
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <string.h>

// from stb.h -- return value must be freed
char **stringfile(char *buffer) {
	char **list = nullptr, *s;
	size_t count, i;

	// two passes through: first time count lines, second time set them
	for (i = 0; i < 2; ++i) {
		s = buffer;
		if (i == 1)
			list[0] = s;
		count = 1;
		while (*s) {
			if (*s == '\n' || *s == '\r') {
				// detect if both cr & lf are together
				int crlf = (s[0] + s[1]) == ('\n' + '\r');
				if (i == 1)
					*s = 0;
				if (crlf)
					++s;
				if (s[1]) { // it's not over yet
					if (i == 1)
						list[count] = s + 1;
					++count;
				}
			}
			++s;
		}
		if (i == 0) {
			list = (char **)malloc(sizeof(*list) * (count + 2));
			if (!list)
				return NULL;
			list[count] = 0;
		}
	}
	return list;
}

char *fix_to_utf8(char *s, char **arena, char *arena_end) {
	if (!utf8valid(s)) {
		return s;
	}
	char *p = *arena;
	char *begin = p;
	while (*s) {
		uint32_t c = (uint8_t)*s;
		if (c < 0x80) {
			if (p + 1 >= arena_end)
				goto done;
			*p++ = c;
		} else {
			if (p + 2 >= arena_end)
				goto done;
			*p++ = 0xc0 | (c >> 6);
			*p++ = 0x80 | (c & 0x3f);
		}
		++s;
	}
	if (p + 1 >= arena_end)
		goto done;
	*p++ = 0;

// GOTO done
done:
	*arena = p;
	return begin;
}

BRDFile::BRDFile(const char *buf, size_t buffer_size) {
	memset(this, 0, sizeof(*this));

	#define ENSURE(X) \
	  assert(X);      \
	  if (!(X))       \
	    return;

	ENSURE(buffer_size > 4);
	size_t file_buf_size = 3 * (1 + buffer_size);
	file_buf = (char *)malloc(file_buf_size);
	memcpy(file_buf, buf, buffer_size);
	file_buf[buffer_size] = 0;
	// This is for fixing degenerate utf8
	char *arena = &file_buf[buffer_size + 1];
	char *arena_end = file_buf + file_buf_size - 1;
	*arena_end = 0;

	// decode the file if it appears to be encoded:
	static const uint8_t encoded_header[] = {0x23, 0xe2, 0x63, 0x28};
	if (!memcmp(file_buf, encoded_header, 4)) {
		for (size_t i = 0; i < buffer_size; i++) {
			char x = file_buf[i];
			if (!(x == '\r' || x == '\n' || !x)) {
				int c = x;
				x = ~(((c >> 6) & 3) | (c << 2));
			}
			file_buf[i] = x;
		}
	}

	int current_block = 0;
	num_format = 0;
	num_parts = 0;
	num_pins = 0;
	num_nails = 0;
	int format_idx = 0;
	int parts_idx = 0;
	int pins_idx = 0;
	int nails_idx = 0;
	char **lines = stringfile(file_buf);
	if (!lines)
		return;
	char **lines_begin = lines;

	#undef ENSURE
	#define ENSURE(X)      \
	  assert(X);           \
	  if (!(X)) {          \
	    free(lines_begin); \
	    return;            \
	  }

	while (*lines) {
		char *line = *lines;
		++lines;

		while (isspace((uint8_t)*line))
			line++;
		if (!line[0])
			continue;
		if (!strcmp(line, "str_length:")) {
			current_block = 1;
			continue;
		}
		if (!strcmp(line, "var_data:")) {
			current_block = 2;
			continue;
		}
		if (!strcmp(line, "Format:")) {
			current_block = 3;
			continue;
		}
		if (!strcmp(line, "Parts:")) {
			current_block = 4;
			continue;
		}
		if (!strcmp(line, "Pins:")) {
			current_block = 5;
			continue;
		}
		if (!strcmp(line, "Nails:")) {
			current_block = 6;
			continue;
		}

		char *p = line;
		char *s;

		#define LOAD_INT(var) var = strtol(p, &p, 10)
		#define LOAD_STR(var)                        \
		  while (isspace((uint8_t)*p))               \
		    ++p;                                     \
		  s = p;                                     \
		  while (!isspace((uint8_t)*p))              \
		    ++p;                                     \
		  *p++ = 0;                                  \
		  var = fix_to_utf8(s, &arena, arena_end);

		switch (current_block) {
		case 2: { // var_data
			LOAD_INT(num_format);
			LOAD_INT(num_parts);
			LOAD_INT(num_pins);
			LOAD_INT(num_nails);
			ENSURE(num_format >= 0);
			ENSURE(num_parts >= 0);
			ENSURE(num_pins >= 0);
			ENSURE(num_nails >= 0);
			// NOTE: can allocate together because everything aligns fine
			// in 32- and 64-bit.
			size_t buf_size = sizeof(BRDPoint) * num_format;
			buf_size += sizeof(BRDPart) * num_parts;
			buf_size += sizeof(BRDPin) * num_pins;
			buf_size += sizeof(BRDNail) * num_nails;
			format = (BRDPoint *)malloc(buf_size);
			parts = (BRDPart *)(format + num_format);
			pins = (BRDPin *)(parts + num_parts);
			nails = (BRDNail *)(pins + num_pins);
		} break;
		case 3: { // Format
			ENSURE(format_idx < num_format);
			BRDPoint *fmt = &format[format_idx++];
			fmt->x = strtol(p, &p, 10);
			fmt->y = strtol(p, &p, 10);
		} break;
		case 4: { // Parts
			ENSURE(parts_idx < num_parts);
			BRDPart *part = &parts[parts_idx++];
			LOAD_STR(part->name);
			LOAD_INT(part->type);
			LOAD_INT(part->end_of_pins);
			ENSURE(part->end_of_pins <= num_pins);
		} break;
		case 5: { // Pins
			ENSURE(pins_idx < num_pins);
			BRDPin *pin = &pins[pins_idx++];
			LOAD_INT(pin->pos.x);
			LOAD_INT(pin->pos.y);
			LOAD_INT(pin->probe);
			LOAD_INT(pin->part);
			LOAD_STR(pin->net);
			ENSURE(pin->part <= num_parts);
		} break;
		case 6: { // Nails
			ENSURE(nails_idx < num_nails);
			BRDNail *nail = &nails[nails_idx++];
			LOAD_INT(nail->probe);
			LOAD_INT(nail->pos.x);
			LOAD_INT(nail->pos.y);
			LOAD_INT(nail->side);
			LOAD_STR(nail->net);
		} break;
		}
	}
	valid = current_block != 0;
}

// Ensure this files #defines dont bleed out
#undef LOAD_STR
#undef LOAD_INT
#undef ENSURE
<commit_msg>minor-bug: LOAD_STR() should end if null<commit_after>#include "BRDFile.h"

#include "utf8.h"
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <string.h>

// from stb.h -- return value must be freed
char **stringfile(char *buffer) {
	char **list = nullptr, *s;
	size_t count, i;

	// two passes through: first time count lines, second time set them
	for (i = 0; i < 2; ++i) {
		s = buffer;
		if (i == 1)
			list[0] = s;
		count = 1;
		while (*s) {
			if (*s == '\n' || *s == '\r') {
				// detect if both cr & lf are together
				int crlf = (s[0] + s[1]) == ('\n' + '\r');
				if (i == 1)
					*s = 0;
				if (crlf)
					++s;
				if (s[1]) { // it's not over yet
					if (i == 1)
						list[count] = s + 1;
					++count;
				}
			}
			++s;
		}
		if (i == 0) {
			list = (char **)malloc(sizeof(*list) * (count + 2));
			if (!list)
				return NULL;
			list[count] = 0;
		}
	}
	return list;
}

char *fix_to_utf8(char *s, char **arena, char *arena_end) {
	if (!utf8valid(s)) {
		return s;
	}
	char *p = *arena;
	char *begin = p;
	while (*s) {
		uint32_t c = (uint8_t)*s;
		if (c < 0x80) {
			if (p + 1 >= arena_end)
				goto done;
			*p++ = c;
		} else {
			if (p + 2 >= arena_end)
				goto done;
			*p++ = 0xc0 | (c >> 6);
			*p++ = 0x80 | (c & 0x3f);
		}
		++s;
	}
	if (p + 1 >= arena_end)
		goto done;
	*p++ = 0;

// GOTO done
done:
	*arena = p;
	return begin;
}

BRDFile::BRDFile(const char *buf, size_t buffer_size) {
	memset(this, 0, sizeof(*this));

	#define ENSURE(X) \
	  assert(X);      \
	  if (!(X))       \
	    return;

	ENSURE(buffer_size > 4);
	size_t file_buf_size = 3 * (1 + buffer_size);
	file_buf = (char *)malloc(file_buf_size);
	memcpy(file_buf, buf, buffer_size);
	file_buf[buffer_size] = 0;
	// This is for fixing degenerate utf8
	char *arena = &file_buf[buffer_size + 1];
	char *arena_end = file_buf + file_buf_size - 1;
	*arena_end = 0;

	// decode the file if it appears to be encoded:
	static const uint8_t encoded_header[] = {0x23, 0xe2, 0x63, 0x28};
	if (!memcmp(file_buf, encoded_header, 4)) {
		for (size_t i = 0; i < buffer_size; i++) {
			char x = file_buf[i];
			if (!(x == '\r' || x == '\n' || !x)) {
				int c = x;
				x = ~(((c >> 6) & 3) | (c << 2));
			}
			file_buf[i] = x;
		}
	}

	int current_block = 0;
	num_format = 0;
	num_parts = 0;
	num_pins = 0;
	num_nails = 0;
	int format_idx = 0;
	int parts_idx = 0;
	int pins_idx = 0;
	int nails_idx = 0;
	char **lines = stringfile(file_buf);
	if (!lines)
		return;
	char **lines_begin = lines;

	#undef ENSURE
	#define ENSURE(X)      \
	  assert(X);           \
	  if (!(X)) {          \
	    free(lines_begin); \
	    return;            \
	  }

	while (*lines) {
		char *line = *lines;
		++lines;

		while (isspace((uint8_t)*line))
			line++;
		if (!line[0])
			continue;
		if (!strcmp(line, "str_length:")) {
			current_block = 1;
			continue;
		}
		if (!strcmp(line, "var_data:")) {
			current_block = 2;
			continue;
		}
		if (!strcmp(line, "Format:")) {
			current_block = 3;
			continue;
		}
		if (!strcmp(line, "Parts:")) {
			current_block = 4;
			continue;
		}
		if (!strcmp(line, "Pins:")) {
			current_block = 5;
			continue;
		}
		if (!strcmp(line, "Nails:")) {
			current_block = 6;
			continue;
		}

		char *p = line;
		char *s;

		#define LOAD_INT(var) var = strtol(p, &p, 10)
		#define LOAD_STR(var)                        \
		  while ((*p) && (isspace((uint8_t)*p)))     \
		    ++p;                                     \
		  s = p;                                     \
		  while ((*p) && (!isspace((uint8_t)*p)))    \
		    ++p;                                     \
		  *p++ = 0;                                  \
		  var = fix_to_utf8(s, &arena, arena_end);

		switch (current_block) {
		case 2: { // var_data
			LOAD_INT(num_format);
			LOAD_INT(num_parts);
			LOAD_INT(num_pins);
			LOAD_INT(num_nails);
			ENSURE(num_format >= 0);
			ENSURE(num_parts >= 0);
			ENSURE(num_pins >= 0);
			ENSURE(num_nails >= 0);
			// NOTE: can allocate together because everything aligns fine
			// in 32- and 64-bit.
			size_t buf_size = sizeof(BRDPoint) * num_format;
			buf_size += sizeof(BRDPart) * num_parts;
			buf_size += sizeof(BRDPin) * num_pins;
			buf_size += sizeof(BRDNail) * num_nails;
			format = (BRDPoint *)malloc(buf_size);
			parts = (BRDPart *)(format + num_format);
			pins = (BRDPin *)(parts + num_parts);
			nails = (BRDNail *)(pins + num_pins);
		} break;
		case 3: { // Format
			ENSURE(format_idx < num_format);
			BRDPoint *fmt = &format[format_idx++];
			fmt->x = strtol(p, &p, 10);
			fmt->y = strtol(p, &p, 10);
		} break;
		case 4: { // Parts
			ENSURE(parts_idx < num_parts);
			BRDPart *part = &parts[parts_idx++];
			LOAD_STR(part->name);
			LOAD_INT(part->type);
			LOAD_INT(part->end_of_pins);
			ENSURE(part->end_of_pins <= num_pins);
		} break;
		case 5: { // Pins
			ENSURE(pins_idx < num_pins);
			BRDPin *pin = &pins[pins_idx++];
			LOAD_INT(pin->pos.x);
			LOAD_INT(pin->pos.y);
			LOAD_INT(pin->probe);
			LOAD_INT(pin->part);
			LOAD_STR(pin->net);
			ENSURE(pin->part <= num_parts);
		} break;
		case 6: { // Nails
			ENSURE(nails_idx < num_nails);
			BRDNail *nail = &nails[nails_idx++];
			LOAD_INT(nail->probe);
			LOAD_INT(nail->pos.x);
			LOAD_INT(nail->pos.y);
			LOAD_INT(nail->side);
			LOAD_STR(nail->net);
		} break;
		}
	}
	valid = current_block != 0;
}

// Ensure this files #defines dont bleed out
#undef LOAD_STR
#undef LOAD_INT
#undef ENSURE
<|endoftext|>


<commit_before>#ifndef TAKEWHILE__H__
#define TAKEWHILE__H__

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {

    //Forward declarations of TakeWhile and takewhile
    template <typename FilterFunc, typename Container>
    class TakeWhile;

    template <typename FilterFunc, typename Container>
    TakeWhile<FilterFunc, Container> takewhile(FilterFunc, Container &&);

    template <typename FilterFunc, typename T>
    TakeWhile<FilterFunc, std::initializer_list<T>> takewhile(
            FilterFunc, std::initializer_list<T> &&);

    template <typename FilterFunc, typename Container>
    class TakeWhile : IterBase<Container>{
        private:
            Container & container;
            FilterFunc filter_func;

            friend TakeWhile takewhile<FilterFunc, Container>(
                    FilterFunc, Container &&);

            template <typename FF, typename T>
            friend TakeWhile<FF, std::initializer_list<T>> takewhile(
                    FF, std::initializer_list<T> &&);

            using typename IterBase<Container>::contained_iter_type;

            using typename IterBase<Container>::contained_iter_ret;

            // Value constructor for use only in the takewhile function
            TakeWhile(FilterFunc filter_func, Container && container) :
                container(container),
                filter_func(filter_func)
            { }

            TakeWhile () = delete;
            TakeWhile & operator=(const TakeWhile &) = delete;

        public:
            TakeWhile(const TakeWhile &) = default;

            class Iterator {
                private:
                    contained_iter_type sub_iter;
                    const contained_iter_type sub_end;
                    FilterFunc filter_func;

                    // check if the current value is true under the predicate
                    // if it is not, set the sub_iter to the end using
                    // placement new to avoid the requirement of the iterator
                    // having an operator=
                    void check_current() {
                        if (!this->filter_func(*this->sub_iter)) {
                            this->sub_iter.~contained_iter_type();
                            new(&this->sub_iter) contained_iter_type(
                                    this->sub_end);
                        }
                    }

                public:
                    Iterator (contained_iter_type iter,
                            contained_iter_type end,
                            FilterFunc filter_func) :
                        sub_iter(iter),
                        sub_end(end),
                        filter_func(filter_func)
                    {
                        this->check_current();
                    }

                    contained_iter_ret operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator & operator++() {
                        ++this->sub_iter;
                        this->check_current();
                        return *this;
                    }

                    bool operator!=(const Iterator & other) const {
                        return this->sub_iter != other.sub_iter;
                    }
            };

            Iterator begin() const {
                return Iterator(
                        std::begin(this->container),
                        std::end(this->container),
                        this->filter_func);
            }

            Iterator end() const {
                return Iterator(
                        std::end(this->container),
                        std::end(this->container),
                        this->filter_func);
            }

    };

    // Helper function to instantiate a TakeWhile
    template <typename FilterFunc, typename Container>
    TakeWhile<FilterFunc, Container> takewhile(
            FilterFunc filter_func, Container && container) {
        return TakeWhile<FilterFunc, Container>(
                filter_func,
                std::forward<Container>(container));
    }

    template <typename FilterFunc, typename T>
    TakeWhile<FilterFunc, std::initializer_list<T>> takewhile(
            FilterFunc filter_func, std::initializer_list<T> && il)
    {
        return TakeWhile<FilterFunc, std::initializer_list<T>>(
                filter_func,
                std::move(il));
    }

}

#endif //ifndef TAKEWHILE__H__
<commit_msg>Fixes memory error in takewhile<commit_after>#ifndef TAKEWHILE__H__
#define TAKEWHILE__H__

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {

    //Forward declarations of TakeWhile and takewhile
    template <typename FilterFunc, typename Container>
    class TakeWhile;

    template <typename FilterFunc, typename Container>
    TakeWhile<FilterFunc, Container> takewhile(FilterFunc, Container &&);

    template <typename FilterFunc, typename T>
    TakeWhile<FilterFunc, std::initializer_list<T>> takewhile(
            FilterFunc, std::initializer_list<T> &&);

    template <typename FilterFunc, typename Container>
    class TakeWhile : IterBase<Container>{
        private:
            Container & container;
            FilterFunc filter_func;

            friend TakeWhile takewhile<FilterFunc, Container>(
                    FilterFunc, Container &&);

            template <typename FF, typename T>
            friend TakeWhile<FF, std::initializer_list<T>> takewhile(
                    FF, std::initializer_list<T> &&);

            using typename IterBase<Container>::contained_iter_type;

            using typename IterBase<Container>::contained_iter_ret;

            // Value constructor for use only in the takewhile function
            TakeWhile(FilterFunc filter_func, Container && container) :
                container(container),
                filter_func(filter_func)
            { }

            TakeWhile () = delete;
            TakeWhile & operator=(const TakeWhile &) = delete;

        public:
            TakeWhile(const TakeWhile &) = default;

            class Iterator {
                private:
                    contained_iter_type sub_iter;
                    const contained_iter_type sub_end;
                    FilterFunc filter_func;

                    // check if the current value is true under the predicate
                    // if it is not, set the sub_iter to the end using
                    // placement new to avoid the requirement of the iterator
                    // having an operator=
                    void check_current() {
                        if (!this->filter_func(*this->sub_iter)) {
                            this->sub_iter.~contained_iter_type();
                            new(&this->sub_iter) contained_iter_type(
                                    this->sub_end);
                        }
                    }

                public:
                    Iterator (contained_iter_type iter,
                            contained_iter_type end,
                            FilterFunc filter_func) :
                        sub_iter(iter),
                        sub_end(end),
                        filter_func(filter_func)
                    {
                        if (this->sub_iter != this->sub_end) {
                            // only do the check if not already at the end
                            this->check_current();
                        }
                    }

                    contained_iter_ret operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator & operator++() {
                        ++this->sub_iter;
                        this->check_current();
                        return *this;
                    }

                    bool operator!=(const Iterator & other) const {
                        return this->sub_iter != other.sub_iter;
                    }
            };

            Iterator begin() const {
                return Iterator(
                        std::begin(this->container),
                        std::end(this->container),
                        this->filter_func);
            }

            Iterator end() const {
                return Iterator(
                        std::end(this->container),
                        std::end(this->container),
                        this->filter_func);
            }

    };

    // Helper function to instantiate a TakeWhile
    template <typename FilterFunc, typename Container>
    TakeWhile<FilterFunc, Container> takewhile(
            FilterFunc filter_func, Container && container) {
        return TakeWhile<FilterFunc, Container>(
                filter_func,
                std::forward<Container>(container));
    }

    template <typename FilterFunc, typename T>
    TakeWhile<FilterFunc, std::initializer_list<T>> takewhile(
            FilterFunc filter_func, std::initializer_list<T> && il)
    {
        return TakeWhile<FilterFunc, std::initializer_list<T>>(
                filter_func,
                std::move(il));
    }

}

#endif //ifndef TAKEWHILE__H__
<|endoftext|>


<commit_before>/*################################################################################
  ##
  ##   Copyright (C) 2016-2020 Keith O'Hara
  ##
  ##   This file is part of the OptimLib C++ library.
  ##
  ##   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.
  ##
  ################################################################################*/

/*
 * BFGS method for quasi-Newton-based non-linear optimization
 */

#include "optim.hpp"

// [OPTIM_BEGIN]
optimlib_inline
bool
optim::internal::bfgs_impl(
    Vec_t& init_out_vals,
    std::function<double (const Vec_t& vals_inp, Vec_t* grad_out, void* opt_data)> opt_objfn,
    void* opt_data,
    algo_settings_t* settings_inp)
{
    // notation: 'p' stands for '+1'.

    bool success = false;

    const size_t n_vals = OPTIM_MATOPS_SIZE(init_out_vals);

    //
    // BFGS settings

    algo_settings_t settings;

    if (settings_inp) {
        settings = *settings_inp;
    }

    const int print_level = settings.print_level;

    const uint_t conv_failure_switch = settings.conv_failure_switch;

    const size_t iter_max = settings.iter_max;
    const double grad_err_tol = settings.grad_err_tol;
    const double rel_sol_change_tol = settings.rel_sol_change_tol;

    const double wolfe_cons_1 = settings.bfgs_settings.wolfe_cons_1; // line search tuning parameter
    const double wolfe_cons_2 = settings.bfgs_settings.wolfe_cons_2; // line search tuning parameter

    const bool vals_bound = settings.vals_bound;

    const Vec_t lower_bounds = settings.lower_bounds;
    const Vec_t upper_bounds = settings.upper_bounds;

    const VecInt_t bounds_type = determine_bounds_type(vals_bound, n_vals, lower_bounds, upper_bounds);

    // lambda function for box constraints

    std::function<double (const Vec_t& vals_inp, Vec_t* grad_out, void* box_data)> box_objfn \
    = [opt_objfn, vals_bound, bounds_type, lower_bounds, upper_bounds] (const Vec_t& vals_inp, Vec_t* grad_out, void* opt_data) \
    -> double
    {
        if (vals_bound) {
            Vec_t vals_inv_trans = inv_transform(vals_inp, bounds_type, lower_bounds, upper_bounds);
            double ret;

            if (grad_out) {
                Vec_t grad_obj = *grad_out;

                ret = opt_objfn(vals_inv_trans,&grad_obj,opt_data);

                // Mat_t jacob_matrix = jacobian_adjust(vals_inp,bounds_type,lower_bounds,upper_bounds);
                Vec_t jacob_vec = OPTIM_MATOPS_EXTRACT_DIAG( jacobian_adjust(vals_inp, bounds_type, lower_bounds, upper_bounds) );

                // *grad_out = jacob_matrix * grad_obj; // no need for transpose as jacob_matrix is diagonal
                *grad_out = OPTIM_MATOPS_HADAMARD_PROD(jacob_vec, grad_obj);
            } else {
                ret = opt_objfn(vals_inv_trans,nullptr,opt_data);
            }

            return ret;
        } else {
            return opt_objfn(vals_inp,grad_out,opt_data);
        }
    };

    // initialization

    Vec_t x = init_out_vals;

    if (! OPTIM_MATOPS_IS_FINITE(x) ) {
        printf("bfgs error: non-finite initial value(s).\n");
        return false;
    }

    if (vals_bound) { // should we transform the parameters?
        x = transform(x, bounds_type, lower_bounds, upper_bounds);
    }

    const Mat_t I_mat = OPTIM_MATOPS_EYE(n_vals);

    Mat_t W = I_mat;                            // initial approx. to (inverse) Hessian
    Vec_t grad(n_vals);                         // gradient vector
    Vec_t d = OPTIM_MATOPS_ZERO_VEC(n_vals);    // direction vector
    Vec_t s = OPTIM_MATOPS_ZERO_VEC(n_vals);
    Vec_t y = OPTIM_MATOPS_ZERO_VEC(n_vals);

    box_objfn(x, &grad, opt_data);

    double grad_err = OPTIM_MATOPS_L2NORM(grad);

    OPTIM_BFGS_TRACE(-1, grad_err, 0.0, x, d, grad, s, y, W);

    if (grad_err <= grad_err_tol) {
        return true;
    }

    // if ||gradient(initial values)|| > tolerance, continue

    d = - W*grad; // direction

    Vec_t x_p = x, grad_p = grad;

    line_search_mt(1.0, x_p, grad_p, d, &wolfe_cons_1, &wolfe_cons_2, box_objfn, opt_data);

    s = x_p - x;
    y = grad_p - grad;

    // update approx. inverse Hessian (W)

    double W_denom_term = OPTIM_MATOPS_DOT_PROD(y,s);
    Mat_t W_term_1;

    if (W_denom_term > 1E-10) {
        // checking whether the curvature condition holds: y's > 0
        W_term_1 = I_mat - s * (OPTIM_MATOPS_TRANSPOSE_IN_PLACE(y)) / W_denom_term;

        // perform rank-1 update of inverse Hessian approximation
        W = W_term_1 * W * (OPTIM_MATOPS_TRANSPOSE_IN_PLACE(W_term_1)) + s * (OPTIM_MATOPS_TRANSPOSE_IN_PLACE(s)) / W_denom_term;
    } else {
        W = 0.1 * W;
    }

    grad = grad_p;

    grad_err = OPTIM_MATOPS_L2NORM(grad_p);
    double rel_sol_change = OPTIM_MATOPS_L1NORM( OPTIM_MATOPS_ARRAY_DIV_ARRAY(s, (OPTIM_MATOPS_ARRAY_ADD_SCALAR(OPTIM_MATOPS_ABS(x), 1.0e-08)) ) );

    OPTIM_BFGS_TRACE(0, grad_err, rel_sol_change, x_p, d, grad_p, s, y, W);

    if (grad_err <= grad_err_tol) {
        init_out_vals = x_p;
        return true;
    }

    // begin loop

    size_t iter = 0;

    while (grad_err > grad_err_tol && rel_sol_change > rel_sol_change_tol && iter < iter_max) {
        ++iter;

        //

        d = - W*grad;

        line_search_mt(1.0, x_p, grad_p, d, &wolfe_cons_1, &wolfe_cons_2, box_objfn, opt_data);

        //

        s = x_p - x;
        y = grad_p - grad;

        W_denom_term = OPTIM_MATOPS_DOT_PROD(y,s);

        if (W_denom_term > 1E-10) {
            // checking the curvature condition y.s > 0
            W_term_1 = I_mat - s * OPTIM_MATOPS_TRANSPOSE_IN_PLACE(y) / W_denom_term;

            W = W_term_1 * W * OPTIM_MATOPS_TRANSPOSE_IN_PLACE(W_term_1) + s * OPTIM_MATOPS_TRANSPOSE_IN_PLACE(s) / W_denom_term;
        }

        //

        grad_err = OPTIM_MATOPS_L2NORM(grad_p);
        rel_sol_change = OPTIM_MATOPS_L1NORM( OPTIM_MATOPS_ARRAY_DIV_ARRAY(s, (OPTIM_MATOPS_ARRAY_ADD_SCALAR(OPTIM_MATOPS_ABS(x), 1.0e-08)) ) );

        x = x_p;
        grad = grad_p;

        //

        OPTIM_BFGS_TRACE(iter, grad_err, rel_sol_change, x, d, grad, s, y, W);
    }

    //

    if (vals_bound) {
        x_p = inv_transform(x_p, bounds_type, lower_bounds, upper_bounds);
    }

    error_reporting(init_out_vals, x_p, opt_objfn, opt_data,
                    success, grad_err, grad_err_tol, iter, iter_max,
                    conv_failure_switch, settings_inp);

    //

    return success;
}

optimlib_inline
bool
optim::bfgs(
    Vec_t& init_out_vals,
    std::function<double (const Vec_t& vals_inp, Vec_t* grad_out, void* opt_data)> opt_objfn,
    void* opt_data)
{
    return internal::bfgs_impl(init_out_vals, opt_objfn, opt_data, nullptr);
}

optimlib_inline
bool
optim::bfgs(
    Vec_t& init_out_vals,
    std::function<double (const Vec_t& vals_inp, Vec_t* grad_out, void* opt_data)> opt_objfn,
    void* opt_data,
    algo_settings_t& settings)
{
    return internal::bfgs_impl(init_out_vals, opt_objfn, opt_data, &settings);
}
<commit_msg>bfgs: added missing inverse transform upon early return<commit_after>/*################################################################################
  ##
  ##   Copyright (C) 2016-2020 Keith O'Hara
  ##
  ##   This file is part of the OptimLib C++ library.
  ##
  ##   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.
  ##
  ################################################################################*/

/*
 * BFGS method for quasi-Newton-based non-linear optimization
 */

#include "optim.hpp"

// [OPTIM_BEGIN]
optimlib_inline
bool
optim::internal::bfgs_impl(
    Vec_t& init_out_vals,
    std::function<double (const Vec_t& vals_inp, Vec_t* grad_out, void* opt_data)> opt_objfn,
    void* opt_data,
    algo_settings_t* settings_inp)
{
    // notation: 'p' stands for '+1'.

    bool success = false;

    const size_t n_vals = OPTIM_MATOPS_SIZE(init_out_vals);

    //
    // BFGS settings

    algo_settings_t settings;

    if (settings_inp) {
        settings = *settings_inp;
    }

    const int print_level = settings.print_level;

    const uint_t conv_failure_switch = settings.conv_failure_switch;

    const size_t iter_max = settings.iter_max;
    const double grad_err_tol = settings.grad_err_tol;
    const double rel_sol_change_tol = settings.rel_sol_change_tol;

    const double wolfe_cons_1 = settings.bfgs_settings.wolfe_cons_1; // line search tuning parameter
    const double wolfe_cons_2 = settings.bfgs_settings.wolfe_cons_2; // line search tuning parameter

    const bool vals_bound = settings.vals_bound;

    const Vec_t lower_bounds = settings.lower_bounds;
    const Vec_t upper_bounds = settings.upper_bounds;

    const VecInt_t bounds_type = determine_bounds_type(vals_bound, n_vals, lower_bounds, upper_bounds);

    // lambda function for box constraints

    std::function<double (const Vec_t& vals_inp, Vec_t* grad_out, void* box_data)> box_objfn \
    = [opt_objfn, vals_bound, bounds_type, lower_bounds, upper_bounds] (const Vec_t& vals_inp, Vec_t* grad_out, void* opt_data) \
    -> double
    {
        if (vals_bound) {
            Vec_t vals_inv_trans = inv_transform(vals_inp, bounds_type, lower_bounds, upper_bounds);
            double ret;

            if (grad_out) {
                Vec_t grad_obj = *grad_out;

                ret = opt_objfn(vals_inv_trans,&grad_obj,opt_data);

                // Mat_t jacob_matrix = jacobian_adjust(vals_inp,bounds_type,lower_bounds,upper_bounds);
                Vec_t jacob_vec = OPTIM_MATOPS_EXTRACT_DIAG( jacobian_adjust(vals_inp, bounds_type, lower_bounds, upper_bounds) );

                // *grad_out = jacob_matrix * grad_obj; // no need for transpose as jacob_matrix is diagonal
                *grad_out = OPTIM_MATOPS_HADAMARD_PROD(jacob_vec, grad_obj);
            } else {
                ret = opt_objfn(vals_inv_trans,nullptr,opt_data);
            }

            return ret;
        } else {
            return opt_objfn(vals_inp,grad_out,opt_data);
        }
    };

    // initialization

    Vec_t x = init_out_vals;

    if (! OPTIM_MATOPS_IS_FINITE(x) ) {
        printf("bfgs error: non-finite initial value(s).\n");
        return false;
    }

    if (vals_bound) { // should we transform the parameters?
        x = transform(x, bounds_type, lower_bounds, upper_bounds);
    }

    const Mat_t I_mat = OPTIM_MATOPS_EYE(n_vals);

    Mat_t W = I_mat;                            // initial approx. to (inverse) Hessian
    Vec_t grad(n_vals);                         // gradient vector
    Vec_t d = OPTIM_MATOPS_ZERO_VEC(n_vals);    // direction vector
    Vec_t s = OPTIM_MATOPS_ZERO_VEC(n_vals);
    Vec_t y = OPTIM_MATOPS_ZERO_VEC(n_vals);

    box_objfn(x, &grad, opt_data);

    double grad_err = OPTIM_MATOPS_L2NORM(grad);

    OPTIM_BFGS_TRACE(-1, grad_err, 0.0, x, d, grad, s, y, W);

    if (grad_err <= grad_err_tol) {
        return true;
    }

    // if ||gradient(initial values)|| > tolerance, continue

    d = - W*grad; // direction

    Vec_t x_p = x, grad_p = grad;

    line_search_mt(1.0, x_p, grad_p, d, &wolfe_cons_1, &wolfe_cons_2, box_objfn, opt_data);

    s = x_p - x;
    y = grad_p - grad;

    // update approx. inverse Hessian (W)

    double W_denom_term = OPTIM_MATOPS_DOT_PROD(y,s);
    Mat_t W_term_1;

    if (W_denom_term > 1E-10) {
        // checking whether the curvature condition holds: y's > 0
        W_term_1 = I_mat - s * (OPTIM_MATOPS_TRANSPOSE_IN_PLACE(y)) / W_denom_term;

        // perform rank-1 update of inverse Hessian approximation
        W = W_term_1 * W * (OPTIM_MATOPS_TRANSPOSE_IN_PLACE(W_term_1)) + s * (OPTIM_MATOPS_TRANSPOSE_IN_PLACE(s)) / W_denom_term;
    } else {
        W = 0.1 * W;
    }

    grad = grad_p;

    grad_err = OPTIM_MATOPS_L2NORM(grad_p);
    double rel_sol_change = OPTIM_MATOPS_L1NORM( OPTIM_MATOPS_ARRAY_DIV_ARRAY(s, (OPTIM_MATOPS_ARRAY_ADD_SCALAR(OPTIM_MATOPS_ABS(x), 1.0e-08)) ) );

    OPTIM_BFGS_TRACE(0, grad_err, rel_sol_change, x_p, d, grad_p, s, y, W);

    if (grad_err <= grad_err_tol) {
    	if (vals_bound) {
    	    init_out_vals = inv_transform(x_p, bounds_type, lower_bounds, upper_bounds);
    	}
    	else {
            init_out_vals = x_p;
        }
        return true;
    }

    // begin loop

    size_t iter = 0;

    while (grad_err > grad_err_tol && rel_sol_change > rel_sol_change_tol && iter < iter_max) {
        ++iter;

        //

        d = - W*grad;

        line_search_mt(1.0, x_p, grad_p, d, &wolfe_cons_1, &wolfe_cons_2, box_objfn, opt_data);

        //

        s = x_p - x;
        y = grad_p - grad;

        W_denom_term = OPTIM_MATOPS_DOT_PROD(y,s);

        if (W_denom_term > 1E-10) {
            // checking the curvature condition y.s > 0
            W_term_1 = I_mat - s * OPTIM_MATOPS_TRANSPOSE_IN_PLACE(y) / W_denom_term;

            W = W_term_1 * W * OPTIM_MATOPS_TRANSPOSE_IN_PLACE(W_term_1) + s * OPTIM_MATOPS_TRANSPOSE_IN_PLACE(s) / W_denom_term;
        }

        //

        grad_err = OPTIM_MATOPS_L2NORM(grad_p);
        rel_sol_change = OPTIM_MATOPS_L1NORM( OPTIM_MATOPS_ARRAY_DIV_ARRAY(s, (OPTIM_MATOPS_ARRAY_ADD_SCALAR(OPTIM_MATOPS_ABS(x), 1.0e-08)) ) );

        x = x_p;
        grad = grad_p;

        //

        OPTIM_BFGS_TRACE(iter, grad_err, rel_sol_change, x, d, grad, s, y, W);
    }

    //

    if (vals_bound) {
        x_p = inv_transform(x_p, bounds_type, lower_bounds, upper_bounds);
    }

    error_reporting(init_out_vals, x_p, opt_objfn, opt_data,
                    success, grad_err, grad_err_tol, iter, iter_max,
                    conv_failure_switch, settings_inp);

    //

    return success;
}

optimlib_inline
bool
optim::bfgs(
    Vec_t& init_out_vals,
    std::function<double (const Vec_t& vals_inp, Vec_t* grad_out, void* opt_data)> opt_objfn,
    void* opt_data)
{
    return internal::bfgs_impl(init_out_vals, opt_objfn, opt_data, nullptr);
}

optimlib_inline
bool
optim::bfgs(
    Vec_t& init_out_vals,
    std::function<double (const Vec_t& vals_inp, Vec_t* grad_out, void* opt_data)> opt_objfn,
    void* opt_data,
    algo_settings_t& settings)
{
    return internal::bfgs_impl(init_out_vals, opt_objfn, opt_data, &settings);
}
<|endoftext|>


<commit_before>#include <QtWidgets>
#include "LatticeFittingWindow.hpp"
#include "PointDetector.hpp"
#include "ImageProcessor.hpp"
#include "LatticeFittingDockWidget.hpp"

LatticeFittingWindow::LatticeFittingWindow()
  : _imageLabel(new QLabel(this)),
    _scrollArea(new QScrollArea(this)),
    _dockWidget(new LatticeFittingDockWidget(this)),
    _imageProcessor(new ImageProcessor(this)),
    _pointDetector(new PointDetector(*_dockWidget->_pointDetectorWidget, this))
{
  _imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
  _imageLabel->setScaledContents(true);

  _scrollArea->setBackgroundRole(QPalette::Dark);
  _scrollArea->setWidget(_imageLabel);

  auto layout = new QHBoxLayout;
  layout->addWidget(_scrollArea);

  auto centralWidget = new QWidget(this);
  centralWidget->setLayout(layout);
  setCentralWidget(centralWidget);

  createActions();
  createMenus();

  // dialog --------------------------------------------------------------------
  const auto picturesLocations =
    QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);

  _openDialog = new QFileDialog(
    this, tr("Open File"),
    picturesLocations.isEmpty() ? QDir::currentPath() : picturesLocations.last()
  );

  _openDialog->setAcceptMode(QFileDialog::AcceptOpen);
  _openDialog->selectMimeTypeFilter("image/jpeg");

  setStatusBar(new QStatusBar);

  addDockWidget(Qt::RightDockWidgetArea, _dockWidget);

  resize(QGuiApplication::primaryScreen()->availableSize() / 1.5);
}

bool LatticeFittingWindow::loadFile(const QString& fileName)
{
  _cvImage = cv::imread(fileName.toStdString());

  if (!_cvImage.data) {
    QMessageBox::information(
      this, QGuiApplication::applicationDisplayName(),
      tr("Cannot load %1.").arg(QDir::toNativeSeparators(fileName)));

    setWindowFilePath(QString());
    _imageLabel->setPixmap(QPixmap());
    _imageLabel->adjustSize();
    return false;
  }

  resetImage();

  cv::cvtColor(_cvImage, _cvGray, cv::COLOR_BGR2GRAY);

  setWindowFilePath(fileName);

  statusBar()->showMessage("Image Loaded successfully.");

  return true;
}

void LatticeFittingWindow::open()
{
  while (_openDialog->exec() && !loadFile(_openDialog->selectedFiles().first()));

  if (!_openDialog->selectedFiles().isEmpty())
    _openDialog->setDirectory(
      QFileInfo(_openDialog->selectedFiles().first()).path());
}

void LatticeFittingWindow::detect()
{
  if (_dockWidget->_thresholdWidget->isChecked()) {
    _pointDetector->detect(_cvThresh, _cvThresh);
    _imageLabel->setPixmap(
      _imageProcessor->mat2QPixmapGray(_pointDetector->_points_image)
    );
  } else {
    _pointDetector->detect(_cvImage, _cvGray);
    _imageLabel->setPixmap(
      _imageProcessor->mat2QPixmap(_pointDetector->_points_image)
    );
  }

  _imageLabel->adjustSize();
}

void LatticeFittingWindow::toggleDetect(bool toggle)
{
  if (toggle) {
    detect();
  } else {
    resetImage();

    if (_dockWidget->_thresholdWidget->isChecked())
      threshold(_dockWidget->_thresholdWidget->level());
  }
}

void LatticeFittingWindow::threshold(int value)
{
  _imageProcessor->threshold(_cvGray, _cvThresh, static_cast<double>(value));
  _imageLabel->setPixmap(_imageProcessor->mat2QPixmapGray(_cvThresh));
  _imageLabel->adjustSize();
}

void LatticeFittingWindow::toggleThreshold(bool toggle)
{
  if (toggle) {
    threshold(_dockWidget->_thresholdWidget->level());
  } else {
    resetImage();
  }

  if (_dockWidget->_pointDetectorWidget->isChecked())
    detect();
}

void LatticeFittingWindow::createActions()
{
  _openAct = new QAction(tr("&Open Image..."), this);
  _openAct->setShortcut(tr("Ctrl+O"));
  connect(_openAct, &QAction::triggered, this, &LatticeFittingWindow::open);

  _exitAct = new QAction(tr("E&xit"), this);
  _exitAct->setShortcut(tr("Ctrl+Q"));
  connect(_exitAct, &QAction::triggered, this, &LatticeFittingWindow::close);

  _detectAct = new QAction(tr("Detect Grid &Points"), this);
  _detectAct->setShortcut(tr("Ctrl+P"));
  connect(_detectAct, &QAction::triggered, this, &LatticeFittingWindow::detect);

  connect(_dockWidget->_pointDetectorWidget, SIGNAL(parameterChanged()), this,
          SLOT(detect()));
  connect(_dockWidget->_pointDetectorWidget, SIGNAL(toggled(bool)), this,
          SLOT(toggleDetect(bool)));
  connect(_dockWidget->_thresholdWidget, SIGNAL(levelChanged(int)), this,
          SLOT(threshold(int)));
  connect(_dockWidget->_thresholdWidget, SIGNAL(toggled(bool)), this,
          SLOT(toggleThreshold(bool)));
}

void LatticeFittingWindow::createMenus()
{
  _fileMenu = new QMenu(tr("&File"), this);
  _fileMenu->addAction(_openAct);
  _fileMenu->addSeparator();
  _fileMenu->addAction(_exitAct);

  _detectMenu = new QMenu(tr("&Detection"), this);
  _detectMenu->addAction(_detectAct);

  menuBar()->addMenu(_fileMenu);
  menuBar()->addMenu(_detectMenu);
}

void LatticeFittingWindow::resetImage()
{
  _imageLabel->setPixmap(_imageProcessor->mat2QPixmap(_cvImage));
  _imageLabel->adjustSize();
}
<commit_msg>Added Timeout for statusbar message<commit_after>#include <QtWidgets>
#include "LatticeFittingWindow.hpp"
#include "PointDetector.hpp"
#include "ImageProcessor.hpp"
#include "LatticeFittingDockWidget.hpp"

LatticeFittingWindow::LatticeFittingWindow()
  : _imageLabel(new QLabel(this)),
    _scrollArea(new QScrollArea(this)),
    _dockWidget(new LatticeFittingDockWidget(this)),
    _imageProcessor(new ImageProcessor(this)),
    _pointDetector(new PointDetector(*_dockWidget->_pointDetectorWidget, this))
{
  _imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
  _imageLabel->setScaledContents(true);

  _scrollArea->setBackgroundRole(QPalette::Dark);
  _scrollArea->setWidget(_imageLabel);

  auto layout = new QHBoxLayout;
  layout->addWidget(_scrollArea);

  auto centralWidget = new QWidget(this);
  centralWidget->setLayout(layout);
  setCentralWidget(centralWidget);

  createActions();
  createMenus();

  // dialog --------------------------------------------------------------------
  const auto picturesLocations =
    QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);

  _openDialog = new QFileDialog(
    this, tr("Open File"),
    picturesLocations.isEmpty() ? QDir::currentPath() : picturesLocations.last()
  );

  _openDialog->setAcceptMode(QFileDialog::AcceptOpen);
  _openDialog->selectMimeTypeFilter("image/jpeg");

  setStatusBar(new QStatusBar);

  addDockWidget(Qt::RightDockWidgetArea, _dockWidget);

  resize(QGuiApplication::primaryScreen()->availableSize() / 1.5);
}

bool LatticeFittingWindow::loadFile(const QString& fileName)
{
  _cvImage = cv::imread(fileName.toStdString());

  if (!_cvImage.data) {
    QMessageBox::information(
      this, QGuiApplication::applicationDisplayName(),
      tr("Cannot load %1.").arg(QDir::toNativeSeparators(fileName)));

    setWindowFilePath(QString());
    _imageLabel->setPixmap(QPixmap());
    _imageLabel->adjustSize();
    return false;
  }

  resetImage();

  cv::cvtColor(_cvImage, _cvGray, cv::COLOR_BGR2GRAY);

  setWindowFilePath(fileName);

  statusBar()->showMessage(QStringLiteral("Image Loaded successfully."), 10000);

  return true;
}

void LatticeFittingWindow::open()
{
  while (_openDialog->exec() && !loadFile(_openDialog->selectedFiles().first()));

  if (!_openDialog->selectedFiles().isEmpty())
    _openDialog->setDirectory(
      QFileInfo(_openDialog->selectedFiles().first()).path());
}

void LatticeFittingWindow::detect()
{
  if (_dockWidget->_thresholdWidget->isChecked()) {
    _pointDetector->detect(_cvThresh, _cvThresh);
    _imageLabel->setPixmap(
      _imageProcessor->mat2QPixmapGray(_pointDetector->_points_image)
    );
  } else {
    _pointDetector->detect(_cvImage, _cvGray);
    _imageLabel->setPixmap(
      _imageProcessor->mat2QPixmap(_pointDetector->_points_image)
    );
  }

  _imageLabel->adjustSize();
}

void LatticeFittingWindow::toggleDetect(bool toggle)
{
  if (toggle) {
    detect();
  } else {
    resetImage();

    if (_dockWidget->_thresholdWidget->isChecked())
      threshold(_dockWidget->_thresholdWidget->level());
  }
}

void LatticeFittingWindow::threshold(int value)
{
  _imageProcessor->threshold(_cvGray, _cvThresh, static_cast<double>(value));
  _imageLabel->setPixmap(_imageProcessor->mat2QPixmapGray(_cvThresh));
  _imageLabel->adjustSize();
}

void LatticeFittingWindow::toggleThreshold(bool toggle)
{
  if (toggle) {
    threshold(_dockWidget->_thresholdWidget->level());
  } else {
    resetImage();
  }

  if (_dockWidget->_pointDetectorWidget->isChecked())
    detect();
}

void LatticeFittingWindow::createActions()
{
  _openAct = new QAction(tr("&Open Image..."), this);
  _openAct->setShortcut(tr("Ctrl+O"));
  connect(_openAct, &QAction::triggered, this, &LatticeFittingWindow::open);

  _exitAct = new QAction(tr("E&xit"), this);
  _exitAct->setShortcut(tr("Ctrl+Q"));
  connect(_exitAct, &QAction::triggered, this, &LatticeFittingWindow::close);

  _detectAct = new QAction(tr("Detect Grid &Points"), this);
  _detectAct->setShortcut(tr("Ctrl+P"));
  connect(_detectAct, &QAction::triggered, this, &LatticeFittingWindow::detect);

  connect(_dockWidget->_pointDetectorWidget, SIGNAL(parameterChanged()), this,
          SLOT(detect()));
  connect(_dockWidget->_pointDetectorWidget, SIGNAL(toggled(bool)), this,
          SLOT(toggleDetect(bool)));
  connect(_dockWidget->_thresholdWidget, SIGNAL(levelChanged(int)), this,
          SLOT(threshold(int)));
  connect(_dockWidget->_thresholdWidget, SIGNAL(toggled(bool)), this,
          SLOT(toggleThreshold(bool)));
}

void LatticeFittingWindow::createMenus()
{
  _fileMenu = new QMenu(tr("&File"), this);
  _fileMenu->addAction(_openAct);
  _fileMenu->addSeparator();
  _fileMenu->addAction(_exitAct);

  _detectMenu = new QMenu(tr("&Detection"), this);
  _detectMenu->addAction(_detectAct);

  menuBar()->addMenu(_fileMenu);
  menuBar()->addMenu(_detectMenu);
}

void LatticeFittingWindow::resetImage()
{
  _imageLabel->setPixmap(_imageProcessor->mat2QPixmap(_cvImage));
  _imageLabel->adjustSize();
}
<|endoftext|>


<commit_before>#include <QCoreApplication>
#include <QStringList>
#include <QDebug>
#include <QElapsedTimer>
#include <QVector>
#include <cassert>
#include <algorithm>

#include <linux/perf_event.h>
#include <sys/syscall.h>
#include <unistd.h>

/* perf_event_open syscall wrapper */
static long
sys_perf_event_open(struct perf_event_attr *event,
                    pid_t pid, int cpu, int group_fd, unsigned long flags)
{
    return syscall(__NR_perf_event_open, event, pid, cpu, group_fd, flags);
}

static inline pid_t gettid()
{
    return syscall(SYS_gettid);
}

void do_compute(int repeat) {
    volatile int x = 0;
    while(x < repeat) {
        x++;
    }
}

void read_data(QVector<int> &v, QVector<int> &idx)
{
    volatile int b = 0;
    (void) b;
    int size = idx.size();
    for (int i = 0; i < (1 << 20); i++) {
        b = v[idx[i % size] % v.size()];
    }
}

class Sample {
public:
    bool slow;
    qint64 delta;
    qint64 inst;
    qint64 cpu;
    qint64 miss;
    friend QDebug operator<< (QDebug dbg, const Sample model) {
        dbg << "(" << model.slow << model.delta << "," << model.inst << "," << model.cpu << "," << model.miss << ")";
        return dbg;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QElapsedTimer timer;
    perf_event_attr attr_inst, attr_cpu, attr_miss;

    memset(&attr_inst, 0, sizeof(attr_inst));
    attr_inst.size = sizeof(attr_inst);
    attr_inst.type = PERF_TYPE_HARDWARE;
    attr_inst.config = PERF_COUNT_HW_INSTRUCTIONS;

    memset(&attr_cpu, 0, sizeof(attr_cpu));
    attr_cpu.size = sizeof(attr_cpu);
    attr_cpu.type = PERF_TYPE_SOFTWARE;
    attr_cpu.config = PERF_COUNT_SW_TASK_CLOCK;

    memset(&attr_miss, 0, sizeof(attr_miss));
    attr_miss.size = sizeof(attr_miss);
    attr_miss.type = PERF_TYPE_HW_CACHE;
    attr_miss.config = (PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16);

    pid_t tid = gettid();
    int fd_inst = sys_perf_event_open(&attr_inst, tid, -1, -1, 0);
    int fd_cpu = sys_perf_event_open(&attr_cpu, tid, -1, -1, 0);
    int fd_miss = sys_perf_event_open(&attr_cpu, tid, -1, -1, 0);

    int n = 100;
    QVector<Sample> samples(n);

    int scale = 1E6;
    QVector<int> work = { 1, 1, 1, 1, 1, 10 };

    int sz = 100000;
    QVector<int> idx_rnd(sz); // 100 000 * sizeof(int) = 400 kio, L1 32kio, LLC 4mb
    QVector<int> idx_lin(sz);
    QVector<int> buf_large(sz);
    QVector<int> buf_small(10);
    for (int i = 0; i < sz; i++) {
        idx_rnd[i] = i;
        idx_lin[i] = i;
    }
    std::random_shuffle(idx_rnd.begin(), idx_rnd.end());

    for (int i = 0; i < n; i++) {
        //qDebug() << "before";
        timer.restart();

        qint64 ret = 0;
        qint64 val_inst0, val_inst1;
        qint64 val_cpu0, val_cpu1;
        qint64 val_miss0, val_miss1;

        ret |= read(fd_inst, &val_inst0, sizeof(val_inst0));
        ret |= read(fd_cpu, &val_cpu0, sizeof(val_cpu0));
        ret = read(fd_miss, &val_miss0, sizeof(val_miss0));
        assert(ret > 0);

        bool slow = (i % 6) == 0;
        if (slow) {
            read_data(buf_large, idx_rnd);
        } else {
            read_data(buf_small, idx_lin);
        }

        //do_compute(work[i % work.size()] * scale);
        ret |= read(fd_inst, &val_inst1, sizeof(val_inst1));
        ret |= read(fd_cpu, &val_cpu1, sizeof(val_cpu1));
        ret |= read(fd_miss, &val_miss1, sizeof(val_miss1));
        qint64 delta = timer.nsecsElapsed() / 1000;
        //qDebug() << "after" << delta;
        samples[i].slow = slow;
        samples[i].delta = delta;
        samples[i].inst = (val_inst1 - val_inst0) / 1000;
        samples[i].cpu = (val_cpu1 - val_cpu0) / 1000;
        samples[i].miss = (val_miss1 - val_miss0);
    }
    for (const Sample &s: samples) {
        qDebug() << s;
    }
    return 0;
}

<commit_msg>Save results to a file<commit_after>#include <QCoreApplication>
#include <QStringList>
#include <QDebug>
#include <QElapsedTimer>
#include <QVector>
#include <QFile>
#include <cassert>
#include <algorithm>

#include <linux/perf_event.h>
#include <sys/syscall.h>
#include <unistd.h>

/* perf_event_open syscall wrapper */
static long
sys_perf_event_open(struct perf_event_attr *event,
                    pid_t pid, int cpu, int group_fd, unsigned long flags)
{
    return syscall(__NR_perf_event_open, event, pid, cpu, group_fd, flags);
}

static inline pid_t gettid()
{
    return syscall(SYS_gettid);
}

void do_compute(int repeat) {
    volatile int x = 0;
    while(x < repeat) {
        x++;
    }
}

void read_data(QVector<int> &v, QVector<int> &idx)
{
    volatile int b = 0;
    (void) b;
    int size = idx.size();
    for (int i = 0; i < (1 << 20); i++) {
        b = v[idx[i % size] % v.size()];
    }
}

class Sample {
public:
    bool slow;
    qint64 delta;
    qint64 inst;
    qint64 cpu;
    qint64 miss;
    friend QDebug operator<< (QDebug dbg, const Sample model) {
        dbg << "(" << model.slow << model.delta << "," << model.inst << "," << model.cpu << "," << model.miss << ")";
        return dbg;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QElapsedTimer timer;
    perf_event_attr attr_inst, attr_cpu, attr_miss;

    memset(&attr_inst, 0, sizeof(attr_inst));
    attr_inst.size = sizeof(attr_inst);
    attr_inst.type = PERF_TYPE_HARDWARE;
    attr_inst.config = PERF_COUNT_HW_INSTRUCTIONS;

    memset(&attr_cpu, 0, sizeof(attr_cpu));
    attr_cpu.size = sizeof(attr_cpu);
    attr_cpu.type = PERF_TYPE_SOFTWARE;
    attr_cpu.config = PERF_COUNT_SW_TASK_CLOCK;

    memset(&attr_miss, 0, sizeof(attr_miss));
    attr_miss.size = sizeof(attr_miss);
    attr_miss.type = PERF_TYPE_HW_CACHE;
    attr_miss.config = (PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16);

    pid_t tid = gettid();
    int fd_inst = sys_perf_event_open(&attr_inst, tid, -1, -1, 0);
    int fd_cpu = sys_perf_event_open(&attr_cpu, tid, -1, -1, 0);
    int fd_miss = sys_perf_event_open(&attr_cpu, tid, -1, -1, 0);

    int n = 100;
    QVector<Sample> samples(n);

    int scale = 1E6;
    QVector<int> work = { 1, 1, 1, 1, 1, 10 };

    int sz = 100000;
    QVector<int> idx_rnd(sz); // 100 000 * sizeof(int) = 400 kio, L1 32kio, LLC 4mb
    QVector<int> idx_lin(sz);
    QVector<int> buf_large(sz);
    QVector<int> buf_small(10);
    for (int i = 0; i < sz; i++) {
        idx_rnd[i] = i;
        idx_lin[i] = i;
    }
    std::random_shuffle(idx_rnd.begin(), idx_rnd.end());

    for (int i = 0; i < n; i++) {
        //qDebug() << "before";
        timer.restart();

        qint64 ret = 0;
        qint64 val_inst0, val_inst1;
        qint64 val_cpu0, val_cpu1;
        qint64 val_miss0, val_miss1;

        ret |= read(fd_inst, &val_inst0, sizeof(val_inst0));
        ret |= read(fd_cpu, &val_cpu0, sizeof(val_cpu0));
        ret = read(fd_miss, &val_miss0, sizeof(val_miss0));
        assert(ret > 0);

        bool slow = (i % 6) == 0;
        if (slow) {
            read_data(buf_large, idx_rnd);
        } else {
            read_data(buf_small, idx_lin);
        }

        //do_compute(work[i % work.size()] * scale);
        ret |= read(fd_inst, &val_inst1, sizeof(val_inst1));
        ret |= read(fd_cpu, &val_cpu1, sizeof(val_cpu1));
        ret |= read(fd_miss, &val_miss1, sizeof(val_miss1));
        qint64 delta = timer.nsecsElapsed() / 1000;
        //qDebug() << "after" << delta;
        samples[i].slow = slow;
        samples[i].delta = delta;
        samples[i].inst = (val_inst1 - val_inst0) / 1000;
        samples[i].cpu = (val_cpu1 - val_cpu0) / 1000;
        samples[i].miss = (val_miss1 - val_miss0);
    }
    for (const Sample &s: samples) {
        qDebug() << s;
    }

    QFile file("sample.csv");
    if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QTextStream out(&file);
        for (const Sample &s: samples) {
            out << s.slow << "," << s.delta << "," << s.inst << "," << s.cpu << "," << s.miss << "\n";
        }
        file.close();
    }

    return 0;
}

<|endoftext|>


<commit_before>#pragma once
#include <bts/blockchain/chain_interface.hpp>
#include <deque>

namespace bts { namespace blockchain {

   class pending_chain_state : public chain_interface, public std::enable_shared_from_this<pending_chain_state>
   {
      public:
                                        pending_chain_state( chain_interface_ptr prev_state = chain_interface_ptr() );
         virtual                        ~pending_chain_state()override;

         void                           set_prev_state( chain_interface_ptr prev_state );

         fc::ripemd160                  get_current_random_seed()const override;

         virtual void                   set_feed( const feed_record&  ) override;
         virtual ofeed_record           get_feed( const feed_index& )const override;
         virtual oprice                 get_median_delegate_price( const asset_id_type&, const asset_id_type& base_id = 0 )const override;
         virtual void                   set_market_dirty( const asset_id_type& quote_id, const asset_id_type& base_id )override;

         virtual fc::time_point_sec     now()const override;

         virtual void                   store_burn_record( const burn_record& br ) override;
         virtual oburn_record           fetch_burn_record( const burn_record_key& key )const override;

         virtual oasset_record          get_asset_record( const asset_id_type& id )const override;
         virtual obalance_record        get_balance_record( const balance_id_type& id )const override;
         virtual oaccount_record        get_account_record( const account_id_type& id )const override;
         virtual oaccount_record        get_account_record( const address& owner )const override;

         virtual odelegate_slate        get_delegate_slate( slate_id_type id )const override;
         virtual void                   store_delegate_slate( slate_id_type id, const delegate_slate& slate ) override;

         virtual bool                   is_known_transaction( const transaction_id_type& trx_id ) override;
         virtual otransaction_record    get_transaction( const transaction_id_type& trx_id, bool exact = true )const override;

         virtual void                   store_transaction( const transaction_id_type&, const transaction_record&  ) override;

         virtual oasset_record          get_asset_record( const string& symbol )const override;
         virtual oaccount_record        get_account_record( const string& name )const override;

         virtual omarket_status         get_market_status( const asset_id_type& quote_id, const asset_id_type& base_id )override;
         virtual void                   store_market_status( const market_status& s ) override;

         virtual omarket_order          get_lowest_ask_record( const asset_id_type& quote_id,
                                                               const asset_id_type& base_id )override;
         virtual oorder_record          get_bid_record( const market_index_key& )const override;
         virtual oorder_record          get_ask_record( const market_index_key& )const override;
         virtual oorder_record          get_short_record( const market_index_key& )const override;
         virtual ocollateral_record     get_collateral_record( const market_index_key& )const override;

         virtual void                   store_bid_record( const market_index_key& key, const order_record& ) override;
         virtual void                   store_ask_record( const market_index_key& key, const order_record& ) override;
         virtual void                   store_short_record( const market_index_key& key, const order_record& ) override;
         virtual void                   store_collateral_record( const market_index_key& key, const collateral_record& ) override;

#if 0
         virtual void                   store_proposal_record( const proposal_record& r )override;
         virtual oproposal_record       get_proposal_record( proposal_id_type id )const override;

         virtual void                   store_proposal_vote( const proposal_vote& r )override;
         virtual oproposal_vote         get_proposal_vote( proposal_vote_id_type id )const override;
#endif

         virtual void                   store_asset_record( const asset_record& r )override;
         virtual void                   store_balance_record( const balance_record& r )override;
         virtual void                   store_account_record( const account_record& r )override;

         virtual vector<operation>      get_recent_operations( operation_type_enum t )override;
         virtual void                   store_recent_operation( const operation& o )override;

         virtual variant                get_property( chain_property_enum property_id )const override;
         virtual void                   set_property( chain_property_enum property_id, const variant& property_value )override;

         virtual void                   store_slot_record( const slot_record& r ) override;
         virtual oslot_record           get_slot_record( const time_point_sec& start_time )const override;

         virtual void                   store_market_history_record( const market_history_key& key,
                                                                     const market_history_record& record )override;
         virtual omarket_history_record get_market_history_record( const market_history_key& key )const override;

         /**
          *  Based upon the current state of the database, calculate any updates that
          *  should be executed in a deterministic manner.
          */
         virtual void                   apply_deterministic_updates()override;

         /** polymorphically allcoate a new state */
         virtual chain_interface_ptr    create( const chain_interface_ptr& prev_state )const;
         /** apply changes from this pending state to the previous state */
         virtual void                   apply_changes()const;

         /** populate undo state with everything that would be necessary to revert this
          * pending state to the previous state.
          */
         virtual void                   get_undo_state( const chain_interface_ptr& undo_state )const;

         /** load the state from a variant */
         virtual void                   from_variant( const variant& v );
         /** convert the state to a variant */
         virtual variant                to_variant()const;

         virtual uint32_t               get_head_block_num()const override;

         virtual void                   set_market_transactions( vector<market_transaction> trxs )override;

         // NOTE: this isn't really part of the chain state, but more part of the block state
         vector<market_transaction>                                     market_transactions;

         unordered_map< asset_id_type, asset_record>                    assets;
         unordered_map< slate_id_type, delegate_slate>                  slates;
         unordered_map< account_id_type, account_record>                accounts;
         unordered_map< balance_id_type, balance_record>                balances;
         unordered_map< string, account_id_type>                        account_id_index;
         unordered_map< string, asset_id_type>                          symbol_id_index;
         unordered_map< transaction_id_type, transaction_record>        transactions;
         unordered_map< chain_property_type, variant>                   properties;
#if 0
         unordered_map<proposal_id_type, proposal_record>               proposals;
         map< proposal_vote_id_type, proposal_vote>                     proposal_votes;
#endif
         unordered_map<address, account_id_type>                        key_to_account;
         map< market_index_key, order_record>                           bids;
         map< market_index_key, order_record>                           asks;
         map< market_index_key, order_record>                           shorts;
         map< market_index_key, collateral_record>                      collateral;
         map<time_point_sec, slot_record>                               slots;
         map<market_history_key, market_history_record>                 market_history;
         map< std::pair<asset_id_type,asset_id_type>, market_status>    market_statuses;
         map<operation_type_enum, std::deque<operation>>                recent_operations;
         map<feed_index, feed_record>                                   feeds;
         map<burn_record_key,burn_record_value>                         burns;

         std::set<std::pair<asset_id_type, asset_id_type>>              _dirty_markets;

         chain_interface_weak_ptr                                       _prev_state;
   };

   typedef std::shared_ptr<pending_chain_state> pending_chain_state_ptr;

} } // bts::blockchain

// TODO: Why not reflect all members?
FC_REFLECT( bts::blockchain::pending_chain_state,
            (assets)(slates)(accounts)(balances)(account_id_index)(symbol_id_index)(transactions)
            (properties)(bids)(asks)(shorts)(collateral)(slots)(market_statuses)(feeds)(burns)(_dirty_markets) )
<commit_msg>Add missing #include<commit_after>#pragma once
#include <bts/blockchain/chain_interface.hpp>
#include <fc/reflect/reflect.hpp>
#include <deque>

namespace bts { namespace blockchain {

   class pending_chain_state : public chain_interface, public std::enable_shared_from_this<pending_chain_state>
   {
      public:
                                        pending_chain_state( chain_interface_ptr prev_state = chain_interface_ptr() );
         virtual                        ~pending_chain_state()override;

         void                           set_prev_state( chain_interface_ptr prev_state );

         fc::ripemd160                  get_current_random_seed()const override;

         virtual void                   set_feed( const feed_record&  ) override;
         virtual ofeed_record           get_feed( const feed_index& )const override;
         virtual oprice                 get_median_delegate_price( const asset_id_type&, const asset_id_type& base_id = 0 )const override;
         virtual void                   set_market_dirty( const asset_id_type& quote_id, const asset_id_type& base_id )override;

         virtual fc::time_point_sec     now()const override;

         virtual void                   store_burn_record( const burn_record& br ) override;
         virtual oburn_record           fetch_burn_record( const burn_record_key& key )const override;

         virtual oasset_record          get_asset_record( const asset_id_type& id )const override;
         virtual obalance_record        get_balance_record( const balance_id_type& id )const override;
         virtual oaccount_record        get_account_record( const account_id_type& id )const override;
         virtual oaccount_record        get_account_record( const address& owner )const override;

         virtual odelegate_slate        get_delegate_slate( slate_id_type id )const override;
         virtual void                   store_delegate_slate( slate_id_type id, const delegate_slate& slate ) override;

         virtual bool                   is_known_transaction( const transaction_id_type& trx_id ) override;
         virtual otransaction_record    get_transaction( const transaction_id_type& trx_id, bool exact = true )const override;

         virtual void                   store_transaction( const transaction_id_type&, const transaction_record&  ) override;

         virtual oasset_record          get_asset_record( const string& symbol )const override;
         virtual oaccount_record        get_account_record( const string& name )const override;

         virtual omarket_status         get_market_status( const asset_id_type& quote_id, const asset_id_type& base_id )override;
         virtual void                   store_market_status( const market_status& s ) override;

         virtual omarket_order          get_lowest_ask_record( const asset_id_type& quote_id,
                                                               const asset_id_type& base_id )override;
         virtual oorder_record          get_bid_record( const market_index_key& )const override;
         virtual oorder_record          get_ask_record( const market_index_key& )const override;
         virtual oorder_record          get_short_record( const market_index_key& )const override;
         virtual ocollateral_record     get_collateral_record( const market_index_key& )const override;

         virtual void                   store_bid_record( const market_index_key& key, const order_record& ) override;
         virtual void                   store_ask_record( const market_index_key& key, const order_record& ) override;
         virtual void                   store_short_record( const market_index_key& key, const order_record& ) override;
         virtual void                   store_collateral_record( const market_index_key& key, const collateral_record& ) override;

#if 0
         virtual void                   store_proposal_record( const proposal_record& r )override;
         virtual oproposal_record       get_proposal_record( proposal_id_type id )const override;

         virtual void                   store_proposal_vote( const proposal_vote& r )override;
         virtual oproposal_vote         get_proposal_vote( proposal_vote_id_type id )const override;
#endif

         virtual void                   store_asset_record( const asset_record& r )override;
         virtual void                   store_balance_record( const balance_record& r )override;
         virtual void                   store_account_record( const account_record& r )override;

         virtual vector<operation>      get_recent_operations( operation_type_enum t )override;
         virtual void                   store_recent_operation( const operation& o )override;

         virtual variant                get_property( chain_property_enum property_id )const override;
         virtual void                   set_property( chain_property_enum property_id, const variant& property_value )override;

         virtual void                   store_slot_record( const slot_record& r ) override;
         virtual oslot_record           get_slot_record( const time_point_sec& start_time )const override;

         virtual void                   store_market_history_record( const market_history_key& key,
                                                                     const market_history_record& record )override;
         virtual omarket_history_record get_market_history_record( const market_history_key& key )const override;

         /**
          *  Based upon the current state of the database, calculate any updates that
          *  should be executed in a deterministic manner.
          */
         virtual void                   apply_deterministic_updates()override;

         /** polymorphically allcoate a new state */
         virtual chain_interface_ptr    create( const chain_interface_ptr& prev_state )const;
         /** apply changes from this pending state to the previous state */
         virtual void                   apply_changes()const;

         /** populate undo state with everything that would be necessary to revert this
          * pending state to the previous state.
          */
         virtual void                   get_undo_state( const chain_interface_ptr& undo_state )const;

         /** load the state from a variant */
         virtual void                   from_variant( const variant& v );
         /** convert the state to a variant */
         virtual variant                to_variant()const;

         virtual uint32_t               get_head_block_num()const override;

         virtual void                   set_market_transactions( vector<market_transaction> trxs )override;

         // NOTE: this isn't really part of the chain state, but more part of the block state
         vector<market_transaction>                                     market_transactions;

         unordered_map< asset_id_type, asset_record>                    assets;
         unordered_map< slate_id_type, delegate_slate>                  slates;
         unordered_map< account_id_type, account_record>                accounts;
         unordered_map< balance_id_type, balance_record>                balances;
         unordered_map< string, account_id_type>                        account_id_index;
         unordered_map< string, asset_id_type>                          symbol_id_index;
         unordered_map< transaction_id_type, transaction_record>        transactions;
         unordered_map< chain_property_type, variant>                   properties;
#if 0
         unordered_map<proposal_id_type, proposal_record>               proposals;
         map< proposal_vote_id_type, proposal_vote>                     proposal_votes;
#endif
         unordered_map<address, account_id_type>                        key_to_account;
         map< market_index_key, order_record>                           bids;
         map< market_index_key, order_record>                           asks;
         map< market_index_key, order_record>                           shorts;
         map< market_index_key, collateral_record>                      collateral;
         map<time_point_sec, slot_record>                               slots;
         map<market_history_key, market_history_record>                 market_history;
         map< std::pair<asset_id_type,asset_id_type>, market_status>    market_statuses;
         map<operation_type_enum, std::deque<operation>>                recent_operations;
         map<feed_index, feed_record>                                   feeds;
         map<burn_record_key,burn_record_value>                         burns;

         std::set<std::pair<asset_id_type, asset_id_type>>              _dirty_markets;

         chain_interface_weak_ptr                                       _prev_state;
   };

   typedef std::shared_ptr<pending_chain_state> pending_chain_state_ptr;

} } // bts::blockchain

// TODO: Why not reflect all members?
FC_REFLECT( bts::blockchain::pending_chain_state,
            (assets)(slates)(accounts)(balances)(account_id_index)(symbol_id_index)(transactions)
            (properties)(bids)(asks)(shorts)(collateral)(slots)(market_statuses)(feeds)(burns)(_dirty_markets) )
<|endoftext|>


<commit_before>#pragma once

#include <eosio/chain/transaction_metadata.hpp>
#include <eosio/chain/block_state.hpp>
#include <eosio/chain/exceptions.hpp>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>

namespace fc {
  inline std::size_t hash_value( const fc::sha256& v ) {
     return v._hash[3];
  }
}

namespace eosio { namespace chain {

using namespace boost::multi_index;

enum class trx_enum_type {
   unknown = 0,
   persisted = 1,
   forked = 2,
   aborted = 3
};

struct unapplied_transaction {
   const transaction_metadata_ptr trx_meta;
   const fc::time_point           expiry;
   trx_enum_type                  trx_type = trx_enum_type::unknown;

   const transaction_id_type& id()const { return trx_meta->id(); }

   unapplied_transaction(const unapplied_transaction&) = delete;
   unapplied_transaction() = delete;
   unapplied_transaction& operator=(const unapplied_transaction&) = delete;
   unapplied_transaction(unapplied_transaction&&) = default;
};

/**
 * Track unapplied transactions for persisted, forked blocks, and aborted blocks.
 * Persisted are first so that they can be applied in each block until expired.
 */
class unapplied_transaction_queue {
public:
   enum class process_mode {
      non_speculative,           // HEAD, READ_ONLY, IRREVERSIBLE
      speculative_non_producer,  // will never produce
      speculative_producer       // can produce
   };

private:
   struct by_trx_id;
   struct by_type;
   struct by_expiry;

   typedef multi_index_container< unapplied_transaction,
      indexed_by<
         hashed_unique< tag<by_trx_id>,
               const_mem_fun<unapplied_transaction, const transaction_id_type&, &unapplied_transaction::id>
         >,
         ordered_non_unique< tag<by_type>, member<unapplied_transaction, trx_enum_type, &unapplied_transaction::trx_type> >,
         ordered_non_unique< tag<by_expiry>, member<unapplied_transaction, const fc::time_point, &unapplied_transaction::expiry> >
      >
   > unapplied_trx_queue_type;

   unapplied_trx_queue_type queue;
   process_mode mode = process_mode::speculative_producer;

public:

   void set_mode( process_mode new_mode ) {
      if( new_mode != mode ) {
         FC_ASSERT( empty(), "set_mode, queue required to be empty" );
      }
      mode = new_mode;
   }

   bool empty() const {
      return queue.empty();
   }

   size_t size() const {
      return queue.size();
   }

   void clear() {
      queue.clear();
   }

   bool contains_persisted()const {
      return queue.get<by_type>().find( trx_enum_type::persisted ) != queue.get<by_type>().end();
   }

   bool is_persisted(const transaction_metadata_ptr& trx)const {
      auto itr = queue.get<by_trx_id>().find( trx->id() );
      if( itr == queue.get<by_trx_id>().end() ) return false;
      return itr->trx_type == trx_enum_type::persisted;
   }

   transaction_metadata_ptr get_trx( const transaction_id_type& id ) const {
      auto itr = queue.get<by_trx_id>().find( id );
      if( itr == queue.get<by_trx_id>().end() ) return {};
      return itr->trx_meta;
   }

   template <typename Func>
   bool clear_expired( const time_point& pending_block_time, const time_point& deadline, Func&& callback ) {
      auto& persisted_by_expiry = queue.get<by_expiry>();
      while(!persisted_by_expiry.empty() && persisted_by_expiry.begin()->expiry <= pending_block_time) {
         if (deadline <= fc::time_point::now()) {
            return false;
         }
         callback( persisted_by_expiry.begin()->id(), persisted_by_expiry.begin()->trx_type );
         persisted_by_expiry.erase( persisted_by_expiry.begin() );
      }
      return true;
   }

   void clear_applied( const block_state_ptr& bs ) {
      if( empty() ) return;
      auto& idx = queue.get<by_trx_id>();
      for( const auto& receipt : bs->block->transactions ) {
         if( receipt.trx.contains<packed_transaction>() ) {
            const auto& pt = receipt.trx.get<packed_transaction>();
            idx.erase( pt.id() );
         }
      }
   }

   void add_forked( const branch_type& forked_branch ) {
      if( mode == process_mode::non_speculative || mode == process_mode::speculative_non_producer ) return;
      // forked_branch is in reverse order
      for( auto ritr = forked_branch.rbegin(), rend = forked_branch.rend(); ritr != rend; ++ritr ) {
         const block_state_ptr& bsptr = *ritr;
         for( auto itr = bsptr->trxs_metas().begin(), end = bsptr->trxs_metas().end(); itr != end; ++itr ) {
            const auto& trx = *itr;
            fc::time_point expiry = trx->packed_trx()->expiration();
            queue.insert( { trx, expiry, trx_enum_type::forked } );
         }
      }
   }

   void add_aborted( std::vector<transaction_metadata_ptr> aborted_trxs ) {
      if( mode == process_mode::non_speculative || mode == process_mode::speculative_non_producer ) return;
      for( auto& trx : aborted_trxs ) {
         fc::time_point expiry = trx->packed_trx()->expiration();
         queue.insert( { std::move( trx ), expiry, trx_enum_type::aborted } );
      }
   }

   void add_persisted( const transaction_metadata_ptr& trx ) {
      if( mode == process_mode::non_speculative ) return;
      auto itr = queue.get<by_trx_id>().find( trx->id() );
      if( itr == queue.get<by_trx_id>().end() ) {
         fc::time_point expiry = trx->packed_trx()->expiration();
         queue.insert( { trx, expiry, trx_enum_type::persisted } );
      } else if( itr->trx_type != trx_enum_type::persisted ) {
         queue.get<by_trx_id>().modify( itr, [](auto& un){
            un.trx_type = trx_enum_type::persisted;
         } );
      }
   }

   using iterator = unapplied_trx_queue_type::index<by_type>::type::iterator;

   iterator begin() { return queue.get<by_type>().begin(); }
   iterator end() { return queue.get<by_type>().end(); }

   iterator persisted_begin() { return queue.get<by_type>().lower_bound( trx_enum_type::persisted ); }
   iterator persisted_end() { return queue.get<by_type>().upper_bound( trx_enum_type::persisted ); }

   iterator erase( iterator itr ) { return queue.get<by_type>().erase( itr ); }

};

} } //eosio::chain
<commit_msg>Retain persisted trx until expired on speculative nodes<commit_after>#pragma once

#include <eosio/chain/transaction_metadata.hpp>
#include <eosio/chain/block_state.hpp>
#include <eosio/chain/exceptions.hpp>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>

namespace fc {
  inline std::size_t hash_value( const fc::sha256& v ) {
     return v._hash[3];
  }
}

namespace eosio { namespace chain {

using namespace boost::multi_index;

enum class trx_enum_type {
   unknown = 0,
   persisted = 1,
   forked = 2,
   aborted = 3
};

struct unapplied_transaction {
   const transaction_metadata_ptr trx_meta;
   const fc::time_point           expiry;
   trx_enum_type                  trx_type = trx_enum_type::unknown;

   const transaction_id_type& id()const { return trx_meta->id(); }

   unapplied_transaction(const unapplied_transaction&) = delete;
   unapplied_transaction() = delete;
   unapplied_transaction& operator=(const unapplied_transaction&) = delete;
   unapplied_transaction(unapplied_transaction&&) = default;
};

/**
 * Track unapplied transactions for persisted, forked blocks, and aborted blocks.
 * Persisted are first so that they can be applied in each block until expired.
 */
class unapplied_transaction_queue {
public:
   enum class process_mode {
      non_speculative,           // HEAD, READ_ONLY, IRREVERSIBLE
      speculative_non_producer,  // will never produce
      speculative_producer       // can produce
   };

private:
   struct by_trx_id;
   struct by_type;
   struct by_expiry;

   typedef multi_index_container< unapplied_transaction,
      indexed_by<
         hashed_unique< tag<by_trx_id>,
               const_mem_fun<unapplied_transaction, const transaction_id_type&, &unapplied_transaction::id>
         >,
         ordered_non_unique< tag<by_type>, member<unapplied_transaction, trx_enum_type, &unapplied_transaction::trx_type> >,
         ordered_non_unique< tag<by_expiry>, member<unapplied_transaction, const fc::time_point, &unapplied_transaction::expiry> >
      >
   > unapplied_trx_queue_type;

   unapplied_trx_queue_type queue;
   process_mode mode = process_mode::speculative_producer;

public:

   void set_mode( process_mode new_mode ) {
      if( new_mode != mode ) {
         FC_ASSERT( empty(), "set_mode, queue required to be empty" );
      }
      mode = new_mode;
   }

   bool empty() const {
      return queue.empty();
   }

   size_t size() const {
      return queue.size();
   }

   void clear() {
      queue.clear();
   }

   bool contains_persisted()const {
      return queue.get<by_type>().find( trx_enum_type::persisted ) != queue.get<by_type>().end();
   }

   bool is_persisted(const transaction_metadata_ptr& trx)const {
      auto itr = queue.get<by_trx_id>().find( trx->id() );
      if( itr == queue.get<by_trx_id>().end() ) return false;
      return itr->trx_type == trx_enum_type::persisted;
   }

   transaction_metadata_ptr get_trx( const transaction_id_type& id ) const {
      auto itr = queue.get<by_trx_id>().find( id );
      if( itr == queue.get<by_trx_id>().end() ) return {};
      return itr->trx_meta;
   }

   template <typename Func>
   bool clear_expired( const time_point& pending_block_time, const time_point& deadline, Func&& callback ) {
      auto& persisted_by_expiry = queue.get<by_expiry>();
      while(!persisted_by_expiry.empty() && persisted_by_expiry.begin()->expiry <= pending_block_time) {
         if (deadline <= fc::time_point::now()) {
            return false;
         }
         callback( persisted_by_expiry.begin()->id(), persisted_by_expiry.begin()->trx_type );
         persisted_by_expiry.erase( persisted_by_expiry.begin() );
      }
      return true;
   }

   void clear_applied( const block_state_ptr& bs ) {
      if( empty() ) return;
      auto& idx = queue.get<by_trx_id>();
      for( const auto& receipt : bs->block->transactions ) {
         if( receipt.trx.contains<packed_transaction>() ) {
            const auto& pt = receipt.trx.get<packed_transaction>();
            auto itr = queue.get<by_trx_id>().find( pt.id() );
            if( itr != queue.get<by_trx_id>().end() ) {
               if( itr->trx_type != trx_enum_type::persisted ) {
                  idx.erase( pt.id() );
               }
            }
         }
      }
   }

   void add_forked( const branch_type& forked_branch ) {
      if( mode == process_mode::non_speculative || mode == process_mode::speculative_non_producer ) return;
      // forked_branch is in reverse order
      for( auto ritr = forked_branch.rbegin(), rend = forked_branch.rend(); ritr != rend; ++ritr ) {
         const block_state_ptr& bsptr = *ritr;
         for( auto itr = bsptr->trxs_metas().begin(), end = bsptr->trxs_metas().end(); itr != end; ++itr ) {
            const auto& trx = *itr;
            fc::time_point expiry = trx->packed_trx()->expiration();
            queue.insert( { trx, expiry, trx_enum_type::forked } );
         }
      }
   }

   void add_aborted( std::vector<transaction_metadata_ptr> aborted_trxs ) {
      if( mode == process_mode::non_speculative || mode == process_mode::speculative_non_producer ) return;
      for( auto& trx : aborted_trxs ) {
         fc::time_point expiry = trx->packed_trx()->expiration();
         queue.insert( { std::move( trx ), expiry, trx_enum_type::aborted } );
      }
   }

   void add_persisted( const transaction_metadata_ptr& trx ) {
      if( mode == process_mode::non_speculative ) return;
      auto itr = queue.get<by_trx_id>().find( trx->id() );
      if( itr == queue.get<by_trx_id>().end() ) {
         fc::time_point expiry = trx->packed_trx()->expiration();
         queue.insert( { trx, expiry, trx_enum_type::persisted } );
      } else if( itr->trx_type != trx_enum_type::persisted ) {
         queue.get<by_trx_id>().modify( itr, [](auto& un){
            un.trx_type = trx_enum_type::persisted;
         } );
      }
   }

   using iterator = unapplied_trx_queue_type::index<by_type>::type::iterator;

   iterator begin() { return queue.get<by_type>().begin(); }
   iterator end() { return queue.get<by_type>().end(); }

   iterator persisted_begin() { return queue.get<by_type>().lower_bound( trx_enum_type::persisted ); }
   iterator persisted_end() { return queue.get<by_type>().upper_bound( trx_enum_type::persisted ); }

   iterator erase( iterator itr ) { return queue.get<by_type>().erase( itr ); }

};

} } //eosio::chain
<|endoftext|>