text:
#include <iostream>
#include <fstream>

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#define USE_PERIODIC_FFT
#include <imgproc/derivative_gradient.hpp>
#include <imgproc/susan.hpp>
#include <imgproc/rcmg.hpp>
#include <imgproc/quadratureG2.hpp>
#include <imgproc/quadratureS.hpp>
#include <imgproc/quadratureSF.hpp>
#include <imgproc/quadratureLGF.hpp>
#include <imgproc/pc_sqf.hpp>
#include <imgproc/pc_lgf.hpp>
#include <imgproc/pc_matlab.hpp>
#include <imgproc/laplace.hpp>

#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>

using namespace lsfm;
using namespace std;
namespace fs = boost::filesystem;

constexpr int runs = 1;

constexpr int ENTRY_SQR = 1;
constexpr int ENTRY_RGB = 2;
constexpr int ENTRY_NO_3 = 4;
constexpr int ENTRY_NO_5 = 8;

typedef double FT;

constexpr FT mag_th = static_cast<FT>(0.05);

struct Entry {
    Entry() {}

    Entry(const cv::Ptr<FilterI<uchar>>& a, const std::string& b, int f = 0)
        : filter(a), name(b), flags(f) {}

    cv::Ptr<FilterI<uchar>> filter;
    std::string name;
    int flags;

    Value value(const std::string &name) {
        return dynamic_cast<ValueManager*>(&(*filter))->value(name);
    }

    void value(const std::string &name, const Value &v) {
        dynamic_cast<ValueManager*>(&(*filter))->value(name, v);
    }

    inline bool rgb() const {
        return flags & ENTRY_RGB;
    }

    inline bool sqr() const {
        return flags & ENTRY_SQR;
    }

    inline int border() const {
        if (flags & ENTRY_NO_3)
            return 2;
        if (flags & ENTRY_NO_5)
            return 3;
        return 0;
    }

    inline lsfm::FilterResults process(const cv::Mat src) {
        filter->process(src);
        return filter->results();
    }
};

inline cv::Vec3b dirColor(FT val) {
    static FT r = static_cast<FT>(CV_PI / 4);
    static cv::Vec3b colors[] = { cv::Vec3b(255,0  ,150),
                                  cv::Vec3b(255,0  ,255),
                                  cv::Vec3b(0  ,0  ,255),
                                  cv::Vec3b(0  ,150,255),
                                  cv::Vec3b(0  ,255,255),
                                  cv::Vec3b(0  ,255,0),
                                  cv::Vec3b(255,255,0),
                                  cv::Vec3b(255,0  ,0),
                                  cv::Vec3b(255,0  ,150) };
    FT div = val / r;
    int divi = static_cast<int>(div);
    cv::Vec<FT, 3> a = colors[divi + 4], b = colors[divi + 4 + (val < 0 ? -1 : 1)];
    /*cv::Vec<FT, 3> c = b - a;
    FT mul = abs(div) - abs(divi);
    cv::Vec<FT, 3> d = c * mul;
    cv::Vec3b res = a + d;
    return res;*/
    return  a + (b - a) * (abs(div) - abs(divi));
}

void saveDir(cv::Mat &data, const std::string &name, const cv::Mat &mask = cv::Mat()) {
    cv::Mat tmp(data.size(), CV_8UC3);
    cv::Vec3b *pdst = tmp.ptr<cv::Vec3b>();
    if (data.isContinuous() && data.isContinuous()) {
        const FT *pd = data.ptr<FT>();
        int size = data.rows * data.cols;
        for (int j = 0; j != size; ++j) {
            pdst[j] = dirColor(pd[j]);
        }
    }
    else {
        for (int i = 0; i != data.rows; ++i, pdst += data.cols) {
            const FT *pd = data.ptr<FT>(i);
            for (int j = 0; j != data.cols; ++j) {
                pdst[j] = dirColor(pd[j]);
            }
        }
    }
    if (!mask.empty())
        tmp.setTo(cv::Scalar(0, 0, 0), mask < mag_th);
    cv::imwrite("./grad/" + name + ".png", tmp);
}

void savePhase(cv::Mat &data, const std::string &name, const cv::Mat &energy) {
    double vmin, vmax;
    cv::minMaxIdx(energy, &vmin, &vmax);
    cv::Mat en = energy / vmax;

    cv::Mat tmp(data.size(), CV_8UC3);
    cv::Vec3b *pdst = tmp.ptr<cv::Vec3b>();
    if (data.isContinuous() && en.isContinuous()) {
        const FT *pd = data.ptr<FT>();
        const FT *pe = en.ptr<FT>();
        int size = data.rows * data.cols;
        for (int j = 0; j != size; ++j) {
            pdst[j] = dirColor(pd[j]) * pe[j];
        }
    }
    else {
        for (int i = 0; i != data.rows; ++i, pdst += data.cols) {
            const FT *pd = data.ptr<FT>(i);
            const FT *pe = en.ptr<FT>(i);
            for (int j = 0; j != data.cols; ++j) {
                pdst[j] = dirColor(pd[j]) * pe[j];
            }
        }
    }
    cv::imwrite("./grad/" + name + ".png", tmp);
}

void saveNormalized(cv::Mat &data, const std::string &name) {
    double vmin, vmax;
    cv::minMaxIdx(data, &vmin, &vmax);
    if (vmin < 0) {
        vmax = std::max(vmax, -vmin);
        cv::Mat tmp = cv::abs(data);
        tmp *= 255.0 / vmax;
        tmp.convertTo(tmp, CV_8U);
        cv::imwrite("./grad/" + name + "_abs.png", tmp);
        data += vmax;
        data *= 127.5 / vmax;
    } else
        data *= 255.0 / vmax;
    data.convertTo(data, CV_8U);
    //std::cout << "write: " << "./grad/" + name + ".png" << std::endl;
    cv::imwrite("./grad/" + name + ".png", data);
}

void saveResults(const lsfm::FilterResults &results, const std::string &name, bool sqr = false, int border = 0) {
    for_each(results.begin(), results.end(), [&](const FilterResult &r) {
        cv::Mat tmp;
        if (r.second.data.type() != cv::DataType<FT>::type)
            r.second.data.convertTo(tmp, cv::DataType<FT>::type);
        else
            r.second.data.copyTo(tmp);

        if (r.first == "phase") {
            lsfm::FilterResults::const_iterator f = results.find("energy");
            if (f != results.end())
                savePhase(tmp, name + "_" + r.first, f->second.data);
            else
                saveDir(tmp, name + "_" + r.first);
            return;
        }
        if (r.first == "dir") {
            lsfm::FilterResults::const_iterator f = results.find("odd");
            if (f == results.end())
                f = results.find("mag");
            if (f != results.end())
                saveDir(tmp, name + "_" + r.first, f->second.data);
            else
                saveDir(tmp, name + "_" + r.first);
            return;
        }
        if (r.first == "mag" && sqr)
            cv::sqrt(tmp, tmp);

        if (border > 0) {
            tmp.colRange(0, border).setTo(0);
            tmp.colRange(tmp.cols - border, tmp.cols).setTo(0);
            tmp.rowRange(0, border).setTo(0);
            tmp.rowRange(tmp.rows - border, tmp.rows).setTo(0);
        }

        saveNormalized(tmp, name + "_" + r.first);
    });
}

void parseFolder(const fs::path &folder, std::vector<fs::path> &files) {
    fs::directory_iterator end_iter;
    for_each(fs::directory_iterator(folder), fs::directory_iterator(), [&files](const fs::path& file) {
        if (fs::is_regular_file(file))
        {
            std::string ext = file.extension().generic_string();
            boost::algorithm::to_lower(ext);
            if (ext == ".jpg" || ext == ".png") {
                files.push_back(file);
            }
        }
        if (fs::is_directory(file))
            parseFolder(file, files);
    });
}

void processPath(std::vector<Entry> &entries, const std::pair<fs::path, std::string> &path) {
    std::cout << "processing " << path.first << std::endl;
    std::vector<fs::path> files;
    parseFolder(path.first, files);

    std::for_each(files.begin(), files.end(), [&](const fs::path& file) {
        cv::Mat rgb = cv::imread(file.generic_string());
        if (rgb.empty())
        {
            cout << "Can not open " << file.generic_string() << endl;
            return;
        }
        std::cout << file << std::endl;
        cv::Mat src;
        cv::cvtColor(rgb, src, CV_BGR2GRAY);

        for_each(entries.begin(), entries.end(), [&](Entry &e) {
            saveResults(e.process(e.rgb() ? rgb : src), path.second + "/" + file.stem().generic_string() + "_" + e.name,e.sqr(),e.border());
        });
    });
}

int main(int argc, char** argv)
{
    std::vector<std::pair<fs::path, std::string>> sets;
    //sets.push_back(std::pair<fs::path, std::string>("../../images/noise", "noise"));
    sets.push_back(std::pair<fs::path, std::string>("../../images/Selection", "Selection"));
    //sets.push_back(std::pair<fs::path, std::string>("../../images/BSDS500", "BSDS500"));
    //sets.push_back(std::pair<fs::path, std::string>("../../images/MDB/MiddEval3-Q", "MDB-Q"));
    //sets.push_back(std::pair<fs::path, std::string>("../../images/MDB/MiddEval3-H", "MDB-H"));
    //sets.push_back(std::pair<fs::path, std::string>("../../images/MDB/MiddEval3-F", "MDB-F"));

    std::vector<Entry> filter;
    /*filter.push_back(Entry(new DerivativeGradient<uchar,short, FT, FT, RobertsDerivative>,"Roberts_(2x2)"));
    filter.push_back(Entry(new DerivativeGradient<uchar, short,FT, FT, PrewittDerivative>, "Prewitt_(3x3)"));
    filter.push_back(Entry(new DerivativeGradient<uchar, short, FT, FT, ScharrDerivative>, "Scharr_(3x3)"));

    filter.push_back(Entry(new DerivativeGradient<uchar, short,FT, FT, SobelDerivative>, "Sobel_(3x3)"));
    filter.push_back(Entry(new DerivativeGradient<uchar, short,FT, FT, SobelDerivative>({ NV("grad_kernel_size",5) }), "Sobel_(5x5)"));
    filter.push_back(Entry(new DerivativeGradient<uchar, short,FT, FT, SobelDerivative>({ NV("grad_kernel_size",7) }), "Sobel_(7x7)"));
    filter.push_back(Entry(new DerivativeGradient<uchar, short,FT, FT, SobelDerivative>({ NV("grad_kernel_size",9) }), "Sobel_(9x9)"));

    filter.push_back(Entry(new DerivativeGradient<uchar, FT, FT, FT, GaussianDerivative, Magnitude>({ NV("grad_kernel_size",3), NV("grad_range",1.5) }), "Gauss_(3x3)"));
    filter.push_back(Entry(new DerivativeGradient<uchar, FT, FT, FT, GaussianDerivative, Magnitude>({ NV("grad_kernel_size",5), NV("grad_range",2.3) }), "Gauss_(5x5)"));
    filter.push_back(Entry(new DerivativeGradient<uchar, FT, FT, FT, GaussianDerivative, Magnitude>({ NV("grad_kernel_size",7), NV("grad_range",3.0) }), "Gauss_(7x7)"));
    filter.push_back(Entry(new DerivativeGradient<uchar, FT, FT, FT, GaussianDerivative, Magnitude>({ NV("grad_kernel_size",9), NV("grad_range",3.5) }), "Gauss_(9x9)"));

    filter.push_back(Entry(new SusanGradient<short, int>(20), "Susan_(37)"));
    filter.push_back(Entry(new SusanGradient<short, int>(20,true), "Susan_(3x3)"));
    filter.push_back(Entry(new RCMGradient<uchar, 1, short, int>(3,1), "RMG_(3x3)", ENTRY_NO_3));
    filter.push_back(Entry(new RCMGradient<uchar, 1, short, int>(5, 3), "RMG_(5x5)", ENTRY_NO_5));
    filter.push_back(Entry(new RCMGradient<uchar, 3, short, int>(3, 1), "RCMG_(3x3)", ENTRY_NO_3 | ENTRY_SQR | ENTRY_RGB));

    filter.push_back(Entry(new LaplaceSimple<uchar, short>, "Laplace_(3x3)"));
    filter.push_back(Entry(new LaplaceCV<uchar, short>(5), "Laplace_Sobel_(5x5)"));
    filter.push_back(Entry(new LaplaceCV<uchar, short>(7), "Laplace_Sobel_(7x7)"));
    filter.push_back(Entry(new LaplaceCV<uchar, short>(9), "Laplace_Sobel_(9x9)"));*/

    /*filter.push_back(Entry(new LoG<uchar, FT>(3, 1.240080), "LoG_(3x3)"));
    filter.push_back(Entry(new LoG<uchar, FT>(5, 1.008030), "LoG_(5x5)"));
    filter.push_back(Entry(new LoG<uchar, FT>(7, 0.873228), "LoG_(7x7)"));
    filter.push_back(Entry(new LoG<uchar, FT>(9, 0.781859), "LoG_(9x9)"));*/

    /*filter.push_back(Entry(new QuadratureG2<uchar, FT>(3, 1.24008), "QF_StG_(3x3)"));
    filter.push_back(Entry(new QuadratureG2<uchar, FT>(5, 1.008),   "QF_StG_(5x5)"));
    filter.push_back(Entry(new QuadratureG2<uchar, FT>(7, 0.873226), "QF_StG_(7x7)"));
    filter.push_back(Entry(new QuadratureG2<uchar, FT>(9, 0.781854), "QF_StG_(9x9)"));*/

    /*filter.push_back(Entry(new QuadratureS<uchar, FT, FT>(1, 2, 3, 1.2), "SQF_Po_(3x3)"));
    filter.push_back(Entry(new QuadratureS<uchar, FT, FT>(1, 2, 5, 1.2), "SQF_Po_(5x5)"));
    filter.push_back(Entry(new QuadratureS<uchar, FT, FT>(1, 2, 7, 1.2), "SQF_Po_(7x7)"));*/
    filter.push_back(Entry(new QuadratureS<uchar, FT, FT>(1, 2, 9, 1.2), "SQF_Po_(9x9)"));

    /*filter.push_back(Entry(dynamic_cast<Quadrature<uchar, FT, FT, FT, FT>*>(new PCLSq<uchar, FT, FT>(1, 2, 3, 1.2)), "SQF_Po_(3x3)"));
    filter.push_back(Entry(dynamic_cast<Quadrature<uchar, FT, FT, FT, FT>*>(new PCLSq<uchar, FT, FT>(1, 2, 5, 1.2)), "SQF_Po_(5x5)"));
    filter.push_back(Entry(dynamic_cast<Quadrature<uchar, FT, FT, FT, FT>*>(new PCLSq<uchar, FT, FT>(1, 2, 7, 1.2)), "SQF_Po_(7x7)"));
    filter.push_back(Entry(dynamic_cast<Quadrature<uchar, FT, FT, FT, FT>*>(new PCLSq<uchar, FT, FT>(1, 2, 9, 1.2)), "SQF_Po_(9x9)"));*/

    //filter.push_back(Entry(new QuadratureSF<uchar, FT>(1, 2, 1.2), "SQFF_Po_12"));
    filter.push_back(Entry(dynamic_cast<Quadrature<uchar,FT,FT,FT, FT>*>(new PCLSqf<uchar, FT>(1, 2, 1.2)), "SQFF_Po_12"));
    filter.push_back(Entry(dynamic_cast<Quadrature<uchar, FT, FT, FT, FT>*>(new PCLSqf<uchar, FT>(1, 3, 2.5)), "SQFF_Po"));
    //filter.push_back(Entry(new QuadratureLGF<uchar, FT>(5, 0.55), "SQFF_Lg"));

    //filter.push_back(Entry(new PCLgf<uchar, FT>(4, 3,2.1,0.55), "PCF_Lg"));
    //filter.push_back(Entry(new PCMatlab<uchar>(4, 3, 2.1, 0.55), "PCF_Ml"));
    //filter.push_back(Entry(new PCSqf<uchar, FT>(1,3,2.5), "PCF_Po"));

    fs::create_directory("./grad");
    for_each(sets.begin(), sets.end(), [&](const std::pair<fs::path, std::string> &data) {
        fs::create_directory("./grad/" + data.second);
        processPath(filter, data);
    });

    return 0;
}

max_stars_repo_name: waterben/LineExtraction

max_issues_repo_name: waterben/LineExtraction

max_forks_repo_name: waterben/LineExtraction


text:
/*
    Copyright 2014
    Use, modification and distribution are subject to the Boost Software License,
    Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
    http://www.boost.org/LICENSE_1_0.txt).
*/

/*************************************************************************************************/

#ifndef BOOST_GIL_PREMULTIPLY_HPP
#define BOOST_GIL_PREMULTIPLY_HPP

#include <iostream>

#include <boost/gil/rgba.hpp>
#include <boost/mpl/remove.hpp>

namespace boost { namespace gil {

template <typename SrcP, typename DstP>
struct channel_premultiply {
	channel_premultiply (SrcP const & src, DstP & dst)
		: src_ (src), dst_ (dst)
	{}

	template <typename Channel>
	void operator () (Channel c) const {
		// @todo: need to do a “channel_convert” too, in case the channel types aren't the same?
		get_color (dst_, Channel()) = channel_multiply(get_color(src_,Channel()), alpha_or_max(src_));
	}
	SrcP const & src_;
	DstP & dst_;
};

namespace detail
{
	template <typename SrcP, typename DstP>
	void assign_alpha_if(mpl::true_, SrcP const &src, DstP &dst)
	{
	  get_color (dst,alpha_t()) = alpha_or_max (src);
	};

	template <typename SrcP, typename DstP>
	void assign_alpha_if(mpl::false_, SrcP const &src, DstP &dst)
	{
	  // nothing to do
	};
}

struct premultiply {
	template <typename SrcP, typename DstP>
	void operator()(const SrcP& src, DstP& dst) const {
		typedef typename color_space_type<SrcP>::type src_colour_space_t;
		typedef typename color_space_type<DstP>::type dst_colour_space_t;
		typedef typename mpl:: remove <src_colour_space_t, alpha_t>:: type src_colour_channels;

		typedef mpl::bool_<mpl::contains<dst_colour_space_t, alpha_t>::value> has_alpha_t;
		mpl:: for_each <src_colour_channels> ( channel_premultiply <SrcP, DstP> (src, dst) );
		detail::assign_alpha_if(has_alpha_t(), src, dst);
	}
};

template <typename SrcConstRefP,  // const reference to the source pixel
          typename DstP>          // Destination pixel value (models PixelValueConcept)
class premultiply_deref_fn {
public:
    typedef premultiply_deref_fn const_t;
    typedef DstP                value_type;
    typedef value_type          reference;      // read-only dereferencing
    typedef const value_type&   const_reference;
    typedef SrcConstRefP        argument_type;
    typedef reference           result_type;
    BOOST_STATIC_CONSTANT(bool, is_mutable=false);

    result_type operator()(argument_type srcP) const {
        result_type dstP;
        premultiply () (srcP,dstP);
        return dstP;
    }
};

template <typename SrcView, typename DstP>
struct premultiplied_view_type {
private:
    typedef typename SrcView::const_t::reference src_pix_ref;  // const reference to pixel in SrcView
    typedef premultiply_deref_fn<src_pix_ref, DstP> deref_t; // the dereference adaptor that performs color conversion
    typedef typename SrcView::template add_deref<deref_t> add_ref_t;
public:
    typedef typename add_ref_t::type type; // the color converted view type
    static type make(const SrcView& sv) { return add_ref_t::make(sv, deref_t()); }
};

template <typename DstP, typename View> inline
typename premultiplied_view_type<View,DstP>::type premultiply_view(const View& src) {
    return premultiplied_view_type<View,DstP>::make(src);
}

	}
}

#endif // BOOST_GIL_PREMULTIPLY_HPP

ext: hpp

max_forks_repo_name: ZeroInfinite/turicreate


text:
//
// Copyright (c) 2010 steve.bush@neosys.com
//
#include <algorithm>
#include <cassert>
#define INSIDE_MVHANDLES_CPP  // global obj in "mvhandles.h"
#include "mvhandles.h"

#include <boost/thread/mutex.hpp>
boost::mutex mvhandles_mutex;

#define HANDLES_CACHE_SIZE 3

namespace exodus {

MvHandleEntry::MvHandleEntry()
	: deleter((DELETER_AND_DESTROYER)0), handle(0) {}

MvHandlesCache::MvHandlesCache()
	: conntbl(HANDLES_CACHE_SIZE) {}

int MvHandlesCache::add_handle(CACHED_HANDLE handle_to_cache, DELETER_AND_DESTROYER del, std::string name) {
	assert(del);
	boost::mutex::scoped_lock lock(mvhandles_mutex);

	int ix;
	for (ix = 0; ix < (int)conntbl.size(); ix++)
		if (conntbl[ix].deleter == HANDLE_ENTRY_FREE)
			break;

	if (ix == (int)conntbl.size())
		conntbl.resize(ix * 2);	 // double the table size

	conntbl[ix].deleter = del;
	conntbl[ix].handle = handle_to_cache;
	conntbl[ix].extra = name;
	return ix;
}

CACHED_HANDLE MvHandlesCache::get_handle(int index, std::string name) {
	boost::mutex::scoped_lock lock(mvhandles_mutex);
	return (conntbl[index].deleter == HANDLE_ENTRY_FREE) || (conntbl[index].extra != name)
			   ? BAD_CACHED_HANDLE
			   : conntbl[index].handle;
}

void MvHandlesCache::del_handle(int index) {
	boost::mutex::scoped_lock lock(mvhandles_mutex);
	assert(conntbl[index].deleter);
	if (conntbl[index].deleter) {
		conntbl[index].deleter(conntbl[index].handle);
		//conntbl[index].handle;
	}
	conntbl[index].deleter = 0;	 //	HANDLE_ENTRY_FREE
}

MvHandlesCache::~MvHandlesCache() {

	// crashes on linux and multithreaded destructor cant exist so  dont lock
	// boost::mutex::scoped_lock lock(mvhandles_mutex);

	int ix;
	for (ix = 0; ix < (int)conntbl.size(); ix++)
		if (conntbl[ix].deleter != HANDLE_ENTRY_FREE) {
			// do not call 'del_handle(ix)' here because of deadlock
			conntbl[ix].deleter(conntbl[ix].handle);
			conntbl[ix].deleter = 0;  //	HANDLE_ENTRY_FREE
		}
}

}  // namespace exodus

ext: cpp

max_stars_repo_name: exodusdb/exodusdb

max_issues_repo_name: exodusdb/exodusdb

max_forks_repo_name: exodusdb/exodusdb


text:
#include <futurehead/lib/config.hpp>

#include <boost/filesystem/path.hpp>
#include <boost/lexical_cast.hpp>

#include <valgrind/valgrind.h>

namespace futurehead
{
	work_thresholds const network_constants::publish_full(
		//0xffffffc000000000,
		//0xfffffff800000000, // 8x higher than epoch_1
		//0xfffffe0000000000 // 8x lower than epoch_1
		//TO-CHANGE
		0xfffff00000000000, // 64x lower
		0xfffff00000000000, // 64x lower
		0xfffff00000000000	// 64x lower
	);

	work_thresholds const network_constants::publish_beta(
		0xfffff00000000000, // 64x lower than publish_full.epoch_1
		0xfffff80000000000, // 2x higher than epoch_1
		0xffffe00000000000	// 2x lower than epoch_1
	);

	work_thresholds const network_constants::publish_test(
		0xfe00000000000000, // Very low for tests
		0xffc0000000000000, // 8x higher than epoch_1
		0xf000000000000000	// 8x lower than epoch_1
	);

	const char *network_constants::active_network_err_msg = "Invalid network. Valid values are live, beta and test.";

	uint8_t get_major_node_version()
	{
		return boost::numeric_cast<uint8_t>(boost::lexical_cast<int>(FUTUREHEAD_MAJOR_VERSION_STRING));
	}
	uint8_t get_minor_node_version()
	{
		return boost::numeric_cast<uint8_t>(boost::lexical_cast<int>(FUTUREHEAD_MINOR_VERSION_STRING));
	}
	uint8_t get_patch_node_version()
	{
		return boost::numeric_cast<uint8_t>(boost::lexical_cast<int>(FUTUREHEAD_PATCH_VERSION_STRING));
	}
	uint8_t get_pre_release_node_version()
	{
		return boost::numeric_cast<uint8_t>(boost::lexical_cast<int>(FUTUREHEAD_PRE_RELEASE_VERSION_STRING));
	}

	void force_futurehead_test_network()
	{
		futurehead::network_constants::set_active_network(futurehead::futurehead_networks::futurehead_test_network);
	}

	bool running_within_valgrind()
	{
		return (RUNNING_ON_VALGRIND > 0);
	}

	std::string get_config_path(boost::filesystem::path const &data_path)
	{
		return (data_path / "config.json").string();
	}

	std::string get_rpc_config_path(boost::filesystem::path const &data_path)
	{
		return (data_path / "rpc_config.json").string();
	}

	std::string get_node_toml_config_path(boost::filesystem::path const &data_path)
	{
		return (data_path / "config-node.toml").string();
	}

	std::string get_rpc_toml_config_path(boost::filesystem::path const &data_path)
	{
		return (data_path / "config-rpc.toml").string();
	}

	std::string get_qtwallet_toml_config_path(boost::filesystem::path const &data_path)
	{
		return (data_path / "config-qtwallet.toml").string();
	}

	std::string get_access_toml_config_path(boost::filesystem::path const &data_path)
	{
		return (data_path / "config-access.toml").string();
	}

	std::string get_tls_toml_config_path(boost::filesystem::path const &data_path)
	{
		return (data_path / "config-tls.toml").string();
	}
} // namespace futurehead

max_stars_repo_name: futureheadgroup/futurehead-node

max_issues_repo_name: FutureHeadCoin/futurehead-node

max_forks_repo_name: FutureHeadCoin/futurehead-node


text:
// Copyright Yamaha 2021
// MIT License
// https://github.com/yamaha-bps/cbr_ros/blob/master/LICENSE

#include <boost/hana/define_struct.hpp>
#include <gtest/gtest.h>
#include <rclcpp/node.hpp>
#include <rclcpp/parameter_value.hpp>

#include <array>
#include <string>
#include <vector>

#include "cbr_ros/parameters.hpp"

struct MySubParams
{
  int i1;
  uint32_t i2;

  bool operator==(const MySubParams & o) const {return i1 == o.i1 && i2 == o.i2;}
};

BOOST_HANA_ADAPT_STRUCT(MySubParams, i1, i2);

struct MyValue
{
  int i1, i2;

  bool operator==(const MyValue & o) const {return i1 == o.i1 && i2 == o.i2;}
};

BOOST_HANA_ADAPT_STRUCT(MyValue, i1, i2);

struct MyParams
{
  int i;
  double d;
  float f;
  bool b1;
  bool b2;
  std::string s;

  std::vector<double> dvec;
  std::vector<std::string> svec;
  std::vector<bool> bvec;
  std::vector<uint8_t> cvec;
  std::vector<int64_t> ivec;
  std::vector<int> i32vec;

  std::array<int, 3> iarr;
  std::array<MyValue, 2> mvarr;
  std::tuple<double, int> tuple;
  MySubParams sub;

  bool operator==(const MyParams & o) const
  {
    return i == o.i && d == o.d && f == o.f && b1 == o.b1 && b2 == o.b2 && dvec == o.dvec &&
           s == o.s && svec == o.svec && bvec == o.bvec && cvec == o.cvec && ivec == o.ivec &&
           i32vec == o.i32vec && iarr == o.iarr && mvarr == o.mvarr && tuple == o.tuple &&
           sub == o.sub;
  }
};

BOOST_HANA_ADAPT_STRUCT(
  MyParams, i, d, f, b1, b2, s, dvec, svec, bvec, cvec, ivec, i32vec, iarr, mvarr, tuple, sub);

inline MyParams prm_example{
  /* .i = */ 2,
  /* .d = */ 5.55,
  /* .f = */ -3.14f,
  /* .b1 = */ false,
  /* .b2 = */ true,
  /* .s = */ "hello",
  /* .dvec = */ {1, 2, 3, 5},
  /* .svec = */ {"hej", "stringvec"},
  /* .bvec = */ {false, true, false, false},
  /* .cvec = */ {uint8_t{0}, uint8_t{26}, uint8_t{101}},
  /* .ivec = */ {1237891, -1241, 123},
  /* .i32vec = */ {1231, 1241, -123},
  /* .iarr = */ {15, 20, -20},
  /* .mvarr = */
  {
    MyValue{ /* .i1 = */ 5, /* .i2 = */ 10},
    MyValue{ /* .i1 = */ 25, /* .i2 = */ 35},
  },
  /* .tpl = */ {1, 2},
  /* .sub = */ MySubParams{ /* .i1 = */ 1, /* .i2 = */ 2},
};

TEST(Prm, Static)
{
  static_assert(std::is_same_v<cbr::detail::ros_type<double>::type, double>);
  static_assert(std::is_same_v<cbr::detail::ros_type<float>::type, double>);
  static_assert(std::is_same_v<cbr::detail::ros_type<bool>::type, bool>);
  static_assert(std::is_same_v<cbr::detail::ros_type<int>::type, int64_t>);
  static_assert(std::is_same_v<cbr::detail::ros_type<std::string>::type, std::string>);
  static_assert(
    std::is_same_v<cbr::detail::ros_type<std::__cxx11::basic_string<char>>::type, std::string>);
}

TEST(Prm, Update)
{
  MyParams prm = prm_example;

  auto r = cbr::updateParam(rclcpp::Parameter("namespace.i", 4), "namespace", prm);
  ASSERT_TRUE(r);
  ASSERT_EQ(prm.i, 4);

  r = cbr::updateParam(rclcpp::Parameter("namespace.does_not_exist", 4), "namespace", prm);
  ASSERT_FALSE(r);

  r = cbr::updateParam(rclcpp::Parameter("namespace.d", 10.55), "namespace", prm);
  ASSERT_TRUE(r);
  ASSERT_EQ(prm.d, 10.55);

  r = cbr::updateParam(
    rclcpp::Parameter("namespace.dvec", std::vector<double>{-10, -20}), "namespace", prm);
  ASSERT_TRUE(r);
  ASSERT_EQ(prm.dvec.size(), 2);
  ASSERT_EQ(prm.dvec[0], -10);
  ASSERT_EQ(prm.dvec[1], -20);

  r = cbr::updateParam(
    rclcpp::Parameter("namespace.svec", std::vector<std::string>{"new", "par", "ams"}),
    "namespace",
    prm);
  ASSERT_TRUE(r);
  ASSERT_EQ(prm.svec.size(), 3);
  ASSERT_EQ(prm.svec[0], "new");
  ASSERT_EQ(prm.svec[1], "par");
  ASSERT_EQ(prm.svec[2], "ams");

  r = cbr::updateParam(
    rclcpp::Parameter("namespace.i32vec", std::vector<int64_t>{199, 299}), "namespace", prm);
  ASSERT_EQ(prm.i32vec.size(), 2);
  ASSERT_TRUE(r);
  ASSERT_EQ(prm.i32vec[0], 199);
  ASSERT_EQ(prm.i32vec[1], 299);

  r = cbr::updateParam(rclcpp::Parameter("namespace.mvarr_0.i1", 55), "namespace", prm);
  ASSERT_TRUE(r);
  r = cbr::updateParam(rclcpp::Parameter("namespace.mvarr_1.i2", -55), "namespace", prm);
  ASSERT_TRUE(r);
  ASSERT_EQ(prm.mvarr[0].i1, 55);
  ASSERT_EQ(prm.mvarr[1].i2, -55);

  r = cbr::updateParam(rclcpp::Parameter("namespace.tuple_0", 11.5), "namespace", prm);
  ASSERT_TRUE(r);
  r = cbr::updateParam(rclcpp::Parameter("namespace.tuple_1", 22), "namespace", prm);
  ASSERT_TRUE(r);
  r = cbr::updateParam(rclcpp::Parameter("namespace.tuple_2", 33.), "namespace", prm);
  ASSERT_FALSE(r);
  ASSERT_EQ(std::get<0>(prm.tuple), 11.5);
  ASSERT_EQ(std::get<1>(prm.tuple), 22);
}

TEST(Prm, RosBasic)
{
  rclcpp::init(0, nullptr);
  auto node = std::make_shared<rclcpp::Node>("asdf");

  // declare
  cbr::declareParams(*node, "namespace", prm_example);

  ASSERT_TRUE(node->has_parameter("namespace.dvec"));
  ASSERT_TRUE(node->has_parameter("namespace.i"));
  ASSERT_TRUE(node->has_parameter("namespace.d"));
  ASSERT_TRUE(node->has_parameter("namespace.sub.i1"));
  ASSERT_TRUE(node->has_parameter("namespace.sub.i2"));

  // get
  auto prm_copy = cbr::getParams<MyParams>(*node, "namespace");
  ASSERT_EQ(prm_example, prm_copy);

  // set
  prm_copy.i = 3;
  prm_copy.d = 7.5;
  cbr::setParams(*node, "namespace", prm_copy);
  ASSERT_EQ(node->get_parameter("namespace.i").as_int(), 3.);
  ASSERT_EQ(node->get_parameter("namespace.d").as_double(), 7.5);

  rclcpp::shutdown();
}

struct SubValueT
{
  double subd;
  uint32_t i;
  std::string s;

  bool operator==(const SubValueT & o) const {return subd == o.subd && s == o.s;}
};

struct ValueT
{
  int64_t i1, i2;
  float f;
  double d;

  SubValueT sub;

  bool operator==(const ValueT & o) const
  {
    return i1 == o.i1 && i2 == o.i2 && f == o.f && d == o.d && sub == o.sub;
  }
};

struct MasterValueT
{
  std::vector<ValueT> vec_of_tpl;
  int i0;

  bool operator==(const MasterValueT & o) const {return vec_of_tpl == o.vec_of_tpl && i0 == o.i0;}
};

BOOST_HANA_ADAPT_STRUCT(SubValueT, subd, i, s);
BOOST_HANA_ADAPT_STRUCT(ValueT, i1, i2, f, d, sub);
BOOST_HANA_ADAPT_STRUCT(MasterValueT, vec_of_tpl, i0);

TEST(Prm, UpdateVectorOfStructs)
{
  std::vector<ValueT> v;
  v.push_back(ValueT{1, 2, 0.1f, 3.12, SubValueT{-1, 100, "str1"}});
  v.push_back(ValueT{3, 4, 0.2f, 6.12, SubValueT{-2, 200, "str2"}});
  v.push_back(ValueT{5, 6, 0.3f, 9.12, SubValueT{-3, 300, "str3"}});
  MasterValueT mv{v, 5};

  auto r = cbr::updateParam(
    rclcpp::Parameter("namespace.vec_of_tpl.i3", std::vector<int>{10, 20, 30}), "namespace", mv);
  ASSERT_FALSE(r);

  r = cbr::updateParam(
    rclcpp::Parameter("namespace.vec_of_tpl.i1", std::vector<int>{10, 20, 30}), "namespace", mv);
  ASSERT_TRUE(r);
  ASSERT_EQ(mv.vec_of_tpl.size(), 3);
  ASSERT_EQ(mv.vec_of_tpl[0].i1, 10);
  ASSERT_EQ(mv.vec_of_tpl[1].i1, 20);
  ASSERT_EQ(mv.vec_of_tpl[2].i1, 30);
  ASSERT_EQ(mv.vec_of_tpl[0].i2, 2);
  ASSERT_EQ(mv.vec_of_tpl[1].i2, 4);
  ASSERT_EQ(mv.vec_of_tpl[2].i2, 6);

  r = cbr::updateParam(
    rclcpp::Parameter("namespace.vec_of_tpl.i1", std::vector<int>{40, 50}), "namespace", mv);
  ASSERT_TRUE(r);
  ASSERT_EQ(mv.vec_of_tpl.size(), 2);
  ASSERT_EQ(mv.vec_of_tpl[0].i1, 40);
  ASSERT_EQ(mv.vec_of_tpl[1].i1, 50);
  ASSERT_EQ(mv.vec_of_tpl[0].i2, 2);
  ASSERT_EQ(mv.vec_of_tpl[1].i2, 4);

  // reset
  mv = MasterValueT{v, 5};

  r = cbr::updateParam(
    rclcpp::Parameter(
      "namespace.vec_of_tpl.sub.s", std::vector<std::string>{"new", "par",
        "ams"}), "namespace", mv);
  ASSERT_TRUE(r);
  ASSERT_EQ(mv.vec_of_tpl.size(), 3);
  ASSERT_EQ(mv.vec_of_tpl[0].sub.s, "new");
  ASSERT_EQ(mv.vec_of_tpl[1].sub.s, "par");
  ASSERT_EQ(mv.vec_of_tpl[2].sub.s, "ams");
}

TEST(Prm, RosVectorOfStructs)
{
  std::vector<ValueT> v;
  v.push_back(ValueT{1, 2, 0.1f, 3.12, SubValueT{-1, 100, "str1"}});
  v.push_back(ValueT{3, 4, 0.2f, 6.12, SubValueT{-2, 200, "str2"}});
  v.push_back(ValueT{5, 6, 0.3f, 9.12, SubValueT{-3, 300, "str3"}});

  MasterValueT mv{v, 5};

  rclcpp::init(0, nullptr);
  auto node = std::make_shared<rclcpp::Node>("node");
  cbr::declareParams(*node, "namespace", mv);

  auto mv_copy = cbr::getParams<MasterValueT>(*node, "namespace");
  ASSERT_EQ(mv, mv_copy);

  mv.vec_of_tpl[2].i1 = 12345;

  cbr::setParams(*node, "namespace", mv);

  auto mv_copy2 = cbr::getParams<MasterValueT>(*node, "namespace");
  ASSERT_EQ(mv, mv_copy2);

  rclcpp::shutdown();
}

TEST(Prm, RosVectorOfStructsInit)
{
  std::vector<ValueT> v;
  v.push_back(ValueT{1, 2, 0.1f, 3.12, SubValueT{-1, 100, "str1"}});
  v.push_back(ValueT{3, 4, 0.2f, 6.12, SubValueT{-2, 200, "str2"}});
  v.push_back(ValueT{5, 6, 0.3f, 9.12, SubValueT{-3, 300, "str3"}});

  MasterValueT mv{v, 5};

  rclcpp::init(0, nullptr);
  auto node = std::make_shared<rclcpp::Node>("node");
  cbr::initParams(*node, "namespace", mv);

  auto prms = node->list_parameters(std::vector<std::string>{}, 10);

  auto f1 = std::find(prms.names.begin(), prms.names.end(), "namespace.i0") != prms.names.end();
  ASSERT_TRUE(f1);
  auto f2 =
    std::find(prms.names.begin(), prms.names.end(), "namespace.vec_of_tpl.i1") != prms.names.end();
  ASSERT_TRUE(f2);
  auto f3 =
    std::find(prms.names.begin(), prms.names.end(), "namespace.vec_of_tpl.i2") != prms.names.end();
  ASSERT_TRUE(f3);
  auto f4 =
    std::find(prms.names.begin(), prms.names.end(), "namespace.vec_of_tpl.f") != prms.names.end();
  ASSERT_TRUE(f4);
  auto f5 =
    std::find(prms.names.begin(), prms.names.end(), "namespace.vec_of_tpl.d") != prms.names.end();
  ASSERT_TRUE(f5);
  auto f6 = std::find(prms.names.begin(), prms.names.end(), "namespace.vec_of_tpl.sub.i") !=
    prms.names.end();
  ASSERT_TRUE(f6);
  auto f7 = std::find(prms.names.begin(), prms.names.end(), "namespace.vec_of_tpl.sub.subd") !=
    prms.names.end();
  ASSERT_TRUE(f7);
  auto f8 = std::find(prms.names.begin(), prms.names.end(), "namespace.vec_of_tpl.sub.s") !=
    prms.names.end();
  ASSERT_TRUE(f8);

  ASSERT_GE(prms.names.size(), 9u);  // some standard params are always there..

  /* for (auto p : prms.names) {
    std::cout << p << std::endl;
    std::cout << node->get_parameter(p).value_to_string() << std::endl;
  } */

  rclcpp::shutdown();
}

struct MyParameters
{
  double d{1};
  int i{2};
  std::string s{"3"};
};

TEST(Prm, Snippets1)
{
  rclcpp::init(0, nullptr);
  auto node = std::make_shared<rclcpp::Node>("node");

  MyParameters prm;

  node->declare_parameter<double>("myprm.d", prm.d);
  node->declare_parameter<int>("myprm.i", prm.i);
  node->declare_parameter<std::string>("myprm.s", prm.s);

  prm.d = node->get_parameter("myprm.d").as_double();
  prm.i = static_cast<int>(node->get_parameter("myprm.i").as_int());
  prm.s = node->get_parameter("myprm.s").as_string();

  rclcpp::shutdown();
}

BOOST_HANA_ADAPT_STRUCT(MyParameters, d, i, s);  // option: register just a subset of the members

TEST(Prm, Snippets2)
{
  rclcpp::init(0, nullptr);
  auto node = std::make_shared<rclcpp::Node>("node");

  MyParameters prm;
  cbr::declareParams(*node, "myprm", prm);
  cbr::getParams(*node, "myprm", prm);

  // cbr::initParams(*node, "myprm", prm);

  rclcpp::shutdown();
}


text:
//  Copyright (c) 2005-2007 Andre Merzky (andre@merzky.net)
//
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  job LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef SAGA_IMPL_ENGINE_OBJECT_HPP
#define SAGA_IMPL_ENGINE_OBJECT_HPP

// include boost helper
#include <boost/noncopyable.hpp>
#include <boost/thread.hpp>

// include config
#include <saga/impl/config.hpp>

// need saga::uuid
#include <saga/saga/uuid.hpp>
#include <saga/saga/object.hpp>

///////////////////////////////////////////////////////////////////////////////
namespace saga { namespace impl {

  /////////////////////////////////////////////////////////////////////////////
  class object
  :  private boost::noncopyable,
     public TR1::enable_shared_from_this <object>
  {
    public:
      typedef boost::recursive_mutex mutex_type;
      mutable mutex_type mtx_;

    private:
      // store uuid - no recursion here, as uuid is not a saga::object,
      // as it is not part of the spec.  It gets created here, and is THE uuid
      // for the saga object, and the proxy.
      saga::uuid uuid_;

      // store the object type, we need to store this in the implementation
      // part to be able to reconstruct a saga::object from the impl only
      saga::object::type type_;

      // store the uuid of the last adaptor successfully executing a CPI
      // function for this instance
      saga::uuid last_known_good_;

    public:
      saga::uuid get_last_known_good() const { return last_known_good_; }
      void set_last_known_good(saga::uuid u) { last_known_good_ = u; }

    public:
      SAGA_EXPORT object (saga::object::type type);
      SAGA_EXPORT virtual ~object (void) {}

      SAGA_EXPORT virtual saga::session& get_session();
      SAGA_EXPORT virtual saga::session const& get_session() const;

      SAGA_EXPORT virtual saga::uuid get_uuid() const;

      SAGA_EXPORT void set_uuid(saga::uuid const& id);
      SAGA_EXPORT void set_type(saga::object::type t);

      SAGA_EXPORT virtual saga::object::type get_cpitype() const;
      SAGA_EXPORT virtual saga::object  clone() const;
      SAGA_EXPORT virtual bool is_equal(saga::impl::object *impl) const;

      // initialize implementation object and newly attached CPI object
      // this needs to be overloaded in the implementation object
      SAGA_EXPORT virtual void init();

      // get_type returns the type of this object
      SAGA_EXPORT virtual saga::object::type get_type() const;

      // get_attributes returns the internal implementation of the
      // impl::attributes interface
      SAGA_EXPORT virtual saga::impl::attribute* get_attributes();
      SAGA_EXPORT virtual saga::impl::attribute const* get_attributes() const;

      // get_monitorable returns the internal implementation of the
      // impl::monitorable interface
      SAGA_EXPORT virtual saga::impl::monitorable* get_monitorable();
      SAGA_EXPORT virtual saga::impl::monitorable const* get_monitorable() const;

      // get_steerable returns the internal implementation of the
      // impl::steerable interface
      SAGA_EXPORT virtual saga::impl::steerable* get_steerable();
      SAGA_EXPORT virtual saga::impl::steerable const* get_steerable() const;

      // get_task_interface returns the internal implementation of the
      // impl::task_interface interface
      SAGA_EXPORT virtual saga::impl::task_interface* get_task_interface();
      SAGA_EXPORT virtual saga::impl::task_interface const* get_task_interface() const;

      // get_permissions returns the internal implementation of the
      // impl::permissions interface
      SAGA_EXPORT virtual saga::impl::permissions* get_permissions();
      SAGA_EXPORT virtual saga::impl::permissions const* get_permissions() const;

  }; // class object

  ///////////////////////////////////////////////////////////////////////////////
}}  // namespace saga::impl

#endif // SAGA_IMPL_ENGINE_OBJECT_HPP

max_stars_repo_name: saga-project/saga-cpp

max_issues_repo_name: saga-project/saga-cpp

max_forks_repo_name: saga-project/saga-cpp


text:
//
// Created by Christoph Kummer on 26.02.19.
//

#include <WhiteBoxTableGenerator.h>
#include <iostream>
#include <vector>

#include <NTL/GF2X.h>
#include <NTL/vec_GF2.h>

#include <RandomPermutation.h>

namespace WhiteBox {
  WhiteBoxTableGenerator::WhiteBoxTableGenerator(
      std::array<uint8_t, AES_KEY_LENGTH_BYTES> aes_key,
      bool use_internal_encoding, bool use_mixing_bijections)
      : aesKey_(aes_key), usesMixingBijections_(use_mixing_bijections) {
    // Calculate round keys
    expandedAesKey_ = aes_key_schedule(aesKey_);

    // Encryption
    // Calculate T-Boxes and Tyi Tables
    TBoxes intermediateTBoxes = calculateTBoxes();
    calculateTyiTables(intermediateTBoxes);
    calculateXorTables(&xorTables_);

    // Decryption
    intermediateTBoxes = calculateTBoxesDecryption();
    calculateTyiTablesDecryption(intermediateTBoxes);
    calculateXorTables(&xorTablesDecryption_);

    if (use_mixing_bijections) {
      calculateMixingBijections();
    }

    if (use_internal_encoding) {
      if (use_mixing_bijections) {
        calculateInternalEncodingsWithMixingBijections();
      } else {
        calculateInternalEncodings();
      }
    }
  }

  TBoxes WhiteBoxTableGenerator::calculateTBoxes() {
    // Calculate T-Boxes for each round
    TBoxes tBoxes{};
    for (size_t i = 1; i < NUM_ROUNDS_AES_128; ++i) {
      State current_round_key;

      // Copy round key to current state
      std::copy(expandedAesKey_.begin() + AES_KEY_LENGTH_BYTES * (i - 1),
                expandedAesKey_.begin() + AES_KEY_LENGTH_BYTES * (i - 1) +
                AES_KEY_LENGTH_BYTES,
                current_round_key.begin());
      // Apply shift-rows to state
      current_round_key = shift_rows(current_round_key);

      // Create the 16 T-Boxes for this round
      for (size_t j = 0; j < AES_KEY_LENGTH_BYTES; ++j) {
        for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
          tBoxes[i - 1][j][x] =
              apply_AES_SBox(static_cast<uint8_t>(x ^ current_round_key[j]));
        }
      }
    }

    // The last round has special rules
    State round_key_9{};
    State round_key_10{};

    // Copy round keys 9 and 10
    std::copy(
        expandedAesKey_.begin() + AES_KEY_LENGTH_BYTES * 9,
        expandedAesKey_.begin() + AES_KEY_LENGTH_BYTES * 9 + AES_KEY_LENGTH_BYTES,
        round_key_9.begin());
    std::copy(expandedAesKey_.begin() + AES_KEY_LENGTH_BYTES * 10,
              expandedAesKey_.begin() + AES_KEY_LENGTH_BYTES * 10 +
              AES_KEY_LENGTH_BYTES,
              round_key_10.begin());

    // Only round key 9 gets shifted in this round
    State shifted_round_key_9 = shift_rows(round_key_9);
    for (size_t j = 0; j < AES_KEY_LENGTH_BYTES; ++j) {
      for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
        // These T-Boxes are inherent to the resultant algorithm, therefore
        // they must be saved separately
        finalRoundTBoxes_[j][x] =
            apply_AES_SBox(static_cast<uint8_t>(x ^ shifted_round_key_9[j])) ^
            round_key_10[j];
      }
    }

    return tBoxes;
  }

  TBoxes WhiteBoxTableGenerator::calculateTBoxesDecryption() {
    // We start with the last round in decryption
    State round_key_9{};
    State round_key_10{};

    // Copy round keys 9 and 10
    std::copy(
        expandedAesKey_.begin() + AES_KEY_LENGTH_BYTES * 9,
        expandedAesKey_.begin() + AES_KEY_LENGTH_BYTES * 9 + AES_KEY_LENGTH_BYTES,
        round_key_9.begin());
    std::copy(expandedAesKey_.begin() + AES_KEY_LENGTH_BYTES * 10,
              expandedAesKey_.begin() + AES_KEY_LENGTH_BYTES * 10 +
              AES_KEY_LENGTH_BYTES,
              round_key_10.begin());

    // Calculate T-Boxes for each round
    TBoxes tBoxes{};
    // Only round key 9 gets shifted in this round
    State shifted_round_key_10 = inverse_shift_rows(round_key_10);

    for (size_t j = 0; j < AES_KEY_LENGTH_BYTES; ++j) {
      for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
        tBoxes[0][j][x] = apply_AES_inverse_SBox(
            static_cast<uint8_t>(x ^ shifted_round_key_10[j])) ^
                          round_key_9[j];
      }
    }

    for (size_t i = 8; i >= 1; --i) {
      State current_round_key;

      // Copy round key to current state
      std::copy(expandedAesKey_.begin() + AES_KEY_LENGTH_BYTES * i,
                expandedAesKey_.begin() + AES_KEY_LENGTH_BYTES * i +
                AES_KEY_LENGTH_BYTES,
                current_round_key.begin());

      // Create the 16 T-Boxes for this round
      for (size_t j = 0; j < AES_KEY_LENGTH_BYTES; ++j) {
        for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
          tBoxes[8 - i + 1][j][x] =
              apply_AES_inverse_SBox(static_cast<uint8_t>(x)) ^
              current_round_key[j];
        }
      }
    }

    // Generate the T-Boxes for the last round
    State round_key_0{};
    std::copy(expandedAesKey_.begin(),
              expandedAesKey_.begin() + AES_KEY_LENGTH_BYTES,
              round_key_0.begin());
    for (size_t j = 0; j < AES_KEY_LENGTH_BYTES; ++j) {
      for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
        finalRoundTBoxesDecryption_[j][x] =
            apply_AES_inverse_SBox(static_cast<uint8_t>(x)) ^ round_key_0[j];
      }
    }

    return tBoxes;
  }

  void WhiteBoxTableGenerator::calculateMixingBijections() {
    std::vector<MixingBijection<uint8_t>> bijections_8;
    std::vector<MixingBijection<uint8_t>> bijections_8_dec;
    std::vector<MixingBijection<uint32_t>> bijections_32;
    std::vector<MixingBijection<uint32_t>> bijections_32_dec;
    std::vector<MixingBijection<uint32_t>> bijections_8_concat;
    std::vector<MixingBijection<uint32_t>> bijections_8_concat_dec;

    calculateXorTables(&mixingXorTables_);
    calculateXorTables(&mixingXorTablesDecryption_);

    for (uint32_t i = 0; i < 9; ++i) {
      bijections_32.clear();
      bijections_32_dec.clear();
      for (uint32_t j = 0; j < 4; ++j) {
        bijections_32.emplace_back(rng);
        bijections_32_dec.emplace_back(rng);
      }

      mixTyiTables(i, bijections_8, bijections_32, i != 0);
      mixTyiTablesDecryption(i, bijections_8_dec, bijections_32_dec, i != 0);

      bijections_8.clear();
      bijections_8_dec.clear();
      for (uint32_t j = 0; j < 16; ++j) {
        bijections_8.emplace_back(rng);
        bijections_8_dec.emplace_back(rng);
      }
      bijections_8_concat.clear();
      bijections_8_concat_dec.clear();
      for (uint32_t j = 0; j < 16; j += 4) {
        MixingBijection<uint32_t> mb_concat =
            concatenateBijections(bijections_8[j + 3], bijections_8[j + 2],
                                  bijections_8[j + 1], bijections_8[j]);
        MixingBijection<uint32_t> mb_concat_dec = concatenateBijections(
            bijections_8_dec[j + 3], bijections_8_dec[j + 2],
            bijections_8_dec[j + 1], bijections_8_dec[j]);
        bijections_8_concat.push_back(mb_concat);
        bijections_8_concat_dec.push_back(mb_concat_dec);
      }

      calculateMixingTables(&mixingTables_, i, bijections_32, bijections_8_concat,
                            true);
      calculateMixingTables(&mixingTablesDecryption_, i, bijections_32_dec,
                            bijections_8_concat_dec, true);
    }

    mixFinalRoundTBoxes(bijections_8);
    mixFinalRoundTBoxesDecryption(bijections_8_dec);
  }

  void WhiteBoxTableGenerator::calculateMixingTables(
      MixingTables *mixing_tables, size_t round,
      const std::vector<MixingBijection<uint32_t>> &bijections_32,
      const std::vector<MixingBijection<uint32_t>> &bijections_8_concat,
      bool use_output_mixing_bijections) const {
    if (mixing_tables == nullptr) return;

    for (size_t i = 0; i < AES_KEY_LENGTH_BYTES; ++i) {
      for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
        NTL::vec_GF2 v;
        v.SetLength(32);

        for (size_t j = 0; j < 32; ++j) {
          v.put(j, 0);
        }

        if (i % 4 == 3) {
          for (size_t k = 0; k < 8; ++k) {
            auto zero_at_pos = static_cast<uint32_t>((x & (1 << k)) != 0);
            v.put(k, zero_at_pos);
          }
        } else if (i % 4 == 2) {
          for (size_t k = 8; k < 16; ++k) {
            auto zero_at_pos = static_cast<uint32_t>((x & (1 << (k - 8))) != 0);
            v.put(k, zero_at_pos);
          }
        } else if (i % 4 == 1) {
          for (size_t k = 16; k < 24; ++k) {
            auto zero_at_pos = static_cast<uint32_t>((x & (1 << (k - 16))) != 0);
            v.put(k, zero_at_pos);
          }
        } else if (i % 4 == 0) {
          for (size_t k = 24; k < 32; ++k) {
            auto zero_at_pos = static_cast<uint32_t>((x & (1 << (k - 24))) != 0);
            v.put(k, zero_at_pos);
          }
        }

        uint32_t transformed = bijections_32[i / 4].applyInverseTransformation(v);
        if (use_output_mixing_bijections) {
          transformed =
              bijections_8_concat[i / 4].applyTransformation(transformed);
        }
        (*mixing_tables)[round][i][x] = transformed;
      }
    }
  }

  void WhiteBoxTableGenerator::mixTyiTables(
      size_t round, const std::vector<MixingBijection<uint8_t>> &bijections_8,
      const std::vector<MixingBijection<uint32_t>> &bijections_32,
      bool use_input_mixing_bijection) {
    for (uint32_t i = 0; i < AES_KEY_LENGTH_BYTES; ++i) {
      TyiTable look_up_copy = tyiTables_[round][i];
      uint32_t shifted_index = get_shifted_index(i);

      for (uint32_t j = 0; j <= std::numeric_limits<uint8_t>::max(); ++j) {
        auto transformed_val = static_cast<uint8_t>(j);
        if (use_input_mixing_bijection) {
          transformed_val =
              bijections_8[shifted_index].applyInverseTransformation(
                  transformed_val);
        }
        uint32_t tyi_Val = look_up_copy[transformed_val];
        tyi_Val = bijections_32[i / 4].applyTransformation(tyi_Val);
        tyiTables_[round][i][j] = tyi_Val;
      }
    }
  }

  void WhiteBoxTableGenerator::mixTyiTablesDecryption(
      size_t round, const std::vector<MixingBijection<uint8_t>> &bijections_8,
      const std::vector<MixingBijection<uint32_t>> &bijections_32,
      bool use_input_mixing_bijection) {
    for (uint32_t i = 0; i < AES_KEY_LENGTH_BYTES; ++i) {
      TyiTable look_up_copy = tyiTablesDecryption_[round][i];
      uint32_t shifted_index = get_inverse_shifted_index(i);

      for (uint32_t j = 0; j <= std::numeric_limits<uint8_t>::max(); ++j) {
        auto transformed_val = static_cast<uint8_t>(j);
        if (use_input_mixing_bijection) {
          transformed_val =
              bijections_8[shifted_index].applyInverseTransformation(
                  transformed_val);
        }
        uint32_t tyi_Val = look_up_copy[transformed_val];
        tyi_Val = bijections_32[i / 4].applyTransformation(tyi_Val);
        tyiTablesDecryption_[round][i][j] = tyi_Val;
      }
    }
  }

  void WhiteBoxTableGenerator::mixFinalRoundTBoxes(
      const std::vector<MixingBijection<uint8_t>> &bijections_8) {
    RoundTBoxes look_up_copy = finalRoundTBoxes_;
    for (uint32_t i = 0; i < AES_KEY_LENGTH_BYTES; ++i) {
      uint32_t shifted_index = get_shifted_index(i);
      for (uint32_t j = 0; j <= std::numeric_limits<uint8_t>::max(); ++j) {
        auto transformed_val = static_cast<uint8_t>(j);
        transformed_val = bijections_8[shifted_index].applyInverseTransformation(
            transformed_val);
        uint8_t result = look_up_copy[i][transformed_val];
        finalRoundTBoxes_[i][j] = result;
      }
    }
  }

  void WhiteBoxTableGenerator::mixFinalRoundTBoxesDecryption(
      const std::vector<MixingBijection<uint8_t>> &bijections_8) {
    RoundTBoxes look_up_copy = finalRoundTBoxesDecryption_;
    for (uint32_t i = 0; i < AES_KEY_LENGTH_BYTES; ++i) {
      uint32_t shifted_index = get_inverse_shifted_index(i);
      for (uint32_t j = 0; j <= std::numeric_limits<uint8_t>::max(); ++j) {
        auto transformed_val = static_cast<uint8_t>(j);
        transformed_val = bijections_8[shifted_index].applyInverseTransformation(
            transformed_val);
        uint8_t result = look_up_copy[i][transformed_val];
        finalRoundTBoxesDecryption_[i][j] = result;
      }
    }
  }

  void WhiteBoxTableGenerator::calculateInternalEncodings() {
    std::vector<RandomPermutation<uint8_t>> tyi_output;
    std::vector<RandomPermutation<uint8_t>> tyi_output_dec;
    std::vector<RandomPermutation<uint8_t>> xor1_output;
    std::vector<RandomPermutation<uint8_t>> xor1_output_dec;
    std::vector<RandomPermutation<uint8_t>> xor2_output;
    std::vector<RandomPermutation<uint8_t>> xor2_output_dec;

    for (size_t i = 0; i < 9; ++i) {
      // Calculate Tyi output encodings
      tyi_output.clear();
      tyi_output_dec.clear();
      for (size_t j = 0; j < 16 * 8; ++j) {
        tyi_output.emplace_back(rng, 16);
        tyi_output_dec.emplace_back(rng, 16);
      }
      encodeTyiTables(i, xor2_output, tyi_output, true, i != 0);
      encodeTyiTablesDecryption(i, xor2_output_dec, tyi_output_dec, true, i != 0);

      // Calculate XOR1 output encodings
      xor1_output.clear();
      xor1_output_dec.clear();
      for (size_t j = 0; j < 8 * 8; ++j) {
        xor1_output.emplace_back(rng, 16);
        xor1_output_dec.emplace_back(rng, 16);
      }
      encodeXorTables(&xorTables_, i, tyi_output, xor1_output, true, false);
      encodeXorTables(&xorTablesDecryption_, i, tyi_output_dec, xor1_output_dec,
                      true, false);

      // Calculate XOR2 output encodings
      xor2_output.clear();
      xor2_output_dec.clear();
      for (size_t j = 0; j < 32; ++j) {
        xor2_output.emplace_back(rng, 16);
        xor2_output_dec.emplace_back(rng, 16);
      }
      encodeXorTables(&xorTables_, i, xor1_output, xor2_output, true, true);
      encodeXorTables(&xorTablesDecryption_, i, xor1_output_dec, xor2_output_dec,
                      true, true);
    }

    encodeFinalTBoxes(xor2_output);
    encodeFinalTBoxesDecryption(xor2_output_dec);
  }

  void WhiteBoxTableGenerator::calculateInternalEncodingsWithMixingBijections() {
    std::vector<RandomPermutation<uint8_t>> tyi_output;
    std::vector<RandomPermutation<uint8_t>> xor1_output;
    std::vector<RandomPermutation<uint8_t>> xor2_output;
    std::vector<RandomPermutation<uint8_t>> mixing_table_output;
    std::vector<RandomPermutation<uint8_t>> xor3_output;
    std::vector<RandomPermutation<uint8_t>> xor4_output;
    std::vector<RandomPermutation<uint8_t>> tyi_output_dec;
    std::vector<RandomPermutation<uint8_t>> xor1_output_dec;
    std::vector<RandomPermutation<uint8_t>> xor2_output_dec;
    std::vector<RandomPermutation<uint8_t>> mixing_table_output_dec;
    std::vector<RandomPermutation<uint8_t>> xor3_output_dec;
    std::vector<RandomPermutation<uint8_t>> xor4_output_dec;

    for (size_t i = 0; i < 9; ++i) {
      // Calculate Tyi output encodings
      tyi_output.clear();
      tyi_output_dec.clear();
      for (size_t j = 0; j < 16 * 8; ++j) {
        tyi_output.emplace_back(rng, 16);
        tyi_output_dec.emplace_back(rng, 16);
      }
      encodeTyiTables(i, xor4_output, tyi_output, true, i != 0);
      encodeTyiTablesDecryption(i, xor4_output_dec, tyi_output_dec, true, i != 0);

      // Calculate XOR1 output encodings
      xor1_output.clear();
      xor1_output_dec.clear();
      for (size_t j = 0; j < 8 * 8; ++j) {
        xor1_output.emplace_back(rng, 16);
        xor1_output_dec.emplace_back(rng, 16);
      }
      encodeXorTables(&xorTables_, i, tyi_output, xor1_output, true, false);
      encodeXorTables(&xorTablesDecryption_, i, tyi_output_dec, xor1_output_dec,
                      true, false);

      // Calculate XOR2 output encodings
      xor2_output.clear();
      xor2_output_dec.clear();
      for (size_t j = 0; j < 32; ++j) {
        xor2_output.emplace_back(rng, 16);
        xor2_output_dec.emplace_back(rng, 16);
      }
      encodeXorTables(&xorTables_, i, xor1_output, xor2_output, true, true);
      encodeXorTables(&xorTablesDecryption_, i, xor1_output_dec, xor2_output_dec,
                      true, true);

      mixing_table_output.clear();
      mixing_table_output_dec.clear();
      for (size_t j = 0; j < 16 * 8; ++j) {
        mixing_table_output.emplace_back(rng, 16);
        mixing_table_output_dec.emplace_back(rng, 16);
      }
      encodeMixingTables(i, xor2_output, mixing_table_output, true);
      encodeMixingTablesDecryption(i, xor2_output_dec, mixing_table_output_dec,
                                   true);

      xor3_output.clear();
      xor3_output_dec.clear();
      for (size_t j = 0; j < 8 * 8; ++j) {
        xor3_output.emplace_back(rng, 16);
        xor3_output_dec.emplace_back(rng, 16);
      }
      encodeXorTables(&mixingXorTables_, i, mixing_table_output, xor3_output,
                      true, false);
      encodeXorTables(&mixingXorTablesDecryption_, i, mixing_table_output_dec,
                      xor3_output_dec, true, false);

      xor4_output.clear();
      xor4_output_dec.clear();
      for (size_t j = 0; j < 32; ++j) {
        xor4_output.emplace_back(rng, 16);
        xor4_output_dec.emplace_back(rng, 16);
      }
      encodeXorTables(&mixingXorTables_, i, xor3_output, xor4_output, true, true);
      encodeXorTables(&mixingXorTablesDecryption_, i, xor3_output_dec,
                      xor4_output_dec, true, true);
    }

    encodeFinalTBoxes(xor4_output);
    encodeFinalTBoxesDecryption(xor4_output_dec);
  }

  void WhiteBoxTableGenerator::encodeXorTables(
      XorTables *xor_tables, size_t round,
      const std::vector<RandomPermutation<uint8_t>> &input_encodings,
      const std::vector<RandomPermutation<uint8_t>> &output_encodings,
      bool add_output_encodings, bool use_offset) const {
    const size_t offset = (use_offset) ? XOR_TABLE_OFFSET : 0;
    const size_t limit = (use_offset) ? 4 : 8;
    if (xor_tables == nullptr) return;

    for (size_t i = 0; i < limit; ++i) {
      for (size_t j = 0; j < 8; ++j) {
        XorTable &current_table = (*xor_tables)[round][j + i * 8 + offset];
        for (size_t k = 0; k <= std::numeric_limits<uint8_t>::max(); ++k) {
          auto x = static_cast<uint8_t>((k & 0xf0) >> 4);
          auto y = static_cast<uint8_t>(k & 0xf);

          const RandomPermutation<uint8_t> &perm_1 =
              input_encodings.at(j + i * 16);
          const RandomPermutation<uint8_t> &perm_2 =
              input_encodings.at(j + i * 16 + 8);
          uint8_t left_nibble_encoded = perm_1.getOutputInverse(x);
          uint8_t right_nibble_encoded = perm_2.getOutputInverse(y);
          uint8_t xor_result_encoded = left_nibble_encoded ^ right_nibble_encoded;
          if (add_output_encodings) {
            const RandomPermutation<uint8_t> &perm_3 =
                output_encodings.at(j + i * 8);
            xor_result_encoded = perm_3.getOutput(xor_result_encoded);
          }
          current_table[(x << 4) | y] = xor_result_encoded;
        }
      }
    }
  }

  void WhiteBoxTableGenerator::encodeTyiTables(
      size_t round,
      const std::vector<RandomPermutation<uint8_t>> &input_encodings,
      const std::vector<RandomPermutation<uint8_t>> &output_encodings,
      bool add_output_encoding, bool add_input_encoding) {
    for (uint32_t i = 0; i < AES_KEY_LENGTH_BYTES; ++i) {
      TyiTable look_up_copy = tyiTables_[round][i];
      for (uint32_t j = 0; j <= std::numeric_limits<uint8_t>::max(); ++j) {
        // Need copy as to not mess up loop
        uint32_t temp = j;
        uint32_t shifted_index = get_shifted_index(i);

        if (add_input_encoding) {
          auto x = static_cast<uint8_t>((j & 0xf0));
          x >>= 4;
          auto y = static_cast<uint8_t>(j & 0xf);

          uint32_t encoded_1 =
              input_encodings.at(shifted_index * 2).getOutputInverse(x);
          uint32_t encoded_2 =
              input_encodings.at(shifted_index * 2 + 1).getOutputInverse(y);

          temp = (encoded_1 << 4) | encoded_2;
        }

        uint32_t result = look_up_copy[temp];

        // Encode nibbles
        if (add_output_encoding) {
          // Get all 8 nibbles of result
          auto nibble_8 = static_cast<uint8_t>(result & 0xf);
          auto nibble_7 = static_cast<uint8_t>((result & 0xf0) >> 4);
          auto nibble_6 = static_cast<uint8_t>((result & 0xf00) >> 8);
          auto nibble_5 = static_cast<uint8_t>((result & 0xf000) >> 12);
          auto nibble_4 = static_cast<uint8_t>((result & 0xf0000) >> 16);
          auto nibble_3 = static_cast<uint8_t>((result & 0xf00000) >> 20);
          auto nibble_2 = static_cast<uint8_t>((result & 0xf000000) >> 24);
          auto nibble_1 = static_cast<uint8_t>((result & 0xf0000000) >> 28);
          nibble_1 = output_encodings.at(i * 8).getOutput(nibble_1);
          nibble_2 = output_encodings.at(i * 8 + 1).getOutput(nibble_2);
          nibble_3 = output_encodings.at(i * 8 + 2).getOutput(nibble_3);
          nibble_4 = output_encodings.at(i * 8 + 3).getOutput(nibble_4);
          nibble_5 = output_encodings.at(i * 8 + 4).getOutput(nibble_5);
          nibble_6 = output_encodings.at(i * 8 + 5).getOutput(nibble_6);
          nibble_7 = output_encodings.at(i * 8 + 6).getOutput(nibble_7);
          nibble_8 = output_encodings.at(i * 8 + 7).getOutput(nibble_8);
          result = (nibble_1 << 28) | (nibble_2 << 24) | (nibble_3 << 20) |
                   (nibble_4 << 16) | (nibble_5 << 12) | (nibble_6 << 8) |
                   (nibble_7 << 4) | nibble_8;
        }
        tyiTables_[round][i][j] = result;
      }
    }
  }

  void WhiteBoxTableGenerator::encodeTyiTablesDecryption(
      size_t round,
      const std::vector<RandomPermutation<uint8_t>> &input_encodings,
      const std::vector<RandomPermutation<uint8_t>> &output_encodings,
      bool add_output_encoding, bool add_input_encoding) {
    for (uint32_t i = 0; i < AES_KEY_LENGTH_BYTES; ++i) {
      TyiTable look_up_copy = tyiTablesDecryption_[round][i];
      for (uint32_t j = 0; j <= std::numeric_limits<uint8_t>::max(); ++j) {
        // Need copy as to not mess up loop
        uint32_t temp = j;
        uint32_t shifted_index = get_inverse_shifted_index(i);

        if (add_input_encoding) {
          auto x = static_cast<uint8_t>((j & 0xf0));
          x >>= 4;
          auto y = static_cast<uint8_t>(j & 0xf);

          uint32_t encoded_1 =
              input_encodings.at(shifted_index * 2).getOutputInverse(x);
          uint32_t encoded_2 =
              input_encodings.at(shifted_index * 2 + 1).getOutputInverse(y);

          temp = (encoded_1 << 4) | encoded_2;
        }

        uint32_t result = look_up_copy[temp];

        // Encode nibbles
        if (add_output_encoding) {
          // Get all 8 nibbles of result
          auto nibble_8 = static_cast<uint8_t>(result & 0xf);
          auto nibble_7 = static_cast<uint8_t>((result & 0xf0) >> 4);
          auto nibble_6 = static_cast<uint8_t>((result & 0xf00) >> 8);
          auto nibble_5 = static_cast<uint8_t>((result & 0xf000) >> 12);
          auto nibble_4 = static_cast<uint8_t>((result & 0xf0000) >> 16);
          auto nibble_3 = static_cast<uint8_t>((result & 0xf00000) >> 20);
          auto nibble_2 = static_cast<uint8_t>((result & 0xf000000) >> 24);
          auto nibble_1 = static_cast<uint8_t>((result & 0xf0000000) >> 28);
          nibble_1 = output_encodings.at(i * 8).getOutput(nibble_1);
          nibble_2 = output_encodings.at(i * 8 + 1).getOutput(nibble_2);
          nibble_3 = output_encodings.at(i * 8 + 2).getOutput(nibble_3);
          nibble_4 = output_encodings.at(i * 8 + 3).getOutput(nibble_4);
          nibble_5 = output_encodings.at(i * 8 + 4).getOutput(nibble_5);
          nibble_6 = output_encodings.at(i * 8 + 5).getOutput(nibble_6);
          nibble_7 = output_encodings.at(i * 8 + 6).getOutput(nibble_7);
          nibble_8 = output_encodings.at(i * 8 + 7).getOutput(nibble_8);
          result = (nibble_1 << 28) | (nibble_2 << 24) | (nibble_3 << 20) |
                   (nibble_4 << 16) | (nibble_5 << 12) | (nibble_6 << 8) |
                   (nibble_7 << 4) | nibble_8;
        }
        tyiTablesDecryption_[round][i][j] = result;
      }
    }
  }

  void WhiteBoxTableGenerator::encodeFinalTBoxes(
      const std::vector<RandomPermutation<uint8_t>> &input_encodings) {
    RoundTBoxes look_up_copy = finalRoundTBoxes_;
    for (uint32_t i = 0; i < AES_KEY_LENGTH_BYTES; ++i) {
      for (uint32_t j = 0; j <= std::numeric_limits<uint8_t>::max(); ++j) {
        // Need copy as to not mess up loop
        uint32_t temp;
        uint32_t shifted_index = get_shifted_index(i);

        auto x = static_cast<uint8_t>((j & 0xf0));
        x >>= 4;
        auto y = static_cast<uint8_t>(j & 0xf);

        uint32_t encoded_1 =
            input_encodings.at(shifted_index * 2).getOutputInverse(x);
        uint32_t encoded_2 =
            input_encodings.at(shifted_index * 2 + 1).getOutputInverse(y);

        temp = (encoded_1 << 4) | encoded_2;
        uint8_t result = look_up_copy[i][temp];
        finalRoundTBoxes_[i][j] = result;
      }
    }
  }

  void WhiteBoxTableGenerator::encodeFinalTBoxesDecryption(
      const std::vector<RandomPermutation<uint8_t>> &input_encodings) {
    RoundTBoxes look_up_copy = finalRoundTBoxesDecryption_;
    for (uint32_t i = 0; i < AES_KEY_LENGTH_BYTES; ++i) {
      for (uint32_t j = 0; j <= std::numeric_limits<uint8_t>::max(); ++j) {
        // Need copy as to not mess up loop
        uint32_t temp;
        uint32_t shifted_index = get_inverse_shifted_index(i);

        auto x = static_cast<uint8_t>((j & 0xf0));
        x >>= 4;
        auto y = static_cast<uint8_t>(j & 0xf);

        uint32_t encoded_1 =
            input_encodings.at(shifted_index * 2).getOutputInverse(x);
        uint32_t encoded_2 =
            input_encodings.at(shifted_index * 2 + 1).getOutputInverse(y);

        temp = (encoded_1 << 4) | encoded_2;
        uint8_t result = look_up_copy[i][temp];
        finalRoundTBoxesDecryption_[i][j] = result;
      }
    }
  }

  void WhiteBoxTableGenerator::encodeMixingTables(
      size_t round,
      const std::vector<RandomPermutation<uint8_t>> &input_encodings,
      const std::vector<RandomPermutation<uint8_t>> &output_encodings,
      bool add_output_encodings) {
    for (uint32_t i = 0; i < AES_KEY_LENGTH_BYTES; ++i) {
      MixingTable look_up_copy = mixingTables_[round][i];
      for (uint32_t j = 0; j <= std::numeric_limits<uint8_t>::max(); ++j) {
        // Need copy as to not mess up loop
        uint32_t temp;

        auto x = static_cast<uint8_t>((j & 0xf0));
        x >>= 4;
        auto y = static_cast<uint8_t>(j & 0xf);

        uint32_t encoded_1 = input_encodings.at(i * 2).getOutputInverse(x);
        uint32_t encoded_2 = input_encodings.at(i * 2 + 1).getOutputInverse(y);

        temp = (encoded_1 << 4) | encoded_2;

        uint32_t result = look_up_copy[temp];

        // Encode nibbles
        if (add_output_encodings) {
          // Get all 8 nibbles of result
          auto nibble_8 = static_cast<uint8_t>(result & 0xf);
          auto nibble_7 = static_cast<uint8_t>((result & 0xf0) >> 4);
          auto nibble_6 = static_cast<uint8_t>((result & 0xf00) >> 8);
          auto nibble_5 = static_cast<uint8_t>((result & 0xf000) >> 12);
          auto nibble_4 = static_cast<uint8_t>((result & 0xf0000) >> 16);
          auto nibble_3 = static_cast<uint8_t>((result & 0xf00000) >> 20);
          auto nibble_2 = static_cast<uint8_t>((result & 0xf000000) >> 24);
          auto nibble_1 = static_cast<uint8_t>((result & 0xf0000000) >> 28);
          nibble_1 = output_encodings.at(i * 8).getOutput(nibble_1);
          nibble_2 = output_encodings.at(i * 8 + 1).getOutput(nibble_2);
          nibble_3 = output_encodings.at(i * 8 + 2).getOutput(nibble_3);
          nibble_4 = output_encodings.at(i * 8 + 3).getOutput(nibble_4);
          nibble_5 = output_encodings.at(i * 8 + 4).getOutput(nibble_5);
          nibble_6 = output_encodings.at(i * 8 + 5).getOutput(nibble_6);
          nibble_7 = output_encodings.at(i * 8 + 6).getOutput(nibble_7);
          nibble_8 = output_encodings.at(i * 8 + 7).getOutput(nibble_8);
          result = (nibble_1 << 28) | (nibble_2 << 24) | (nibble_3 << 20) |
                   (nibble_4 << 16) | (nibble_5 << 12) | (nibble_6 << 8) |
                   (nibble_7 << 4) | nibble_8;
        }
        mixingTables_[round][i][j] = result;
      }
    }
  }

  void WhiteBoxTableGenerator::encodeMixingTablesDecryption(
      size_t round,
      const std::vector<RandomPermutation<uint8_t>> &input_encodings,
      const std::vector<RandomPermutation<uint8_t>> &output_encodings,
      bool add_output_encodings) {
    for (uint32_t i = 0; i < AES_KEY_LENGTH_BYTES; ++i) {
      MixingTable look_up_copy = mixingTablesDecryption_[round][i];
      for (uint32_t j = 0; j <= std::numeric_limits<uint8_t>::max(); ++j) {
        // Need copy as to not mess up loop
        uint32_t temp;

        auto x = static_cast<uint8_t>((j & 0xf0));
        x >>= 4;
        auto y = static_cast<uint8_t>(j & 0xf);

        uint32_t encoded_1 = input_encodings.at(i * 2).getOutputInverse(x);
        uint32_t encoded_2 = input_encodings.at(i * 2 + 1).getOutputInverse(y);

        temp = (encoded_1 << 4) | encoded_2;

        uint32_t result = look_up_copy[temp];

        // Encode nibbles
        if (add_output_encodings) {
          // Get all 8 nibbles of result
          auto nibble_8 = static_cast<uint8_t>(result & 0xf);
          auto nibble_7 = static_cast<uint8_t>((result & 0xf0) >> 4);
          auto nibble_6 = static_cast<uint8_t>((result & 0xf00) >> 8);
          auto nibble_5 = static_cast<uint8_t>((result & 0xf000) >> 12);
          auto nibble_4 = static_cast<uint8_t>((result & 0xf0000) >> 16);
          auto nibble_3 = static_cast<uint8_t>((result & 0xf00000) >> 20);
          auto nibble_2 = static_cast<uint8_t>((result & 0xf000000) >> 24);
          auto nibble_1 = static_cast<uint8_t>((result & 0xf0000000) >> 28);
          nibble_1 = output_encodings.at(i * 8).getOutput(nibble_1);
          nibble_2 = output_encodings.at(i * 8 + 1).getOutput(nibble_2);
          nibble_3 = output_encodings.at(i * 8 + 2).getOutput(nibble_3);
          nibble_4 = output_encodings.at(i * 8 + 3).getOutput(nibble_4);
          nibble_5 = output_encodings.at(i * 8 + 4).getOutput(nibble_5);
          nibble_6 = output_encodings.at(i * 8 + 5).getOutput(nibble_6);
          nibble_7 = output_encodings.at(i * 8 + 6).getOutput(nibble_7);
          nibble_8 = output_encodings.at(i * 8 + 7).getOutput(nibble_8);
          result = (nibble_1 << 28) | (nibble_2 << 24) | (nibble_3 << 20) |
                   (nibble_4 << 16) | (nibble_5 << 12) | (nibble_6 << 8) |
                   (nibble_7 << 4) | nibble_8;
        }
        mixingTablesDecryption_[round][i][j] = result;
      }
    }
  }

  void WhiteBoxTableGenerator::calculateTyiTables(const TBoxes &tBoxes) {
    for (int i = 0; i < NUM_ROUNDS_AES_128 - 1; ++i) {
      for (size_t j = 0; j < AES_KEY_LENGTH_BYTES; ++j) {
        const TBox &t_box = tBoxes[i][j];
        if (j % 4 == 0) {
          for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
            uint8_t t = t_box[x];

            uint8_t byte_1 = galois_mul(0x2, t);
            uint8_t byte_2 = t;
            uint8_t byte_3 = t;
            uint8_t byte_4 = galois_mul(0x3, t);

            tyiTables_[i][j][x] =
                static_cast<unsigned int>((static_cast<uint32_t>(byte_1) << 24U) |
                                          (static_cast<uint32_t>(byte_2) << 16U) |
                                          (static_cast<uint32_t>(byte_3) << 8U) |
                                          static_cast<uint32_t>(byte_4));
          }
        } else if (j % 4 == 1) {
          for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
            uint8_t t = t_box[x];

            uint8_t byte_1 = galois_mul(0x3, t);
            uint8_t byte_2 = galois_mul(0x2, t);
            uint8_t byte_3 = t;
            uint8_t byte_4 = t;

            tyiTables_[i][j][x] =
                static_cast<unsigned int>((static_cast<uint32_t>(byte_1) << 24U) |
                                          (static_cast<uint32_t>(byte_2) << 16U) |
                                          (static_cast<uint32_t>(byte_3) << 8U) |
                                          static_cast<uint32_t>(byte_4));
          }
        } else if (j % 4 == 2) {
          for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
            uint8_t t = t_box[x];

            uint8_t byte_1 = t;
            uint8_t byte_2 = galois_mul(0x3, t);
            uint8_t byte_3 = galois_mul(0x2, t);
            uint8_t byte_4 = t;

            tyiTables_[i][j][x] =
                static_cast<unsigned int>((static_cast<uint32_t>(byte_1) << 24U) |
                                          (static_cast<uint32_t>(byte_2) << 16U) |
                                          (static_cast<uint32_t>(byte_3) << 8U) |
                                          static_cast<uint32_t>(byte_4));
          }
        } else {
          for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
            uint8_t t = t_box[x];

            uint8_t byte_1 = t;
            uint8_t byte_2 = t;
            uint8_t byte_3 = galois_mul(0x3, t);
            uint8_t byte_4 = galois_mul(0x2, t);

            tyiTables_[i][j][x] =
                static_cast<unsigned int>((static_cast<uint32_t>(byte_1) << 24U) |
                                          (static_cast<uint32_t>(byte_2) << 16U) |
                                          (static_cast<uint32_t>(byte_3) << 8U) |
                                          static_cast<uint32_t>(byte_4));
          }
        }
      }
    }
  }

  void WhiteBoxTableGenerator::calculateTyiTablesDecryption(
      const TBoxes &tBoxes) {
    for (uint32_t i = 0; i < NUM_ROUNDS_AES_128 - 1; ++i) {
      for (uint32_t j = 0; j < AES_KEY_LENGTH_BYTES; ++j) {
        const TBox &t_box = tBoxes[i][j];
        if (j % 4 == 0) {
          for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
            uint8_t t = t_box[x];

            uint8_t byte_1 = galois_mul(0xe, t);
            uint8_t byte_2 = galois_mul(0x9, t);
            uint8_t byte_3 = galois_mul(0xd, t);
            uint8_t byte_4 = galois_mul(0xb, t);

            tyiTablesDecryption_[i][j][x] =
                static_cast<unsigned int>((static_cast<uint32_t>(byte_1) << 24U) |
                                          (static_cast<uint32_t>(byte_2) << 16U) |
                                          (static_cast<uint32_t>(byte_3) << 8U) |
                                          static_cast<uint32_t>(byte_4));
          }
        } else if (j % 4 == 1) {
          for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
            uint8_t t = t_box[x];

            uint8_t byte_1 = galois_mul(0xb, t);
            uint8_t byte_2 = galois_mul(0xe, t);
            uint8_t byte_3 = galois_mul(0x9, t);
            uint8_t byte_4 = galois_mul(0xd, t);

            tyiTablesDecryption_[i][j][x] =
                static_cast<unsigned int>((static_cast<uint32_t>(byte_1) << 24U) |
                                          (static_cast<uint32_t>(byte_2) << 16U) |
                                          (static_cast<uint32_t>(byte_3) << 8U) |
                                          static_cast<uint32_t>(byte_4));
          }
        } else if (j % 4 == 2) {
          for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
            uint8_t t = t_box[x];

            uint8_t byte_1 = galois_mul(0xd, t);
            uint8_t byte_2 = galois_mul(0xb, t);
            uint8_t byte_3 = galois_mul(0xe, t);
            uint8_t byte_4 = galois_mul(0x9, t);

            tyiTablesDecryption_[i][j][x] =
                static_cast<unsigned int>((static_cast<uint32_t>(byte_1) << 24U) |
                                          (static_cast<uint32_t>(byte_2) << 16U) |
                                          (static_cast<uint32_t>(byte_3) << 8U) |
                                          static_cast<uint32_t>(byte_4));
          }
        } else {
          for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
            uint8_t t = t_box[x];

            uint8_t byte_1 = galois_mul(0x9, t);
            uint8_t byte_2 = galois_mul(0xd, t);
            uint8_t byte_3 = galois_mul(0xb, t);
            uint8_t byte_4 = galois_mul(0xe, t);

            tyiTablesDecryption_[i][j][x] =
                static_cast<unsigned int>((static_cast<uint32_t>(byte_1) << 24U) |
                                          (static_cast<uint32_t>(byte_2) << 16U) |
                                          (static_cast<uint32_t>(byte_3) << 8U) |
                                          static_cast<uint32_t>(byte_4));
          }
        }
      }
    }
  }

  void WhiteBoxTableGenerator::calculateXorTables(XorTables *xor_tables) const {
    if (xor_tables != nullptr) {
      for (size_t i = 0; i < 9; ++i) {
        for (size_t j = 0; j < 96; ++j) {
          for (size_t x = 0; x <= std::numeric_limits<uint8_t>::max(); ++x) {
            auto lower_nibble = static_cast<uint8_t>(x & 0xF);
            auto upper_nibble = static_cast<uint8_t>(x & 0xF0);
            (*xor_tables)[i][j][x] = (upper_nibble >> 4) ^ lower_nibble;
          }
        }
      }
    }
  }

  WhiteBoxData *WhiteBoxTableGenerator::getEncryptionTable() const {
    auto *data = new WhiteBoxData;

    // Since array has value semantics, this works
    // It is an expensive operation though
    data->finalRoundTBoxes_ = this->finalRoundTBoxes_;
    data->tyiTables_ = this->tyiTables_;
    data->xorTables_ = this->xorTables_;

    data->usesMixingBijections_ = this->usesMixingBijections_;

    data->mixingXorTables_ = this->mixingXorTables_;
    data->mixingTables_ = this->mixingTables_;

    return data;
  }

  WhiteBoxData *WhiteBoxTableGenerator::getDecryptionTable() const {
    auto *data = new WhiteBoxData;

    data->finalRoundTBoxes_ = this->finalRoundTBoxesDecryption_;
    data->tyiTables_ = this->tyiTablesDecryption_;
    data->xorTables_ = this->xorTablesDecryption_;

    data->usesMixingBijections_ = this->usesMixingBijections_;

    data->mixingXorTables_ = this->mixingXorTablesDecryption_;
    data->mixingTables_ = this->mixingTablesDecryption_;

    return data;
  }
}  // namespace WhiteBox


text:
/*!
@file
Defines `boost::hana::infix`.

@copyright Louis Dionne 2013-2017
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#ifndef BOOST_HANA_FUNCTIONAL_INFIX_HPP
#define BOOST_HANA_FUNCTIONAL_INFIX_HPP

#include <boost/hana/config.hpp>
#include <boost/hana/detail/decay.hpp>
#include <boost/hana/functional/partial.hpp>
#include <boost/hana/functional/reverse_partial.hpp>

#include <type_traits>
#include <utility>

BOOST_HANA_NAMESPACE_BEGIN
    //! @ingroup group-functional
    //! Return an equivalent function that can also be applied in infix
    //! notation.
    //!
    //! Specifically, `infix(f)` is an object such that:
    //! @code
    //!     infix(f)(x1, ..., xn) == f(x1, ..., xn)
    //!     x ^infix(f)^ y == f(x, y)
    //! @endcode
    //!
    //! Hence, the returned function can still be applied using the usual
    //! function call syntax, but it also gains the ability to be applied in
    //! infix notation. The infix syntax allows a great deal of expressiveness,
    //! especially when used in combination with some higher order algorithms.
    //! Since `operator^` is left-associative, `x ^infix(f)^ y` is actually
    //! parsed as `(x ^infix(f))^ y`. However, for flexibility, the order in
    //! which both arguments are applied in infix notation does not matter.
    //! Hence, it is always the case that
    //! @code
    //!     (x ^ infix(f)) ^ y == x ^ (infix(f) ^ y)
    //! @endcode
    //!
    //! However, note that applying more than one argument in infix
    //! notation to the same side of the operator will result in a
    //! compile-time assertion:
    //! @code
    //!     (infix(f) ^ x) ^ y; // compile-time assertion
    //!     y ^ (x ^ infix(f)); // compile-time assertion
    //! @endcode
    //!
    //! Additionally, a function created with `infix` may be partially applied
    //! in infix notation. Specifically,
    //! @code
    //!     (x ^ infix(f))(y1, ..., yn) == f(x, y1, ..., yn)
    //!     (infix(f) ^ y)(x1, ..., xn) == f(x1, ..., xn, y)
    //! @endcode
    //!
    //! @internal
    //! ### Rationales
    //! 1. The `^` operator was chosen because it is left-associative and
    //!    has a low enough priority so that most expressions will render
    //!    the expected behavior.
    //! 2. The operator can't be customimzed because that would require more
    //!    sophistication in the implementation; I want to keep it as simple
    //!    as possible. There is also an advantage in having a uniform syntax
    //!    for infix application.
    //! @endinternal
    //!
    //! @param f
    //! The function which gains the ability to be applied in infix notation.
    //! The function must be at least binary; a compile-time error will be
    //! triggered otherwise.
    //!
    //! ### Example
    //! @include example/functional/infix.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
    constexpr auto infix = [](auto f) {
        return unspecified;
    };
#else
    namespace infix_detail {
        // This needs to be in the same namespace as `operator^` so it can be
        // found by ADL.
        template <bool left, bool right, typename F>
        struct infix_t {
            F f;

            template <typename ...X>
            constexpr decltype(auto) operator()(X&& ...x) const&
            { return f(static_cast<X&&>(x)...); }

            template <typename ...X>
            constexpr decltype(auto) operator()(X&& ...x) &
            { return f(static_cast<X&&>(x)...); }

            template <typename ...X>
            constexpr decltype(auto) operator()(X&& ...x) &&
            { return std::move(f)(static_cast<X&&>(x)...); }
        };

        template <bool left, bool right>
        struct make_infix {
            template <typename F>
            constexpr infix_t<left, right, typename detail::decay<F>::type>
            operator()(F&& f) const { return {static_cast<F&&>(f)}; }
        };

        template <bool left, bool right>
        struct Infix;
        struct Object;

        template <typename T>
        struct dispatch { using type = Object; };

        template <bool left, bool right, typename F>
        struct dispatch<infix_t<left, right, F>> {
            using type = Infix<left, right>;
        };

        template <typename, typename>
        struct bind_infix;

        // infix(f) ^ y
        template <>
        struct bind_infix<Infix<false, false>, Object> {
            template <typename F, typename Y>
            static constexpr decltype(auto) apply(F&& f, Y&& y) {
                return make_infix<false, true>{}(
                    hana::reverse_partial(
                        static_cast<F&&>(f), static_cast<Y&&>(y)
                    )
                );
            }
        };

        // (x^infix(f)) ^ y
        template <>
        struct bind_infix<Infix<true, false>, Object> {
            template <typename F, typename Y>
            static constexpr decltype(auto) apply(F&& f, Y&& y) {
                return static_cast<F&&>(f)(static_cast<Y&&>(y));
            }
        };

        // x ^ infix(f)
        template <>
        struct bind_infix<Object, Infix<false, false>> {
            template <typename X, typename F>
            static constexpr decltype(auto) apply(X&& x, F&& f) {
                return make_infix<true, false>{}(
                    hana::partial(static_cast<F&&>(f), static_cast<X&&>(x))
                );
            }
        };

        // x ^ (infix(f)^y)
        template <>
        struct bind_infix<Object, Infix<false, true>> {
            template <typename X, typename F>
            static constexpr decltype(auto) apply(X&& x, F&& f) {
                return static_cast<F&&>(f)(static_cast<X&&>(x));
            }
        };

        template <typename T>
        using strip = typename std::remove_cv<
            typename std::remove_reference<T>::type
        >::type;

        template <typename X, typename Y>
        constexpr decltype(auto) operator^(X&& x, Y&& y) {
            return bind_infix<
                typename dispatch<strip<X>>::type,
                typename dispatch<strip<Y>>::type
            >::apply(static_cast<X&&>(x), static_cast<Y&&>(y));
        }
    } // end namespace infix_detail

    constexpr infix_detail::make_infix<false, false> infix{};
#endif
BOOST_HANA_NAMESPACE_END

#endif // !BOOST_HANA_FUNCTIONAL_INFIX_HPP

max_stars_repo_name: kindlychung/mediasoup-sfu-cpp

max_issues_repo_name: kindlychung/mediasoup-sfu-cpp

max_forks_repo_name: kindlychung/mediasoup-sfu-cpp


text:
#ifndef MODEL_DISTRIBUTION_HPP
#define MODEL_DISTRIBUTION_HPP

#include "gtest/gtest_prod.h"
#include "types.hpp"

#include <algorithm>
#include <boost/log/trivial.hpp>
#include <numeric>
#include <random>
#include <unordered_map>
#include <utility>

namespace FilterModel {

/**
 * Represents the probability distribution encoded by the latent variable model adapted from in
 * Perkins et al.
 */
class ModelDistribution {
   public:
    /**
     * Constructs a new ModelDistribution object from a vector of category counts.
     *
     * Arguments:
     *  data - vector of category counts
     *  generator - random number generator
     *  comparison - test parameter, should usually ignore. If true, runs both exact and approximate
     *    methods for evaluating the probability, compares them, and stops the program if the
     *    estimates are too far apart.
     */
    ModelDistribution(const std::vector<category_counts_t> &data,
                      std::default_random_engine &generator, const Options &options);

    /**
     * Calculates log(p(k | alpha, epsilon, delta)) for every object in the data for every value
     * of alpha in alphas_per_object for that object. Returns a vector over objects of vectors
     * over log conditional probabilities per value of alpha.
     *
     * For example, if alphas_per_object = {{{1,0}}, {0,1}}, {{1,0}},
     * {{1,0}, {0,1}, {1, 1}} then the output might be {{-2, -8}, {-7}, {-1.2,
     * -2.1, -5.7}} where {-2, -8} are the log conditional probabilities for alpha={1,0} and
     * alpha={0,1} for the first object.
     */
    std::vector<std::vector<double>> distribution(
        const std::vector<std::vector<alpha_t>> &alphas_per_object, double epsilon,
        const delta_t &delta) const;

    /**
     * Calculates log(p(k | alpha, epsilon, delta)) for every object in the data for the given
     * alpha. Returns a vector over objects of vectors over log conditional probabilities per value
     * of alpha.
     *
     * For example, if alphas = {{0,1,0}, {1,1,1}} then the output might be {{-2, -7}, {-4, -5}}
     * where log(p(k | alpha={0,1,0}, ...)) = -2 for the first object,
     * log(p(k | alpha={0,1,0}, ...)) = -4 for the second obect, log(p(k | alpha={1,1,1}, ...)) = -7
     * for the first object, and so on.
     */
    std::vector<std::vector<double>> distribution(const std::vector<alpha_t> &alphas,
                                                  double epsilon, const delta_t &delta) const;

    // The following are public only so I can test them easier. FRIEND_TEST exists, but it doesn't
    // work right for static methods.

    static double calculate_log_p_k_positive_given_alpha_n_positive(int n_positive,
                                                                    const alpha_t &alpha);
    // This is non-static only so it has access to the comparison testing parameter.
    double calculate_log_sum_over_k_negative(int n_positive, int n_negative, const alpha_t &alpha,
                                             const delta_t &delta,
                                             const category_counts_t &object_counts) const;
    static double calculate_sum_over_k_negative_exact(int n_positive, int n_negative,
                                                      const alpha_t &alpha, const delta_t &delta,
                                                      const category_counts_t &object_counts);

    // Uses MVI3 integration
    static double calculate_sum_over_k_negative_approx(int n_positive, int n_negative,
                                                       const alpha_t &alpha, const delta_t &delta,
                                                       const category_counts_t &object_counts);
    /**
     * Given n^+, n^-, alpha, and k, loop over all possible values for k^-, and call f() on each.
     *
     * This is hard-coded for |alpha|=3. Doing this in a generic way was incredibly slow.
     */
    static void iterate_over_k_negatives(std::function<void(int, int, int)> f, int n_positive,
                                         int n_negative, const alpha_t &alpha,
                                         const category_counts_t &object_counts);

    /**
     * Removes components of v for which alpha_i has the wrong value.
     */
    template <class T>
    static std::vector<T> filter_by_alpha(const alpha_t &alpha, const std::vector<T> &v,
                                          const bool value = true) {
        assert(alpha.size() == v.size());

        std::vector<T> filtered;
        for (int i = 0; i < alpha.size(); ++i) {
            if (alpha.at(i) == value) {
                filtered.push_back(v.at(i));
            }
        }
        return filtered;
    }

   private:
    const std::vector<category_counts_t> &data;
    const Options options;
    std::default_random_engine &generator;

    /**
     * Test for if using a normal approximation (and mvi3 integration) is permissible.
     *
     * There is no real standard for when the multinomial to multivariate guassian approximation
     * is valid, so we adapt the standard binomial to guassian rule, which is that there is a
     * mean of at least 5 elements in every dimension.
     *
     * TODO(joschnei): Verify experimentally that this is a good heuristic.
     */
    bool can_use_normal_approx(int n_negative, const delta_t &delta) const;

    // The below are currently not in use beacuse of randomness problems.

    // Uses naive Monte-Carlo integration
    double calculate_sum_over_k_negative_approx_2(int n_positive, int n_negative,
                                                  const alpha_t &alpha, const delta_t &delta,
                                                  const category_counts_t &object_counts);
    /**
     * Creates a hyperplane array representing the constraints on k_minus for use in mvi3
     * integration.
     *
     * Each of the four constraints on k_negative can be represented as a set of linear
     * inequalities in the values of k_negative. This function creates those linear equalities
     * so that they can be passed as constraints to mvi3, a method for integrating a multinomial
     * pdf over a convex set. See function defintion for details of the exact constraints.
     */
    static std::vector<std::vector<double>> get_hyperplanes(int n_negative,
                                                            category_counts_t object_counts);
};
}  // namespace FilterModel

#endif

max_stars_repo_name: skinnersBoxy/input-filter

max_issues_repo_name: skinnersBoxy/input-filter

max_forks_repo_name: skinnersBoxy/input-filter