<commit_before>#include <iostream>
#include <fstream>

#include <fstream>
#include <string>
#include <algorithm>
#include <random>
#include <chrono>
#include <memory>
#include <cmath>
#include <stdlib.h>

#include <getopt.h>

#include <unsupported/Eigen/SparseExtra>

#include "macau.h"
#include "gen_random.h"

using namespace Eigen;
using namespace std;

const int num_latent = 5;

int main(int argc, char** argv) {
    assert(argc>3 && "Usage GFA N D iter");

    int N = atoi(argv[1]);
    int D = atoi(argv[2]);
    int iter_max = atoi(argv[3]);

    assert(D>0 && N>0 && iter_max > 0 && "Usage GFA N D iter_max");

    DenseMF slave_model(num_latent);
    Macau slave_macau(slave_model);
    slave_macau.setSamples(10, iter_max);

    // fixed gaussian noise
    slave_macau.setPrecision(1.0);
    slave_macau.setVerbose(true);

    // = random_Ydense(N,D,3);
    auto Ytrain1 = ones_Ydense(N,D,2);
    auto Ytest1  = extract(Ytrain1, .2);
    slave_model.setRelationData(Ytrain1);
    slave_model.setRelationDataTest(Ytest1);

    //-- Normal priors
    //slave_macau.addPrior<DenseSpikeAndSlabPrior>(model);
    slave_macau.addPrior<DenseNormalPrior>();
    slave_macau.addPrior<SlavePrior<DenseNormalPrior>>();

    DenseMF master_model(num_latent);
    Macau master_macau(master_model);
    master_macau.setSamples(10, iter_max);

    // fixed gaussian noise
    master_macau.setPrecision(1.0);
    master_macau.setVerbose(true);

    // = random_Ydense(N,D,3);
    auto Ytrain2 = ones_Ydense(N,D,2);
    auto Ytest2  = extract(Ytrain2, .2);
    master_model.setRelationData(Ytrain2);
    master_model.setRelationDataTest(Ytest2);

    //-- Normal priors
    //master_macau.addPrior<DenseSpikeAndSlabPrior>(model);
    master_macau.addPrior<DenseNormalPrior>();
    auto &master_prior = master_macau.addPrior<MasterNormalPrior<DenseNormalPrior>>();
    master_prior.addSideInfo(slave_macau);

    master_macau.run();
}
<commit_msg>less verbose<commit_after>#include <iostream>
#include <fstream>

#include <fstream>
#include <string>
#include <algorithm>
#include <random>
#include <chrono>
#include <memory>
#include <cmath>
#include <stdlib.h>

#include <getopt.h>

#include <unsupported/Eigen/SparseExtra>

#include "macau.h"
#include "gen_random.h"

using namespace Eigen;
using namespace std;

const int num_latent = 5;

int main(int argc, char** argv) {
    assert(argc>3 && "Usage GFA N D iter");

    int N = atoi(argv[1]);
    int D = atoi(argv[2]);
    int iter_max = atoi(argv[3]);

    assert(D>0 && N>0 && iter_max > 0 && "Usage GFA N D iter_max");

    DenseMF slave_model(num_latent);
    Macau slave_macau(slave_model);
    slave_macau.setSamples(10, iter_max);

    // fixed gaussian noise
    slave_macau.setPrecision(1.0);
    slave_macau.setVerbose(false);

    // = random_Ydense(N,D,3);
    auto Ytrain1 = ones_Ydense(N,2*D,2);
    auto Ytest1  = extract(Ytrain1, .2);
    slave_model.setRelationData(Ytrain1);
    slave_model.setRelationDataTest(Ytest1);

    //-- Normal priors
    //slave_macau.addPrior<DenseSpikeAndSlabPrior>(model);
    slave_macau.addPrior<DenseNormalPrior>();
    slave_macau.addPrior<SlavePrior<DenseNormalPrior>>();

    DenseMF master_model(num_latent);
    Macau master_macau(master_model);
    master_macau.setSamples(10, iter_max);

    // fixed gaussian noise
    master_macau.setPrecision(1.0);
    master_macau.setVerbose(true);

    // = random_Ydense(N,D,3);
    auto Ytrain2 = ones_Ydense(N,D,2);
    auto Ytest2  = extract(Ytrain2, .2);
    master_model.setRelationData(Ytrain2);
    master_model.setRelationDataTest(Ytest2);

    //-- Normal priors
    //master_macau.addPrior<DenseSpikeAndSlabPrior>(model);
    master_macau.addPrior<DenseNormalPrior>();
    auto &master_prior = master_macau.addPrior<MasterNormalPrior<DenseNormalPrior>>();
    master_prior.addSideInfo(slave_macau);

    master_macau.run();
}
<|endoftext|>


<commit_before>// MS WARNINGS MACRO
#define _SCL_SECURE_NO_WARNINGS

// Macro: Program Settings
#define ENABLE_NETWORK_IO 1

#include <iostream>
#include <deque>
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
#include <boost/program_options.hpp>
#include "data_type.hpp"
#include "pixel_sorter.hpp"
#include "ppm_reader.hpp"
#include "splitter.hpp"
#include "algorithm.hpp"
#include "algorithm_2.hpp"
#include "gui.hpp"
#include "network.hpp"
#include "test_tool.hpp"

#include <sort_algorithm/yrange2.hpp>
#include <sort_algorithm/yrange5.hpp>
#include <sort_algorithm/genetic.hpp>
#include <sort_algorithm/Murakami.hpp>

class position_manager : boost::noncopyable
{
public:
    typedef question_data position_type;

    position_manager() = default;
    virtual ~position_manager() = default;

    template<class T>
    void add(T && pos)
    {
        std::lock_guard<std::mutex> lock(mutex_);
        items_.push_back(std::forward<T>(pos));
    }

    position_type get()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        auto res = items_.front();
        items_.pop_front();
        return res;
    }

    bool empty()
    {
        return items_.empty();
    }

private:
    std::mutex mutex_;
    std::deque<position_type> items_;
};

class analyzer : boost::noncopyable
{
public:
    explicit analyzer(
        std::string const& server_addr,
        int const problem_id, std::string const& player_id,
        bool const is_auto, bool const is_blur
        )
        : client_(server_addr), problem_id_(problem_id), player_id_(player_id),
          is_auto_(is_auto), is_blur_(is_blur)
    {
    }
    virtual ~analyzer() = default;

    void operator() (position_manager& manager)
    {
        splitter sp;

        // 問題文の入手
        raw_data_ = get_raw_question();
        data_     = get_skelton_question(raw_data_);

        // 2次元画像に分割
        split_image_ = sp.split_image(raw_data_);

        // compare用の画像を作成
        auto const arranged_split = is_blur_ ? sp.split_image_gaussianblur(split_image_) : split_image_;
        auto const image_comp = sorter_.image_comp(raw_data_, arranged_split);
		auto const image_comp_dx = sorter_dx.image_comp(raw_data_, arranged_split);

        // 原画像推測部
        yrange2 yrange2_(raw_data_, image_comp);
        Murakami murakami_(raw_data_, image_comp,true);

        // GUI Threadの起動
        gui::manager gui_thread(
            [this, &manager](std::vector<std::vector<point_type>> const& data)
            {
                // 回答としてマーク -> 回答ジョブに追加
                auto clone = data_.clone();
                clone.block = data;
                manager.add(convert_block(clone));
            });

        // YRange2 -> YRange5 Thread
        boost::thread y_thread(
            [&, this]()
            {
                // YRange2
                auto yrange2_resolve = yrange2_();
                if (!yrange2_resolve.empty())
		        {
                    // Shoot
                    if(is_auto_)
                    {
                        auto clone = data_.clone();
                        clone.block = yrange2_resolve[0].points;
                        manager.add(convert_block(clone));
                    }

                    // GUI
			        for (int y2 = yrange2_resolve.size() - 1; y2 >= 0; --y2)
			        {
                        gui_thread.push_back(
                            boost::bind(gui::make_mansort_window, split_image_, yrange2_resolve.at(y2).points, "yrange2")
                            );
			        }
		        }

                // YRange5
                auto yrange5_resolve = yrange5(raw_data_, image_comp)(yrange2_.sorted_matrix());
                if (!yrange5_resolve.empty())
		        {
                    // GUI
			        for (int y5 = yrange5_resolve.size() - 1; y5 >= 0; --y5)
			        {
                        gui_thread.push_back(
                            boost::bind(gui::make_mansort_window, split_image_, yrange5_resolve.at(y5).points, "yrange5")
                            );
			        }
                }
            });

        // Murakami Thread
        boost::thread m_thread(
            [&]()
            {
                // Murakami
			std::cout << "村上モード" << std::endl;
                auto murakami_resolve = murakami_()[0].points;
				std::vector<std::vector<point_type>> murakami_dx_resolve, murakami_w_resolve, murakami_dx_w_resolve;
				if (!murakami_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_resolve, "Murakami"));
				if (murakami_resolve.empty()){
					std::cout << "デラックス村上モード" << std::endl;
					Murakami murakami_dx(raw_data_, image_comp_dx, true);
					murakami_dx_resolve = murakami_dx()[0].points;
					if (!murakami_dx_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_dx_resolve, "Murakami_dx"));
					if (murakami_dx_resolve.empty()){
						std::cout << "W村上モード" << std::endl;
						Murakami murakami_w(raw_data_, image_comp, false);
						murakami_w_resolve = murakami_w()[0].points;
						if (!murakami_w_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_w_resolve, "Murakami_w"));
						if (murakami_w_resolve.empty()){
							std::cout << "デラックスW村上モード" << std::endl;
							Murakami murakami_dx_w(raw_data_, image_comp_dx, false);
							murakami_dx_w_resolve = murakami_w()[0].points;
							if (!murakami_dx_w_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_dx_w_resolve, "Murakami_dx_w"));
						}
					}
				}
            });

        gui_thread.push_back(
            boost::bind(gui::make_mansort_window, split_image_, "Yor are the sorter!!! Sort this!")
            );

        // 各Threadの待機
        y_thread.join();
        m_thread.join();
        gui_thread.wait_all_window();
    }

    std::string submit(answer_type const& ans) const
    {
        auto submit_result = client_.submit(problem_id_, player_id_, ans);
        return submit_result.get();
    }

private:
    question_raw_data get_raw_question() const
    {
#if ENABLE_NETWORK_IO
        // ネットワーク通信から
        std::string const data = client_.get_problem(problem_id_).get();
        return ppm_reader().from_data(data);
#else
        // ファイルから
        std::string const path("prob01.ppm");
        return ppm_reader().from_file(path);
#endif
    }

    question_data get_skelton_question(question_raw_data const& raw) const
    {
        question_data formed = {
            problem_id_,
            player_id_,
            raw.split_num,
            raw.selectable_num,
            raw.cost.first,
            raw.cost.second,
            std::vector<std::vector<point_type>>()
        };

        return formed;
    }

    question_data convert_block(question_data const& data) const
    {
        auto res = data.clone();

        for(int i = 0; i < data.size.second; ++i)
        {
            for(int j = 0; j < data.size.first; ++j)
            {
                auto const& target = data.block[i][j];
                res.block[target.y][target.x] = point_type{j, i};
		}
        }

        return res;
    }

    int const problem_id_;
    std::string const player_id_;
    bool const is_auto_;
    bool const is_blur_;

    question_raw_data raw_data_;
    question_data         data_;
    split_image_type  split_image_;
	split_image_type  split_image_gaussianblur;

    mutable network::client client_;
    pixel_sorter<yrange5> sorter_;
	pixel_sorter<yrange2> sorter_dx;
};

void submit_func(question_data question, analyzer const& analyze)
{
    algorithm algo;
    algorithm_2 algo2;
    algo.reset(question);

    auto const answer = algo.get();
    if(answer) // 解が見つかった
    {
#if ENABLE_NETWORK_IO
        // TODO: 前より良くなったら提出など(普通にいらないかも．提出前に目grepしてるわけだし)
        auto result = analyze.submit(answer.get());
        std::cout << "Submit Result: " << result << std::endl;

	// FIXME: 汚いしセグフォする
	int wrong_number = std::stoi(result.substr(result.find(" ")));
	if(wrong_number == 0)
	{
        algo2.reset(question);
		auto const answer = algo2.get();
		if (answer)
		{
			auto result = analyze.submit(answer.get());
			std::cout << "Submit Result: " << result << std::endl;
			std::cout << "勝った！" << std::endl;
		}
	}
#else
        test_tool::emulator emu(question);
        auto result = emu.start(answer.get());
        std::cout << "Wrong: " << result.wrong << std::endl;
        std::cout << "Cost : " << result.cost  << std::endl;
        std::cout << "---" << std::endl;
#endif
    }
}

int main(int const argc, char const* argv[])
{
    std::string server_addr;
	int         problemid = 0;
    auto const  token = "3935105806";
    bool        is_auto;
    bool        is_blur;

    try
    {
        namespace po = boost::program_options;
        po::options_description opt("option");
        opt.add_options()
            ("help,h"    , "produce help message")
            ("auto,a"    , "auto submit flag")
            ("blur,b"    , "gaussian blur to image")
#if ENABLE_NETWORK_IO
            ("server,s"  , po::value<std::string>(&server_addr), "(require)set server ip address")
            ("problem,p" , po::value<int>(&problemid)          , "(require)set problem_id")
#endif
            ;

        po::variables_map argmap;
        po::store(po::parse_command_line(argc, argv, opt), argmap);
        po::notify(argmap);

#if ENABLE_NETWORK_IO
        if(argmap.count("help") || !argmap.count("server") || !argmap.count("problem"))
#else
        if(argmap.count("help"))
#endif
        {
            std::cout << opt << std::endl;
            return 0;
        }

        is_auto = argmap.count("auto");
        is_blur = argmap.count("blur");
    }
    catch(boost::program_options::error_with_option_name const& e)
    {
        std::cout << e.what() << std::endl;
        std::exit(-1);
    }

    analyzer         analyze(server_addr, problemid, token, is_auto, is_blur);
    position_manager manager;

    boost::thread thread(boost::bind(&analyzer::operator(), &analyze, std::ref(manager)));
    boost::thread_group submit_threads;

    while(thread.joinable())
    {
        if(!manager.empty())
        {
            auto question = manager.get();

            // 手順探索部
            submit_threads.create_thread(
                boost::bind(submit_func, question, boost::ref(analyze))
                );
        }
    }

    thread.join();
    submit_threads.join_all();

    return 0;
}

<commit_msg>ダウンロードした問題を保存するコードを追加．デフォルトではマクロは無効になっている．<commit_after>// MS WARNINGS MACRO
#define _SCL_SECURE_NO_WARNINGS

// Macro: Program Settings
#define ENABLE_NETWORK_IO 1
#define ENABLE_SAVE_IMAGE 0

#include <iostream>
#include <deque>
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
#include <boost/program_options.hpp>
#include "data_type.hpp"
#include "pixel_sorter.hpp"
#include "ppm_reader.hpp"
#include "splitter.hpp"
#include "algorithm.hpp"
#include "algorithm_2.hpp"
#include "gui.hpp"
#include "network.hpp"
#include "test_tool.hpp"

#include <sort_algorithm/yrange2.hpp>
#include <sort_algorithm/yrange5.hpp>
#include <sort_algorithm/genetic.hpp>
#include <sort_algorithm/Murakami.hpp>

class position_manager : boost::noncopyable
{
public:
    typedef question_data position_type;

    position_manager() = default;
    virtual ~position_manager() = default;

    template<class T>
    void add(T && pos)
    {
        std::lock_guard<std::mutex> lock(mutex_);
        items_.push_back(std::forward<T>(pos));
    }

    position_type get()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        auto res = items_.front();
        items_.pop_front();
        return res;
    }

    bool empty()
    {
        return items_.empty();
    }

private:
    std::mutex mutex_;
    std::deque<position_type> items_;
};

class analyzer : boost::noncopyable
{
public:
    explicit analyzer(
        std::string const& server_addr,
        int const problem_id, std::string const& player_id,
        bool const is_auto, bool const is_blur
#if ENABLE_SAVE_IMAGE
        ,std::string const& dir_path = "./saved_image"
#endif
        )
        : client_(server_addr), problem_id_(problem_id), player_id_(player_id)
        , is_auto_(is_auto), is_blur_(is_blur)
#if ENABLE_SAVE_IMAGE
        , dir_path_(dir_path), saved_num_(0)
#endif
    {
    }
    virtual ~analyzer() = default;

    void operator() (position_manager& manager)
    {
        splitter sp;

        // 問題文の入手
        raw_data_ = get_raw_question();
        data_     = get_skelton_question(raw_data_);

        // 2次元画像に分割
        split_image_ = sp.split_image(raw_data_);

        // compare用の画像を作成
        auto const arranged_split = is_blur_ ? sp.split_image_gaussianblur(split_image_) : split_image_;
        auto const image_comp = sorter_.image_comp(raw_data_, arranged_split);
		auto const image_comp_dx = sorter_dx.image_comp(raw_data_, arranged_split);

        // 原画像推測部
        yrange2 yrange2_(raw_data_, image_comp);
        Murakami murakami_(raw_data_, image_comp,true);

        // GUI Threadの起動
        gui::manager gui_thread(
            [this, &manager](std::vector<std::vector<point_type>> const& data)
            {
                // 回答としてマーク -> 回答ジョブに追加
                auto clone = data_.clone();
                clone.block = data;
                manager.add(convert_block(clone));
            });

        // YRange2 -> YRange5 Thread
        boost::thread y_thread(
            [&, this]()
            {
                // YRange2
                auto yrange2_resolve = yrange2_();
                if (!yrange2_resolve.empty())
		        {
                    // Shoot
                    if(is_auto_)
                    {
                        auto clone = data_.clone();
                        clone.block = yrange2_resolve[0].points;
                        manager.add(convert_block(clone));
                    }

                    // GUI
			        for (int y2 = yrange2_resolve.size() - 1; y2 >= 0; --y2)
			        {
                        gui_thread.push_back(
                            boost::bind(gui::make_mansort_window, split_image_, yrange2_resolve.at(y2).points, "yrange2")
                            );
			        }
		        }

                // YRange5
                auto yrange5_resolve = yrange5(raw_data_, image_comp)(yrange2_.sorted_matrix());
                if (!yrange5_resolve.empty())
		        {
                    // GUI
			        for (int y5 = yrange5_resolve.size() - 1; y5 >= 0; --y5)
			        {
                        gui_thread.push_back(
                            boost::bind(gui::make_mansort_window, split_image_, yrange5_resolve.at(y5).points, "yrange5")
                            );
			        }
                }
            });

        // Murakami Thread
        boost::thread m_thread(
            [&]()
            {
                // Murakami
			std::cout << "村上モード" << std::endl;
                auto murakami_resolve = murakami_()[0].points;
				std::vector<std::vector<point_type>> murakami_dx_resolve, murakami_w_resolve, murakami_dx_w_resolve;
				if (!murakami_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_resolve, "Murakami"));
				if (murakami_resolve.empty()){
					std::cout << "デラックス村上モード" << std::endl;
					Murakami murakami_dx(raw_data_, image_comp_dx, true);
					murakami_dx_resolve = murakami_dx()[0].points;
					if (!murakami_dx_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_dx_resolve, "Murakami_dx"));
					if (murakami_dx_resolve.empty()){
						std::cout << "W村上モード" << std::endl;
						Murakami murakami_w(raw_data_, image_comp, false);
						murakami_w_resolve = murakami_w()[0].points;
						if (!murakami_w_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_w_resolve, "Murakami_w"));
						if (murakami_w_resolve.empty()){
							std::cout << "デラックスW村上モード" << std::endl;
							Murakami murakami_dx_w(raw_data_, image_comp_dx, false);
							murakami_dx_w_resolve = murakami_w()[0].points;
							if (!murakami_dx_w_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_dx_w_resolve, "Murakami_dx_w"));
						}
					}
				}
            });

        gui_thread.push_back(
            boost::bind(gui::make_mansort_window, split_image_, "Yor are the sorter!!! Sort this!")
            );

        // 各Threadの待機
        y_thread.join();
        m_thread.join();
        gui_thread.wait_all_window();
    }

    std::string submit(answer_type const& ans) const
    {
        auto submit_result = client_.submit(problem_id_, player_id_, ans);
        return submit_result.get();
    }

private:
    question_raw_data get_raw_question() const
    {
#if ENABLE_NETWORK_IO
        // ネットワーク通信から
        std::string const data = client_.get_problem(problem_id_).get();
#if ENABLE_SAVE_IMAGE
        std::ofstream ofs((boost::format("%s/prob%02d.ppm") % dir_path_ % saved_num_++).str(), std::ios::binary);
        ofs << data;
        ofs.close();
#endif
        return ppm_reader().from_data(data);
#else
        // ファイルから
        std::string const path("prob01.ppm");
        return ppm_reader().from_file(path);
#endif
    }

    question_data get_skelton_question(question_raw_data const& raw) const
    {
        question_data formed = {
            problem_id_,
            player_id_,
            raw.split_num,
            raw.selectable_num,
            raw.cost.first,
            raw.cost.second,
            std::vector<std::vector<point_type>>()
        };

        return formed;
    }

    question_data convert_block(question_data const& data) const
    {
        auto res = data.clone();

        for(int i = 0; i < data.size.second; ++i)
        {
            for(int j = 0; j < data.size.first; ++j)
            {
                auto const& target = data.block[i][j];
                res.block[target.y][target.x] = point_type{j, i};
		}
        }

        return res;
    }

    int const problem_id_;
    std::string const player_id_;
    bool const is_auto_;
    bool const is_blur_;

    question_raw_data raw_data_;
    question_data         data_;
    split_image_type  split_image_;
	split_image_type  split_image_gaussianblur;

    mutable network::client client_;
    pixel_sorter<yrange5> sorter_;
	pixel_sorter<yrange2> sorter_dx;

#if ENABLE_SAVE_IMAGE
    mutable std::string dir_path_;
    mutable int         saved_num_;
#endif
};

void submit_func(question_data question, analyzer const& analyze)
{
    algorithm algo;
    algorithm_2 algo2;
    algo.reset(question);

    auto const answer = algo.get();
    if(answer) // 解が見つかった
    {
#if ENABLE_NETWORK_IO
        // TODO: 前より良くなったら提出など(普通にいらないかも．提出前に目grepしてるわけだし)
        auto result = analyze.submit(answer.get());
        std::cout << "Submit Result: " << result << std::endl;

	// FIXME: 汚いしセグフォする
	int wrong_number = std::stoi(result.substr(result.find(" ")));
	if(wrong_number == 0)
	{
        algo2.reset(question);
		auto const answer = algo2.get();
		if (answer)
		{
			auto result = analyze.submit(answer.get());
			std::cout << "Submit Result: " << result << std::endl;
			std::cout << "勝った！" << std::endl;
		}
	}
#else
        test_tool::emulator emu(question);
        auto result = emu.start(answer.get());
        std::cout << "Wrong: " << result.wrong << std::endl;
        std::cout << "Cost : " << result.cost  << std::endl;
        std::cout << "---" << std::endl;
#endif
    }
}

int main(int const argc, char const* argv[])
{
    std::string server_addr;
	int         problemid = 0;
    auto const  token = "3935105806";
    bool        is_auto;
    bool        is_blur;
#if ENABLE_SAVE_IMAGE
    std::string save_dir;
#endif

    try
    {
        namespace po = boost::program_options;
        po::options_description opt("option");
        opt.add_options()
            ("help,h"    , "produce help message")
            ("auto,a"    , "auto submit flag")
            ("blur,b"    , "gaussian blur to image")
#if ENABLE_SAVE_IMAGE
            ("save_dir"  , po::value<std::string>(&save_dir)   , "(require)set image dir to save")
#endif
#if ENABLE_NETWORK_IO
            ("server,s"  , po::value<std::string>(&server_addr), "(require)set server ip address")
            ("problem,p" , po::value<int>(&problemid)          , "(require)set problem_id")
#endif
            ;

        po::variables_map argmap;
        po::store(po::parse_command_line(argc, argv, opt), argmap);
        po::notify(argmap);

#if ENABLE_NETWORK_IO
        if(argmap.count("help") || !argmap.count("server") || !argmap.count("problem"))
#else
        if(argmap.count("help"))
#endif
        {
            std::cout << opt << std::endl;
            return 0;
        }

        is_auto = argmap.count("auto");
        is_blur = argmap.count("blur");
    }
    catch(boost::program_options::error_with_option_name const& e)
    {
        std::cout << e.what() << std::endl;
        std::exit(-1);
    }

#if ENABLE_SAVE_IMAGE
    if(save_dir.empty()) save_dir = "./saved_image";
    analyzer         analyze(server_addr, problemid, token, is_auto, is_blur, save_dir);
#else
    analyzer         analyze(server_addr, problemid, token, is_auto, is_blur);
#endif
    position_manager manager;

    boost::thread thread(boost::bind(&analyzer::operator(), &analyze, std::ref(manager)));
    boost::thread_group submit_threads;

    while(thread.joinable())
    {
        if(!manager.empty())
        {
            auto question = manager.get();

            // 手順探索部
            submit_threads.create_thread(
                boost::bind(submit_func, question, boost::ref(analyze))
                );
        }
    }

    thread.join();
    submit_threads.join_all();

    return 0;
}

<|endoftext|>


<commit_before>#include "rai/lib/errors.hpp"

std::string nano::error_common_messages::message (int ev) const
{
	switch (static_cast<nano::error_common> (ev))
	{
		case nano::error_common::generic:
			return "Unknown error";
		case nano::error_common::account_exists:
			return "Account already exists";
		case nano::error_common::account_not_found:
			return "Account not found";
		case nano::error_common::account_not_found_wallet:
			return "Account not found in wallet";
		case nano::error_common::bad_account_number:
			return "Bad account number";
		case nano::error_common::bad_private_key:
			return "Bad private key";
		case nano::error_common::bad_public_key:
			return "Bad public key";
		case nano::error_common::bad_seed:
			return "Bad seed";
		case nano::error_common::bad_threshold:
			return "Bad threshold number";
		case nano::error_common::bad_wallet_number:
			return "Bad wallet number";
		case nano::error_common::bad_work_format:
			return "Bad work";
		case nano::error_common::insufficient_balance:
			return "Insufficient balance";
		case nano::error_common::invalid_amount:
			return "Invalid amount number";
		case nano::error_common::invalid_amount_big:
			return "Amount too big";
		case nano::error_common::invalid_count:
			return "Invalid count";
		case nano::error_common::invalid_ip_address:
			return "Invalid IP address";
		case nano::error_common::invalid_port:
			return "Invalid port";
		case nano::error_common::invalid_index:
			return "Invalid index";
		case nano::error_common::invalid_work:
			return "Invalid work";
		case nano::error_common::numeric_conversion:
			return "Numeric conversion error";
		case nano::error_common::wallet_lmdb_max_dbs:
			return "Failed to create wallet. Increase lmdb_max_dbs in node config";
		case nano::error_common::wallet_locked:
			return "Wallet is locked";
		case nano::error_common::wallet_not_found:
			return "Wallet not found";
	}

	return "Invalid error code";
}

std::string nano::error_blocks_messages::message (int ev) const
{
	switch (static_cast<nano::error_blocks> (ev))
	{
		case nano::error_blocks::generic:
			return "Unknown error";
		case nano::error_blocks::bad_hash_number:
			return "Bad hash number";
		case nano::error_blocks::invalid_block:
			return "Block is invalid";
		case nano::error_blocks::invalid_block_hash:
			return "Invalid block hash";
		case nano::error_blocks::invalid_type:
			return "Invalid block type";
		case nano::error_blocks::not_found:
			return "Block not found";
		case nano::error_blocks::work_low:
			return "Block work is less than threshold";
	}

	return "Invalid error code";
}

std::string nano::error_rpc_messages::message (int ev) const
{
	switch (static_cast<nano::error_rpc> (ev))
	{
		case nano::error_rpc::generic:
			return "Unknown error";
		case nano::error_rpc::bad_destination:
			return "Bad destination account";
		case nano::error_rpc::bad_key:
			return "Bad key";
		case nano::error_rpc::bad_link:
			return "Bad link number";
		case nano::error_rpc::bad_previous:
			return "Bad previous";
		case nano::error_rpc::bad_representative_number:
			return "Bad representative number";
		case nano::error_rpc::bad_source:
			return "Bad source";
		case nano::error_rpc::bad_timeout:
			return "Bad timeout number";
		case nano::error_rpc::block_create_balance_mismatch:
			return "Balance mismatch for previous block";
		case nano::error_rpc::block_create_key_required:
			return "Private key or local wallet and account required";
		case nano::error_rpc::block_create_public_key_mismatch:
			return "Incorrect key for given account";
		case nano::error_rpc::block_create_requirements_state:
			return "Previous, representative, final balance and link (source or destination) are required";
		case nano::error_rpc::block_create_requirements_open:
			return "Representative account and source hash required";
		case nano::error_rpc::block_create_requirements_receive:
			return "Previous hash and source hash required";
		case nano::error_rpc::block_create_requirements_change:
			return "Representative account and previous hash required";
		case nano::error_rpc::block_create_requirements_send:
			return "Destination account, previous hash, current balance and amount required";
		case nano::error_rpc::invalid_balance:
			return "Invalid balance number";
		case nano::error_rpc::invalid_destinations:
			return "Invalid destinations number";
		case nano::error_rpc::invalid_offset:
			return "Invalid offset";
		case nano::error_rpc::invalid_missing_type:
			return "Invalid or missing type argument";
		case nano::error_rpc::invalid_sources:
			return "Invalid sources number";
		case nano::error_rpc::payment_account_balance:
			return "Account has non-zero balance";
		case nano::error_rpc::payment_unable_create_account:
			return "Unable to create transaction account";
		case nano::error_rpc::rpc_control_disabled:
			return "RPC control is disabled";
		case nano::error_rpc::source_not_found:
			return "Source not found";
	}

	return "Invalid error code";
}

std::string nano::error_process_messages::message (int ev) const
{
	switch (static_cast<nano::error_process> (ev))
	{
		case nano::error_process::generic:
			return "Unknown error";
		case nano::error_process::bad_signature:
			return "Bad signature";
		case nano::error_process::old:
			return "Old block";
		case nano::error_process::negative_spend:
			return "Negative spend";
		case nano::error_process::fork:
			return "Fork";
		case nano::error_process::unreceivable:
			return "Unreceivable";
		case nano::error_process::gap_previous:
			return "Gap previous block";
		case nano::error_process::gap_source:
			return "Gap source block";
		case nano::error_process::opened_burn_account:
			return "Burning account";
		case nano::error_process::balance_mismatch:
			return "Balance and amount delta do not match";
		case nano::error_process::block_position:
			return "This block cannot follow the previous block";
		case nano::error_process::other:
			"Error processing block";
	}

	return "Invalid error code";
}
<commit_msg>Missing return statement in error_process_messages<commit_after>#include "rai/lib/errors.hpp"

std::string nano::error_common_messages::message (int ev) const
{
	switch (static_cast<nano::error_common> (ev))
	{
		case nano::error_common::generic:
			return "Unknown error";
		case nano::error_common::account_exists:
			return "Account already exists";
		case nano::error_common::account_not_found:
			return "Account not found";
		case nano::error_common::account_not_found_wallet:
			return "Account not found in wallet";
		case nano::error_common::bad_account_number:
			return "Bad account number";
		case nano::error_common::bad_private_key:
			return "Bad private key";
		case nano::error_common::bad_public_key:
			return "Bad public key";
		case nano::error_common::bad_seed:
			return "Bad seed";
		case nano::error_common::bad_threshold:
			return "Bad threshold number";
		case nano::error_common::bad_wallet_number:
			return "Bad wallet number";
		case nano::error_common::bad_work_format:
			return "Bad work";
		case nano::error_common::insufficient_balance:
			return "Insufficient balance";
		case nano::error_common::invalid_amount:
			return "Invalid amount number";
		case nano::error_common::invalid_amount_big:
			return "Amount too big";
		case nano::error_common::invalid_count:
			return "Invalid count";
		case nano::error_common::invalid_ip_address:
			return "Invalid IP address";
		case nano::error_common::invalid_port:
			return "Invalid port";
		case nano::error_common::invalid_index:
			return "Invalid index";
		case nano::error_common::invalid_work:
			return "Invalid work";
		case nano::error_common::numeric_conversion:
			return "Numeric conversion error";
		case nano::error_common::wallet_lmdb_max_dbs:
			return "Failed to create wallet. Increase lmdb_max_dbs in node config";
		case nano::error_common::wallet_locked:
			return "Wallet is locked";
		case nano::error_common::wallet_not_found:
			return "Wallet not found";
	}

	return "Invalid error code";
}

std::string nano::error_blocks_messages::message (int ev) const
{
	switch (static_cast<nano::error_blocks> (ev))
	{
		case nano::error_blocks::generic:
			return "Unknown error";
		case nano::error_blocks::bad_hash_number:
			return "Bad hash number";
		case nano::error_blocks::invalid_block:
			return "Block is invalid";
		case nano::error_blocks::invalid_block_hash:
			return "Invalid block hash";
		case nano::error_blocks::invalid_type:
			return "Invalid block type";
		case nano::error_blocks::not_found:
			return "Block not found";
		case nano::error_blocks::work_low:
			return "Block work is less than threshold";
	}

	return "Invalid error code";
}

std::string nano::error_rpc_messages::message (int ev) const
{
	switch (static_cast<nano::error_rpc> (ev))
	{
		case nano::error_rpc::generic:
			return "Unknown error";
		case nano::error_rpc::bad_destination:
			return "Bad destination account";
		case nano::error_rpc::bad_key:
			return "Bad key";
		case nano::error_rpc::bad_link:
			return "Bad link number";
		case nano::error_rpc::bad_previous:
			return "Bad previous";
		case nano::error_rpc::bad_representative_number:
			return "Bad representative number";
		case nano::error_rpc::bad_source:
			return "Bad source";
		case nano::error_rpc::bad_timeout:
			return "Bad timeout number";
		case nano::error_rpc::block_create_balance_mismatch:
			return "Balance mismatch for previous block";
		case nano::error_rpc::block_create_key_required:
			return "Private key or local wallet and account required";
		case nano::error_rpc::block_create_public_key_mismatch:
			return "Incorrect key for given account";
		case nano::error_rpc::block_create_requirements_state:
			return "Previous, representative, final balance and link (source or destination) are required";
		case nano::error_rpc::block_create_requirements_open:
			return "Representative account and source hash required";
		case nano::error_rpc::block_create_requirements_receive:
			return "Previous hash and source hash required";
		case nano::error_rpc::block_create_requirements_change:
			return "Representative account and previous hash required";
		case nano::error_rpc::block_create_requirements_send:
			return "Destination account, previous hash, current balance and amount required";
		case nano::error_rpc::invalid_balance:
			return "Invalid balance number";
		case nano::error_rpc::invalid_destinations:
			return "Invalid destinations number";
		case nano::error_rpc::invalid_offset:
			return "Invalid offset";
		case nano::error_rpc::invalid_missing_type:
			return "Invalid or missing type argument";
		case nano::error_rpc::invalid_sources:
			return "Invalid sources number";
		case nano::error_rpc::payment_account_balance:
			return "Account has non-zero balance";
		case nano::error_rpc::payment_unable_create_account:
			return "Unable to create transaction account";
		case nano::error_rpc::rpc_control_disabled:
			return "RPC control is disabled";
		case nano::error_rpc::source_not_found:
			return "Source not found";
	}

	return "Invalid error code";
}

std::string nano::error_process_messages::message (int ev) const
{
	switch (static_cast<nano::error_process> (ev))
	{
		case nano::error_process::generic:
			return "Unknown error";
		case nano::error_process::bad_signature:
			return "Bad signature";
		case nano::error_process::old:
			return "Old block";
		case nano::error_process::negative_spend:
			return "Negative spend";
		case nano::error_process::fork:
			return "Fork";
		case nano::error_process::unreceivable:
			return "Unreceivable";
		case nano::error_process::gap_previous:
			return "Gap previous block";
		case nano::error_process::gap_source:
			return "Gap source block";
		case nano::error_process::opened_burn_account:
			return "Burning account";
		case nano::error_process::balance_mismatch:
			return "Balance and amount delta do not match";
		case nano::error_process::block_position:
			return "This block cannot follow the previous block";
		case nano::error_process::other:
			return "Error processing block";
	}

	return "Invalid error code";
}
<|endoftext|>


<commit_before>#include"ics3/ics3.hpp"

#include"core.hpp"
#include"ics3/eeprom.hpp"
#include"ics3/parameter.hpp"
#include"ics3/id.hpp"

#include<stdexcept>
#include<array>
#include<cassert>

inline uint16_t getReceiveAngle(const std::vector<unsigned char>& rx) noexcept {
  return static_cast<uint16_t>((rx[4] << 7) | rx[5]);
}

ics::ICS3::ICS3(const std::string& path, const Baudrate& baudrate)
: core {Core::getReference(path, baudrate.get())}
{}

ics::Angle ics::ICS3::free(const ID& id, Angle unit) const {
  static std::vector<unsigned char> tx(3), rx(6);
  tx[0] = 0x80 | id.get();
  tx[1] = 0;
  tx[2] = 0;
  core.communicate(tx, rx); // throw std::runtime_error
  unit.rawData = getReceiveAngle(rx);
  return unit;
}

ics::Angle ics::ICS3::move(const ID& id, Angle angle) const {
  static std::vector<unsigned char> tx(3), rx(6);
  uint16_t send {angle.getRaw()};
  tx[0] = 0x80 | id.get();
  tx[1] = 0x7F & (send >> 7);
  tx[2] = 0x7F & send;
  core.communicate(tx, rx); // throw std::runtime_error
  angle.rawData = getReceiveAngle(rx);
  return angle;
}

ics::Parameter ics::ICS3::get(const ID& id, const Parameter& place) const {
  static std::vector<unsigned char> tx(2), rx(5);
  tx[0] = 0xA0 | id.get();
  tx[1] = place.getSubcommand();
  core.communicate(tx, rx); // throw std::runtime_error
  return Parameter::newParameter(place, rx[4]);
}

void ics::ICS3::set(const ID& id, const Parameter& param) const {
  static std::vector<unsigned char> tx(3), rx(6);
  tx[0] = 0xC0 | id.get();
  tx[1] = param.getSubcommand();
  tx[2] = param.get();
  core.communicate(tx, rx); // throw std::runtime_error
}

ics::EepRom ics::ICS3::getRom(const ID& id) const {
  static std::vector<unsigned char> tx(2), rx(68);
  tx[0] = 0xA0 | id.get();
  tx[1] = 0;
  core.communicate(tx, rx); // throw std::runtime_error
  std::array<unsigned char, 64> rom;
  std::copy(rx.begin() + 2, rx.end(), rom.begin());
  return EepRom {rom}; // need friend
}

void ics::ICS3::setRom(const ID& id, const EepRom& rom) const {
  static std::vector<unsigned char> tx(66), rx(68);
  tx[0] = 0xC0 | id.get();
  tx[2] = 0;
  rom.write(tx.begin() + 2);
  core.communicate(tx, rx); // throw std::runtime_error
}
<commit_msg>Fix receive EepRom data<commit_after>#include"ics3/ics3.hpp"

#include"core.hpp"
#include"ics3/eeprom.hpp"
#include"ics3/parameter.hpp"
#include"ics3/id.hpp"

#include<stdexcept>
#include<array>
#include<cassert>

inline uint16_t getReceiveAngle(const std::vector<unsigned char>& rx) noexcept {
  return static_cast<uint16_t>((rx[4] << 7) | rx[5]);
}

ics::ICS3::ICS3(const std::string& path, const Baudrate& baudrate)
: core {Core::getReference(path, baudrate.get())}
{}

ics::Angle ics::ICS3::free(const ID& id, Angle unit) const {
  static std::vector<unsigned char> tx(3), rx(6);
  tx[0] = 0x80 | id.get();
  tx[1] = 0;
  tx[2] = 0;
  core.communicate(tx, rx); // throw std::runtime_error
  unit.rawData = getReceiveAngle(rx);
  return unit;
}

ics::Angle ics::ICS3::move(const ID& id, Angle angle) const {
  static std::vector<unsigned char> tx(3), rx(6);
  uint16_t send {angle.getRaw()};
  tx[0] = 0x80 | id.get();
  tx[1] = 0x7F & (send >> 7);
  tx[2] = 0x7F & send;
  core.communicate(tx, rx); // throw std::runtime_error
  angle.rawData = getReceiveAngle(rx);
  return angle;
}

ics::Parameter ics::ICS3::get(const ID& id, const Parameter& place) const {
  static std::vector<unsigned char> tx(2), rx(5);
  tx[0] = 0xA0 | id.get();
  tx[1] = place.getSubcommand();
  core.communicate(tx, rx); // throw std::runtime_error
  return Parameter::newParameter(place, rx[4]);
}

void ics::ICS3::set(const ID& id, const Parameter& param) const {
  static std::vector<unsigned char> tx(3), rx(6);
  tx[0] = 0xC0 | id.get();
  tx[1] = param.getSubcommand();
  tx[2] = param.get();
  core.communicate(tx, rx); // throw std::runtime_error
}

ics::EepRom ics::ICS3::getRom(const ID& id) const {
  static std::vector<unsigned char> tx(2), rx(68);
  tx[0] = 0xA0 | id.get();
  tx[1] = 0;
  core.communicate(tx, rx); // throw std::runtime_error
  std::array<unsigned char, 64> rom;
  std::copy(rx.begin() + 4, rx.end(), rom.begin());
  return EepRom {rom}; // need friend
}

void ics::ICS3::setRom(const ID& id, const EepRom& rom) const {
  static std::vector<unsigned char> tx(66), rx(68);
  tx[0] = 0xC0 | id.get();
  tx[2] = 0;
  rom.write(tx.begin() + 2);
  core.communicate(tx, rx); // throw std::runtime_error
}
<|endoftext|>


<commit_before>/*
   Copyright 2011 John Selbie

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include "commonincludes.hpp"
#include "stuncore.h"
#include "stunsocket.h"
#include "stunsocketthread.h"
#include "recvfromex.h"

CStunSocketThread::CStunSocketThread() :
_arrSendSockets(), // zero-init
_fNeedToExit(false),
_pthread((pthread_t)-1),
_fThreadIsValid(false),
_rotation(0),
_tsa() // zero-init
{
    ClearSocketArray();
}

CStunSocketThread::~CStunSocketThread()
{
    SignalForStop(true);
    WaitForStopAndClose();
}

void CStunSocketThread::ClearSocketArray()
{
    _arrSendSockets = NULL;
    _socks.clear();
}

HRESULT CStunSocketThread::Init(CStunSocket* arrayOfFourSockets, TransportAddressSet* pTSA, IStunAuth* pAuth, SocketRole rolePrimaryRecv)
{
    HRESULT hr = S_OK;

    bool fSingleSocketRecv = ::IsValidSocketRole(rolePrimaryRecv);

    ChkIfA(_fThreadIsValid, E_UNEXPECTED);

    ChkIfA(arrayOfFourSockets == NULL, E_INVALIDARG);
    ChkIfA(pTSA == NULL, E_INVALIDARG);

    // if this thread was configured to listen on a single socket (aka "multi-threaded mode"), then
    // validate that it exists
    if (fSingleSocketRecv)
    {
        ChkIfA(arrayOfFourSockets[rolePrimaryRecv].IsValid()==false, E_UNEXPECTED);
    }

    _arrSendSockets = arrayOfFourSockets;

    // initialize the TSA thing
    _tsa = *pTSA;

    if (fSingleSocketRecv)
    {
        // only one socket to listen on
        _socks.push_back(&_arrSendSockets[rolePrimaryRecv]);
    }
    else
    {
        for (size_t i = 0; i < 4; i++)
        {
            if (_arrSendSockets[i].IsValid())
            {
                _socks.push_back(&_arrSendSockets[i]);
            }
        }
    }

    Chk(InitThreadBuffers());

    _fNeedToExit = false;

    _rotation = 0;

    _spAuth.Attach(pAuth);

Cleanup:
    return hr;
}

HRESULT CStunSocketThread::InitThreadBuffers()
{
    HRESULT hr = S_OK;

    _reader.Reset();

    _spBufferReader = CRefCountedBuffer(new CBuffer(MAX_STUN_MESSAGE_SIZE));
    _spBufferIn = CRefCountedBuffer(new CBuffer(MAX_STUN_MESSAGE_SIZE));
    _spBufferOut = CRefCountedBuffer(new CBuffer(MAX_STUN_MESSAGE_SIZE));

    _reader.GetStream().Attach(_spBufferReader, true);

    _msgIn.fConnectionOriented = false;
    _msgIn.pReader = &_reader;
    _msgOut.spBufferOut = _spBufferOut;

    return hr;
}

void CStunSocketThread::UninitThreadBuffers()
{
    _reader.Reset();
    _spBufferReader.reset();
    _spBufferIn.reset();
    _spBufferOut.reset();

    _msgIn.pReader = NULL;
    _msgOut.spBufferOut.reset();
}

HRESULT CStunSocketThread::Start()
{
    HRESULT hr = S_OK;
    int err = 0;

    ChkIfA(_fThreadIsValid, E_UNEXPECTED);

    ChkIfA(_socks.size() <= 0, E_FAIL);

    err = ::pthread_create(&_pthread, NULL, CStunSocketThread::ThreadFunction, this);

    ChkIfA(err != 0, ERRNO_TO_HRESULT(err));
    _fThreadIsValid = true;

Cleanup:
    return hr;
}

HRESULT CStunSocketThread::SignalForStop(bool fPostMessages)
{

    HRESULT hr = S_OK;

    _fNeedToExit = true;

    // have the socket send a message to itself
    // if another thread is sharing the same socket, this may wake that thread up to
    // but all the threads should be started and shutdown together
    if (fPostMessages)
    {
        for (size_t index = 0; index < _socks.size(); index++)
        {
            char data = 'x';

            ASSERT(_socks[index] != NULL);

            CSocketAddress addr(_socks[index]->GetLocalAddress());

            // If no specific adapter was binded to, IP will be 0.0.0.0
            // Linux evidently treats 0.0.0.0 IP as loopback (and works)
            // On Windows you can't send to 0.0.0.0. sendto will fail - switch to sending to localhost
            if (addr.IsIPAddressZero())
            {
                CSocketAddress addrLocal;
                CSocketAddress::GetLocalHost(addr.GetFamily(), &addrLocal);
                addrLocal.SetPort(addr.GetPort());
                addr = addrLocal;
            }

            ::sendto(_socks[index]->GetSocketHandle(), &data, 1, 0, addr.GetSockAddr(), addr.GetSockAddrLength());
        }
    }

    return hr;
}

HRESULT CStunSocketThread::WaitForStopAndClose()
{
    void* pRetValFromThread = NULL;

    if (_fThreadIsValid)
    {
        // now wait for the thread to exit
        pthread_join(_pthread, &pRetValFromThread);
    }

    _fThreadIsValid = false;
    _pthread = (pthread_t)-1;

    ClearSocketArray();

    UninitThreadBuffers();

    return S_OK;
}

// static
void* CStunSocketThread::ThreadFunction(void* pThis)
{
    ((CStunSocketThread*)pThis)->Run();
    return NULL;
}

// returns an index into _socks, not _arrSockets
CStunSocket* CStunSocketThread::WaitForSocketData()
{
    fd_set set = {};
    int nHighestSockValue = 0;
    int ret;
    CStunSocket* pReadySocket = NULL;
    UNREFERENCED_VARIABLE(ret); // only referenced in ASSERT
    size_t nSocketCount = _socks.size();

    // rotation gives another socket priority in the next loop
    _rotation = (_rotation + 1) % nSocketCount;
    ASSERT(_rotation >= 0);

    FD_ZERO(&set);

    for (size_t index = 0; index < nSocketCount; index++)
    {
        ASSERT(_socks[index] != NULL);
        int sock = _socks[index]->GetSocketHandle();
        ASSERT(sock != -1);
        FD_SET(sock, &set);
        nHighestSockValue = (sock > nHighestSockValue) ? sock : nHighestSockValue;
    }

    // wait indefinitely for a socket
    ret = ::select(nHighestSockValue+1, &set, NULL, NULL, NULL);

    ASSERT(ret > 0); // This will be a benign assert, and should never happen.  But I will want to know if it does

    // now figure out which socket just got data on it
    for (size_t index = 0; index < nSocketCount; index++)
    {
        int indexconverted = (index + _rotation) % nSocketCount;
        int sock = _socks[indexconverted]->GetSocketHandle();

        ASSERT(sock != -1);

        if (FD_ISSET(sock, &set))
        {
            pReadySocket = _socks[indexconverted];
            break;
        }
    }

    ASSERT(pReadySocket != NULL);

    return pReadySocket;
}

void CStunSocketThread::Run()
{
    size_t nSocketCount = _socks.size();
    bool fMultiSocketMode = (nSocketCount > 1);
    int recvflags = fMultiSocketMode ? MSG_DONTWAIT : 0;
    CStunSocket* pSocket = _socks[0];
    int ret;

    int sendsocketcount = 0;

    sendsocketcount += (int)(_tsa.set[RolePP].fValid);
    sendsocketcount += (int)(_tsa.set[RolePA].fValid);
    sendsocketcount += (int)(_tsa.set[RoleAP].fValid);
    sendsocketcount += (int)(_tsa.set[RoleAA].fValid);

    Logging::LogMsg(LL_DEBUG, "Starting listener thread (%d recv sockets, %d send sockets)", _socks.size(), sendsocketcount);

    while (_fNeedToExit == false)
    {

        if (fMultiSocketMode)
        {
            pSocket = WaitForSocketData();

            if (_fNeedToExit)
            {
                break;
            }

            ASSERT(pSocket != NULL);

            if (pSocket == NULL)
            {
                // just go back to waiting;
                continue;
            }
        }

        ASSERT(pSocket != NULL);

        // now receive the data
        _spBufferIn->SetSize(0);

        ret = ::recvfromex(pSocket->GetSocketHandle(), _spBufferIn->GetData(), _spBufferIn->GetAllocatedSize(), recvflags, &_msgIn.addrRemote, &_msgIn.addrLocal);

        // recvfromex no longer sets the port value on the local address
        if (ret >= 0)
        {
            _msgIn.addrLocal.SetPort(pSocket->GetLocalAddress().GetPort());
        }

        if (Logging::GetLogLevel() >= LL_VERBOSE)
        {
            char szIPRemote[100];
            char szIPLocal[100];
            _msgIn.addrRemote.ToStringBuffer(szIPRemote, 100);
            _msgIn.addrLocal.ToStringBuffer(szIPLocal, 100);
            Logging::LogMsg(LL_VERBOSE, "recvfrom returns %d from %s on local interface %s", ret, szIPRemote, szIPLocal);
        }

        if (ret < 0)
        {
            // error
            continue;
        }

        if (_fNeedToExit)
        {
            break;
        }

        _spBufferIn->SetSize(ret);

        _msgIn.socketrole = pSocket->GetRole();

        // --------------------------------------------------------------------
        // now let's handle this message and get the response back out

        ProcessRequestAndSendResponse();
    }

    Logging::LogMsg(LL_DEBUG, "Thread exiting");
}

HRESULT CStunSocketThread::ProcessRequestAndSendResponse()
{
    HRESULT hr = S_OK;
    int sendret = -1;
    int sockout = -1;

    // Reset the reader object and re-attach the buffer
    _reader.Reset();
    _spBufferReader->SetSize(0);
    _reader.GetStream().Attach(_spBufferReader, true);

    // Consume the message and just validate that it is a stun message
    _reader.AddBytes(_spBufferIn->GetData(), _spBufferIn->GetSize());
    ChkIf(_reader.GetState() != CStunMessageReader::BodyValidated, E_FAIL);

    // msgIn and msgOut are already initialized

    Chk(CStunRequestHandler::ProcessRequest(_msgIn, _msgOut, &_tsa, _spAuth));

    ASSERT(_tsa.set[_msgOut.socketrole].fValid);
    ASSERT(_arrSendSockets[_msgOut.socketrole].IsValid());
    sockout = _arrSendSockets[_msgOut.socketrole].GetSocketHandle();
    ASSERT(sockout != -1);

    // find the socket that matches the role specified by msgOut
    sendret = ::sendto(sockout, _spBufferOut->GetData(), _spBufferOut->GetSize(), 0, _msgOut.addrDest.GetSockAddr(), _msgOut.addrDest.GetSockAddrLength());

    if (Logging::GetLogLevel() >= LL_VERBOSE)
    {
        Logging::LogMsg(LL_VERBOSE, "sendto returns %d (err == %d)\n", sendret, errno);
    }

Cleanup:
    return hr;
}

<commit_msg>Subsequent update<commit_after>/*
   Copyright 2011 John Selbie

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include "commonincludes.hpp"
#include "stuncore.h"
#include "stunsocket.h"
#include "stunsocketthread.h"
#include "recvfromex.h"

CStunSocketThread::CStunSocketThread() :
_arrSendSockets(), // zero-init
_fNeedToExit(false),
_pthread((pthread_t)-1),
_fThreadIsValid(false),
_rotation(0),
_tsa() // zero-init
{
    ClearSocketArray();
}

CStunSocketThread::~CStunSocketThread()
{
    SignalForStop(true);
    WaitForStopAndClose();
}

void CStunSocketThread::ClearSocketArray()
{
    _arrSendSockets = NULL;
    _socks.clear();
}

HRESULT CStunSocketThread::Init(CStunSocket* arrayOfFourSockets, TransportAddressSet* pTSA, IStunAuth* pAuth, SocketRole rolePrimaryRecv)
{
    HRESULT hr = S_OK;

    bool fSingleSocketRecv = ::IsValidSocketRole(rolePrimaryRecv);

    ChkIfA(_fThreadIsValid, E_UNEXPECTED);

    ChkIfA(arrayOfFourSockets == NULL, E_INVALIDARG);
    ChkIfA(pTSA == NULL, E_INVALIDARG);

    // if this thread was configured to listen on a single socket (aka "multi-threaded mode"), then
    // validate that it exists
    if (fSingleSocketRecv)
    {
        ChkIfA(arrayOfFourSockets[rolePrimaryRecv].IsValid()==false, E_UNEXPECTED);
    }

    _arrSendSockets = arrayOfFourSockets;

    // initialize the TSA thing
    _tsa = *pTSA;

    if (fSingleSocketRecv)
    {
        // only one socket to listen on
        _socks.push_back(&_arrSendSockets[rolePrimaryRecv]);
    }
    else
    {
        for (size_t i = 0; i < 4; i++)
        {
            if (_arrSendSockets[i].IsValid())
            {
                _socks.push_back(&_arrSendSockets[i]);
            }
        }
    }

    Chk(InitThreadBuffers());

    _fNeedToExit = false;

    _rotation = 0;

    _spAuth.Attach(pAuth);

Cleanup:
    return hr;
}

HRESULT CStunSocketThread::InitThreadBuffers()
{
    HRESULT hr = S_OK;

    _reader.Reset();

    _spBufferReader = CRefCountedBuffer(new CBuffer(MAX_STUN_MESSAGE_SIZE));
    _spBufferIn = CRefCountedBuffer(new CBuffer(MAX_STUN_MESSAGE_SIZE));
    _spBufferOut = CRefCountedBuffer(new CBuffer(MAX_STUN_MESSAGE_SIZE));

    _reader.GetStream().Attach(_spBufferReader, true);

    _msgIn.fConnectionOriented = false;
    _msgIn.pReader = &_reader;
    _msgOut.spBufferOut = _spBufferOut;

    return hr;
}

void CStunSocketThread::UninitThreadBuffers()
{
    _reader.Reset();
    _spBufferReader.reset();
    _spBufferIn.reset();
    _spBufferOut.reset();

    _msgIn.pReader = NULL;
    _msgOut.spBufferOut.reset();
}

HRESULT CStunSocketThread::Start()
{
    HRESULT hr = S_OK;
    int err = 0;

    ChkIfA(_fThreadIsValid, E_UNEXPECTED);

    ChkIfA(_socks.size() <= 0, E_FAIL);

    err = ::pthread_create(&_pthread, NULL, CStunSocketThread::ThreadFunction, this);

    ChkIfA(err != 0, ERRNO_TO_HRESULT(err));
    _fThreadIsValid = true;

Cleanup:
    return hr;
}

HRESULT CStunSocketThread::SignalForStop(bool fPostMessages)
{

    HRESULT hr = S_OK;

    _fNeedToExit = true;

    // have the socket send a message to itself
    // if another thread is sharing the same socket, this may wake that thread up to
    // but all the threads should be started and shutdown together
    if (fPostMessages)
    {
        for (size_t index = 0; index < _socks.size(); index++)
        {
            char data = 'x';

            ASSERT(_socks[index] != NULL);

            CSocketAddress addr(_socks[index]->GetLocalAddress());

            // If no specific adapter was binded to, IP will be 0.0.0.0
            // Linux evidently treats 0.0.0.0 IP as loopback (and works)
            // On Windows you can't send to 0.0.0.0. sendto will fail - switch to sending to localhost
            if (addr.IsIPAddressZero())
            {
                CSocketAddress addrLocal;
                CSocketAddress::GetLocalHost(addr.GetFamily(), &addrLocal);
                addrLocal.SetPort(addr.GetPort());
                addr = addrLocal;
            }

            ::sendto(_socks[index]->GetSocketHandle(), &data, 1, 0, addr.GetSockAddr(), addr.GetSockAddrLength());
        }
    }

    return hr;
}

HRESULT CStunSocketThread::WaitForStopAndClose()
{
    void* pRetValFromThread = NULL;

    if (_fThreadIsValid)
    {
        // now wait for the thread to exit
        pthread_join(_pthread, &pRetValFromThread);
    }

    _fThreadIsValid = false;
    _pthread = (pthread_t)-1;

    ClearSocketArray();

    UninitThreadBuffers();

    return S_OK;
}

// static
void* CStunSocketThread::ThreadFunction(void* pThis)
{
    ((CStunSocketThread*)pThis)->Run();
    return NULL;
}

// returns an index into _socks, not _arrSockets
CStunSocket* CStunSocketThread::WaitForSocketData()
{
    fd_set set = {};
    int nHighestSockValue = 0;
    int ret;
    CStunSocket* pReadySocket = NULL;
    UNREFERENCED_VARIABLE(ret); // only referenced in ASSERT
    size_t nSocketCount = _socks.size();

    // rotation gives another socket priority in the next loop
    _rotation = (_rotation + 1) % nSocketCount;
    ASSERT(_rotation >= 0);

    FD_ZERO(&set);

    for (size_t index = 0; index < nSocketCount; index++)
    {
        ASSERT(_socks[index] != NULL);
        int sock = _socks[index]->GetSocketHandle();
        ASSERT(sock != -1);
        FD_SET(sock, &set);
        nHighestSockValue = (sock > nHighestSockValue) ? sock : nHighestSockValue;
    }

    // wait indefinitely for a socket
    ret = ::select(nHighestSockValue+1, &set, NULL, NULL, NULL);

    ASSERT(ret > 0); // This will be a benign assert, and should never happen.  But I will want to know if it does

    // now figure out which socket just got data on it
    for (size_t index = 0; index < nSocketCount; index++)
    {
        int indexconverted = (index + _rotation) % nSocketCount;
        int sock = _socks[indexconverted]->GetSocketHandle();

        ASSERT(sock != -1);

        if (FD_ISSET(sock, &set))
        {
            pReadySocket = _socks[indexconverted];
            break;
        }
    }

    ASSERT(pReadySocket != NULL);

    return pReadySocket;
}

void CStunSocketThread::Run()
{
    size_t nSocketCount = _socks.size();
    bool fMultiSocketMode = (nSocketCount > 1);
    int recvflags = fMultiSocketMode ? MSG_DONTWAIT : 0;
    CStunSocket* pSocket = _socks[0];
    int ret;

    int sendsocketcount = 0;

    sendsocketcount += (int)(_tsa.set[RolePP].fValid);
    sendsocketcount += (int)(_tsa.set[RolePA].fValid);
    sendsocketcount += (int)(_tsa.set[RoleAP].fValid);
    sendsocketcount += (int)(_tsa.set[RoleAA].fValid);

    Logging::LogMsg(LL_DEBUG, "Starting listener thread (%d recv sockets, %d send sockets)", _socks.size(), sendsocketcount);

    while (_fNeedToExit == false)
    {

        if (fMultiSocketMode)
        {
            pSocket = WaitForSocketData();

            if (_fNeedToExit)
            {
                break;
            }

            ASSERT(pSocket != NULL);

            if (pSocket == NULL)
            {
                // just go back to waiting;
                continue;
            }
        }

        ASSERT(pSocket != NULL);

        // now receive the data
        _spBufferIn->SetSize(0);

        ret = ::recvfromex(pSocket->GetSocketHandle(), _spBufferIn->GetData(), _spBufferIn->GetAllocatedSize(), recvflags, &_msgIn.addrRemote, &_msgIn.addrLocal);

        // recvfromex no longer sets the port value on the local address
        if (ret >= 0)
        {
            _msgIn.addrLocal.SetPort(pSocket->GetLocalAddress().GetPort());
        }

        if (Logging::GetLogLevel() >= LL_VERBOSE)
        {
            char szIPRemote[100];
            char szIPLocal[100];
            _msgIn.addrRemote.ToStringBuffer(szIPRemote, 100);
            _msgIn.addrLocal.ToStringBuffer(szIPLocal, 100);
            Logging::LogMsg(LL_VERBOSE, "recvfrom returns %d from %s on local interface %s", ret, szIPRemote, szIPLocal);
        }

        if (ret < 0)
        {
            // error
            continue;
        }

        if (_fNeedToExit)
        {
            break;
        }

        _spBufferIn->SetSize(ret);

        _msgIn.socketrole = pSocket->GetRole();

        // --------------------------------------------------------------------
        // now let's handle this message and get the response back out

        ProcessRequestAndSendResponse();
    }

    Logging::LogMsg(LL_DEBUG, "Thread exiting");
}

HRESULT CStunSocketThread::ProcessRequestAndSendResponse()
{
    HRESULT hr = S_OK;
    int sendret = -1;
    int sockout = -1;

    // Reset the reader object and re-attach the buffer
    _reader.Reset();
    _spBufferReader->SetSize(0);
    _reader.GetStream().Attach(_spBufferReader, true);

    // Consume the message and just validate that it is a stun message
    _reader.AddBytes(_spBufferIn->GetData(), _spBufferIn->GetSize());
    ChkIf(_reader.GetState() != CStunMessageReader::BodyValidated, E_FAIL);

    // msgIn and msgOut are already initialized

    Chk(CStunRequestHandler::ProcessRequest(_msgIn, _msgOut, &_tsa, _spAuth));

    ASSERT(_tsa.set[_msgOut.socketrole].fValid);
    ASSERT(_arrSendSockets[_msgOut.socketrole].IsValid());
    sockout = _arrSendSockets[_msgOut.socketrole].GetSocketHandle();
    ASSERT(sockout != -1);

    // find the socket that matches the role specified by msgOut
    sendret = ::sendto(sockout, _spBufferOut->GetData(), _spBufferOut->GetSize(), 0, _msgOut.addrDest.GetSockAddr(), _msgOut.addrDest.GetSockAddrLength());

    if (Logging::GetLogLevel() >= LL_VERBOSE)
    {
        Logging::LogMsg(LL_VERBOSE, "sendto returns %d (err == %d)\n", sendret, errno);
    }

Cleanup:
    return hr;
}

<|endoftext|>


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

#include <vector>

#include "OpenType/Builder.h"
#include "TextProcessorTester.h"

using namespace std;
using namespace SheenFigure::Tester;
using namespace SheenFigure::Tester::OpenType;

void TextProcessorTester::testSingleSubstitution()
{
    Builder builder;

    /* Test the first format. */
    {
        /* Test with unmatching glyph. */
        testSubstitution(builder.createSingleSubst({ 0 }, 0), { 1 }, { 1 });
        /* Test with zero delta. */
        testSubstitution(builder.createSingleSubst({ 1 }, 0), { 1 }, { 1 });
        /* Test with positive delta. */
        testSubstitution(builder.createSingleSubst({ 1 }, 99), { 1 }, { 100 });
        /* Test with negative delta. */
        testSubstitution(builder.createSingleSubst({ 100 }, -99), { 100 }, { 1 });
        /* Test with opposite delta. */
        testSubstitution(builder.createSingleSubst({ 1 }, -1), { 1 }, { 0 });
    }

    /* Test the second format. */
    {
        /* Test with unmatching glyph. */
        testSubstitution(builder.createSingleSubst({ {0, 0} }), { 1 }, { 1 });
        /* Test with zero glyph. */
        testSubstitution(builder.createSingleSubst({ {0, 1} }), { 0 }, { 1 });
        /* Test with zero substitution. */
        testSubstitution(builder.createSingleSubst({ {1, 0} }), { 1 }, { 0 });
        /* Test with same substitution. */
        testSubstitution(builder.createSingleSubst({ {1, 1} }), { 1 }, { 1 });
        /* Test with a different substitution. */
        testSubstitution(builder.createSingleSubst({ {1, 100} }), { 1 }, { 100 });
    }
}

void TextProcessorTester::testMultipleSubstitution()
{
    Builder builder;

    /* Test with unmatching glyph. */
    testSubstitution(builder.createMultipleSubst({ {0, { 1, 2, 3 }} }), { 1 }, { 1 });
    /* Test with no glyph. */
    testSubstitution(builder.createMultipleSubst({ {1, { }} }), { 1 }, { 1 });
    /* Test with zero glyph. */
    testSubstitution(builder.createMultipleSubst({ {0, { 1 }} }), { 0 }, { 1 });
    /* Test with zero substitution. */
    testSubstitution(builder.createMultipleSubst({ {1, { 0 }} }), { 1 }, { 0 });
    /* Test with same substitution. */
    testSubstitution(builder.createMultipleSubst({ {1, { 1 }} }), { 1 }, { 1 });
    /* Test with different single substitution. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100 }} }), { 1 }, { 100 });
    /* Test with different two substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 200 }} }), { 1 }, { 100, 200 });
    /* Test with different multiple substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 200, 300 }} }), { 1 }, { 100, 200, 300 });
    /* Test with multiple substitutions having input glyph at the start. */
    testSubstitution(builder.createMultipleSubst({ {1, { 1, 200, 300 }} }), { 1 }, { 1, 200, 300 });
    /* Test with multiple substitutions having input glyph at the middle. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 1, 300 }} }), { 1 }, { 100, 1, 300 });
    /* Test with multiple substitutions having input glyph at the end. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 200, 1 }} }), { 1 }, { 100, 200, 1 });
    /* Test with multiple substitutions having input glyph everywhere. */
    testSubstitution(builder.createMultipleSubst({ {1, { 1, 1, 1 }} }), { 1 }, { 1, 1, 1 });
    /* Test with multiple repeating substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 100, 100 }} }), { 1 }, { 100, 100, 100 });
    /* Test with multiple zero substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 0, 0, 0 }} }), { 1 }, { 0, 0, 0 });
}

void TextProcessorTester::testAlternateSubstitution()
{
    Builder builder;

    /* Test with unmatching glyph. */
    testSubstitution(builder.createAlternateSubst({ {0, { 0 }} }), { 1 }, { 1 });
    /* Test with zero glyph. */
    testSubstitution(builder.createAlternateSubst({ {0, { 1 }} }), { 0 }, { 1 });
    /* Test with zero substitution. */
    testSubstitution(builder.createAlternateSubst({ {1, { 0 }} }), { 1 }, { 0 });
    /* Test with same substitution. */
    testSubstitution(builder.createAlternateSubst({ {1, { 1 }} }), { 1 }, { 1 });
    /* Test with a different substitution. */
    testSubstitution(builder.createAlternateSubst({ {1, { 100 }} }), { 1 }, { 100 });
}

void TextProcessorTester::testLigatureSubstitution()
{
    Builder builder;

    /* Test with unmatching glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 0} }), { 1 }, { 1 });
    /* Test with zero glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 0 }, 1} }), { 0 }, { 1 });
    /* Test with zero substitution. */
    testSubstitution(builder.createLigatureSubst({ {{ 1 }, 0} }), { 1 }, { 0 });
    /* Test with same substitution. */
    testSubstitution(builder.createLigatureSubst({ {{ 1 }, 1} }), { 1 }, { 1 });
    /* Test with different substitution. */
    testSubstitution(builder.createLigatureSubst({ {{ 1 }, 100} }), { 1 }, { 100 });
    /* Test with two different glyphs. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2 }, 100} }), { 1, 2 }, { 100 });
    /* Test with multiple different glyphs. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 100} }), { 1, 2, 3 }, { 100 });
    /* Test with multiple glyphs translating to first input glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 1} }), { 1, 2, 3 }, { 1 });
    /* Test with multiple glyphs translating to middle input glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 2} }), { 1, 2, 3 }, { 2 });
    /* Test with multiple glyphs translating to last input glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 3} }), { 1, 2, 3 }, { 3 });
    /* Test with multiple same glyphs translating to itself. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 1, 1 }, 1} }), { 1, 1, 1 }, { 1 });
    /* Test with multiple same glyphs translating to a different glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 1, 1 }, 100} }), { 1, 1, 1 }, { 100 });
    /* Test with multiple zero glyphs. */
    testSubstitution(builder.createLigatureSubst({ {{ 0, 0, 0 }, 100} }), { 0, 0, 0 }, { 100 });
}

void TextProcessorTester::testReverseChainContextSubstitution()
{
    Builder builder;

    /* Test with unmatching input glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 } }, { { 31 } }),
                     { 21, 0, 31 }, { 21, 0, 31 });
    /* Test with unmatching first backtrack glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 }, { 22} , { 23 } }, { { 31 } }),
                     { 0, 22, 23, 1, 31 }, { 0, 22, 23, 1, 31 });
    /* Test with unmatching middle backtrack glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 }, { 22 }, { 23 } }, { { 31 } }),
                     { 21, 0, 23, 1, 31 }, { 21, 0, 23, 1, 31 });
    /* Test with unmatching last backtrack glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 }, { 22 }, { 23 } }, { { 31 } }),
                     { 21, 22, 0, 1, 31 }, { 21, 22, 0, 1, 31 });
    /* Test with unmatching first lookahead glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 } }, { { 31 }, { 32 }, { 33 } }),
                     { 21, 1, 0, 32, 33 }, { 21, 1, 0, 32, 33 });
    /* Test with unmatching middle lookahead glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 } }, { { 31 }, { 32 }, { 33 } }),
                     { 21, 1, 31, 0, 33 }, { 21, 1, 31, 0, 33 });
    /* Test with unmatching last lookahead glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 } }, { { 31 }, { 32 }, { 33 } }),
                     { 21, 1, 31, 32, 0 }, { 21, 1, 31, 32, 0 });
    /* Test by providing all matching glyphs. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 }, { 22 }, { 23 } }, { { 31 }, { 32 }, { 33 } }),
                     { 21, 22, 23, 1, 31, 32, 33 }, { 21, 22, 23, 11, 31, 32, 33 });
    /* Test by providing no backtrack and lookahead glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { }, { }),
                     { 1 }, { 11 });
    /* Test by providing reverse dependent sequence. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11}, {2, 12}, {3, 13} },
                        { { 1, 2, 21 } },
                        { { 12, 13, 31 } }),
                     { 21, 1, 2, 3, 31 }, { 21, 11, 12, 13, 31 });
}
<commit_msg>[test] Wrote test cases for different alternates<commit_after>/*
 * Copyright (C) 2016-2018 Muhammad Tayyab Akram
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <vector>

#include "OpenType/Builder.h"
#include "TextProcessorTester.h"

using namespace std;
using namespace SheenFigure::Tester;
using namespace SheenFigure::Tester::OpenType;

void TextProcessorTester::testSingleSubstitution()
{
    Builder builder;

    /* Test the first format. */
    {
        /* Test with unmatching glyph. */
        testSubstitution(builder.createSingleSubst({ 0 }, 0), { 1 }, { 1 });
        /* Test with zero delta. */
        testSubstitution(builder.createSingleSubst({ 1 }, 0), { 1 }, { 1 });
        /* Test with positive delta. */
        testSubstitution(builder.createSingleSubst({ 1 }, 99), { 1 }, { 100 });
        /* Test with negative delta. */
        testSubstitution(builder.createSingleSubst({ 100 }, -99), { 100 }, { 1 });
        /* Test with opposite delta. */
        testSubstitution(builder.createSingleSubst({ 1 }, -1), { 1 }, { 0 });
    }

    /* Test the second format. */
    {
        /* Test with unmatching glyph. */
        testSubstitution(builder.createSingleSubst({ {0, 0} }), { 1 }, { 1 });
        /* Test with zero glyph. */
        testSubstitution(builder.createSingleSubst({ {0, 1} }), { 0 }, { 1 });
        /* Test with zero substitution. */
        testSubstitution(builder.createSingleSubst({ {1, 0} }), { 1 }, { 0 });
        /* Test with same substitution. */
        testSubstitution(builder.createSingleSubst({ {1, 1} }), { 1 }, { 1 });
        /* Test with a different substitution. */
        testSubstitution(builder.createSingleSubst({ {1, 100} }), { 1 }, { 100 });
    }
}

void TextProcessorTester::testMultipleSubstitution()
{
    Builder builder;

    /* Test with unmatching glyph. */
    testSubstitution(builder.createMultipleSubst({ {0, { 1, 2, 3 }} }), { 1 }, { 1 });
    /* Test with no glyph. */
    testSubstitution(builder.createMultipleSubst({ {1, { }} }), { 1 }, { 1 });
    /* Test with zero glyph. */
    testSubstitution(builder.createMultipleSubst({ {0, { 1 }} }), { 0 }, { 1 });
    /* Test with zero substitution. */
    testSubstitution(builder.createMultipleSubst({ {1, { 0 }} }), { 1 }, { 0 });
    /* Test with same substitution. */
    testSubstitution(builder.createMultipleSubst({ {1, { 1 }} }), { 1 }, { 1 });
    /* Test with different single substitution. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100 }} }), { 1 }, { 100 });
    /* Test with different two substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 200 }} }), { 1 }, { 100, 200 });
    /* Test with different multiple substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 200, 300 }} }), { 1 }, { 100, 200, 300 });
    /* Test with multiple substitutions having input glyph at the start. */
    testSubstitution(builder.createMultipleSubst({ {1, { 1, 200, 300 }} }), { 1 }, { 1, 200, 300 });
    /* Test with multiple substitutions having input glyph at the middle. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 1, 300 }} }), { 1 }, { 100, 1, 300 });
    /* Test with multiple substitutions having input glyph at the end. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 200, 1 }} }), { 1 }, { 100, 200, 1 });
    /* Test with multiple substitutions having input glyph everywhere. */
    testSubstitution(builder.createMultipleSubst({ {1, { 1, 1, 1 }} }), { 1 }, { 1, 1, 1 });
    /* Test with multiple repeating substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 100, 100 }} }), { 1 }, { 100, 100, 100 });
    /* Test with multiple zero substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 0, 0, 0 }} }), { 1 }, { 0, 0, 0 });
}

void TextProcessorTester::testAlternateSubstitution()
{
    Builder builder;

    /* Test with unmatching glyph. */
    testSubstitution(builder.createAlternateSubst({ {0, { 0 }} }), { 1 }, { 1 });
    /* Test with zero glyph. */
    testSubstitution(builder.createAlternateSubst({ {0, { 1 }} }), { 0 }, { 1 });
    /* Test with zero substitution. */
    testSubstitution(builder.createAlternateSubst({ {1, { 0 }} }), { 1 }, { 0 });
    /* Test with same substitution. */
    testSubstitution(builder.createAlternateSubst({ {1, { 1 }} }), { 1 }, { 1 });
    /* Test with a different substitution. */
    testSubstitution(builder.createAlternateSubst({ {1, { 100 }} }), { 1 }, { 100 });
    /* Test with an alternate at the start. */
    testSubstitution(builder.createAlternateSubst({ {1, { 100, 200, 300 }} }), { 1 }, { 100 }, { }, 1);
    /* Test with an alternate in the middle. */
    testSubstitution(builder.createAlternateSubst({ {1, { 100, 200, 300 }} }), { 1 }, { 200 }, { }, 2);
    /* Test with an alternate at the end. */
    testSubstitution(builder.createAlternateSubst({ {1, { 100, 200, 300 }} }), { 1 }, { 300 }, { }, 3);
}

void TextProcessorTester::testLigatureSubstitution()
{
    Builder builder;

    /* Test with unmatching glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 0} }), { 1 }, { 1 });
    /* Test with zero glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 0 }, 1} }), { 0 }, { 1 });
    /* Test with zero substitution. */
    testSubstitution(builder.createLigatureSubst({ {{ 1 }, 0} }), { 1 }, { 0 });
    /* Test with same substitution. */
    testSubstitution(builder.createLigatureSubst({ {{ 1 }, 1} }), { 1 }, { 1 });
    /* Test with different substitution. */
    testSubstitution(builder.createLigatureSubst({ {{ 1 }, 100} }), { 1 }, { 100 });
    /* Test with two different glyphs. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2 }, 100} }), { 1, 2 }, { 100 });
    /* Test with multiple different glyphs. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 100} }), { 1, 2, 3 }, { 100 });
    /* Test with multiple glyphs translating to first input glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 1} }), { 1, 2, 3 }, { 1 });
    /* Test with multiple glyphs translating to middle input glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 2} }), { 1, 2, 3 }, { 2 });
    /* Test with multiple glyphs translating to last input glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 3} }), { 1, 2, 3 }, { 3 });
    /* Test with multiple same glyphs translating to itself. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 1, 1 }, 1} }), { 1, 1, 1 }, { 1 });
    /* Test with multiple same glyphs translating to a different glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 1, 1 }, 100} }), { 1, 1, 1 }, { 100 });
    /* Test with multiple zero glyphs. */
    testSubstitution(builder.createLigatureSubst({ {{ 0, 0, 0 }, 100} }), { 0, 0, 0 }, { 100 });
}

void TextProcessorTester::testReverseChainContextSubstitution()
{
    Builder builder;

    /* Test with unmatching input glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 } }, { { 31 } }),
                     { 21, 0, 31 }, { 21, 0, 31 });
    /* Test with unmatching first backtrack glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 }, { 22} , { 23 } }, { { 31 } }),
                     { 0, 22, 23, 1, 31 }, { 0, 22, 23, 1, 31 });
    /* Test with unmatching middle backtrack glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 }, { 22 }, { 23 } }, { { 31 } }),
                     { 21, 0, 23, 1, 31 }, { 21, 0, 23, 1, 31 });
    /* Test with unmatching last backtrack glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 }, { 22 }, { 23 } }, { { 31 } }),
                     { 21, 22, 0, 1, 31 }, { 21, 22, 0, 1, 31 });
    /* Test with unmatching first lookahead glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 } }, { { 31 }, { 32 }, { 33 } }),
                     { 21, 1, 0, 32, 33 }, { 21, 1, 0, 32, 33 });
    /* Test with unmatching middle lookahead glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 } }, { { 31 }, { 32 }, { 33 } }),
                     { 21, 1, 31, 0, 33 }, { 21, 1, 31, 0, 33 });
    /* Test with unmatching last lookahead glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 } }, { { 31 }, { 32 }, { 33 } }),
                     { 21, 1, 31, 32, 0 }, { 21, 1, 31, 32, 0 });
    /* Test by providing all matching glyphs. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { { 21 }, { 22 }, { 23 } }, { { 31 }, { 32 }, { 33 } }),
                     { 21, 22, 23, 1, 31, 32, 33 }, { 21, 22, 23, 11, 31, 32, 33 });
    /* Test by providing no backtrack and lookahead glyph. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11} }, { }, { }),
                     { 1 }, { 11 });
    /* Test by providing reverse dependent sequence. */
    testSubstitution(builder.createRevChainSubst(
                        { {1, 11}, {2, 12}, {3, 13} },
                        { { 1, 2, 21 } },
                        { { 12, 13, 31 } }),
                     { 21, 1, 2, 3, 31 }, { 21, 11, 12, 13, 31 });
}
<|endoftext|>


<commit_before>#include "stdafx.h"

#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>

template < typename _inputIterator, typename _unaryFuntion >
void each_tag( _inputIterator _from, _inputIterator _to, typename _inputIterator::value_type _delimiter, _unaryFuntion _function )
{
	_inputIterator _first = _from, _cur = _from;
	for ( ; _from != _to; ++_from )
	{
		if ( *_from == _delimiter )
		{
			if ( _first != _cur )
			{
				_function( std::basic_string<typename _inputIterator::value_type>( _first, _cur ));
			}
			_first = ++_cur;
		}
		else
		{
			++_cur;
		}
	}
	if ( _first != _cur )
	{
		_function( std::basic_string<typename _inputIterator::value_type>( _first, _cur ));
	}
}

template < typename _inputIterator, typename _outputIterator>
void each_tag_push( _inputIterator _from, _inputIterator _to, typename _inputIterator::value_type _delimiter, _outputIterator _output )
{
	_inputIterator _first = _from, _cur = _from;
	for ( ; _from != _to; ++_from )
	{
		if ( *_from == _delimiter )
		{
			if ( _first != _cur )
			{
				_output = std::basic_string<typename _inputIterator::value_type>( _first, _cur );
			}
			_first = ++_cur;
		}
		else
		{
			++_cur;
		}
	}
	if ( _first != _cur )
	{
		_output = std::basic_string<typename _inputIterator::value_type>( _first, _cur );
	}
}

// in process

template < typename _inputIterator, typename _unaryFuntion >
void each_tag( _inputIterator _from, _inputIterator _to, const std::basic_string<typename _inputIterator::value_type> _delimiter, _unaryFuntion _function )
{
	//std::basic_string<typename _inputIterator::value_type> tag;
	//std::basic_string<typename _inputIterator::value_type> searchFor( _delimiter );

	size_t sizeCurrent = 0;
	size_t stringSize = _delimiter.size();
//	while ( _delimiter[ stringSize ] != 0 )
//	{
//		++stringSize;
//	};

	_inputIterator _first = _from, _cur = _from;

	for ( ; _from != _to; ++_from )
	{
		if ( *_from == _delimiter[ sizeCurrent ] )
		{
			tag.push_back( *_from );
		}
		else
		{

			if ( tag.size() > 0 )
			{
				_function( tag );
			}
			tag.clear();
			sizeCurrent = 0;
		}
	}
	if ( tag.size() > 0 )
	{
		_function( tag );
	}
}

template < typename _inputIterator, typename _unaryFuntion >
void each_tag( _inputIterator _from, _inputIterator _to, const typename _inputIterator::value_type* _delimiter, _unaryFuntion _function )
{
	std::basic_string<typename _inputIterator::value_type> tag;
	//std::basic_string<typename _inputIterator::value_type> searchFor( _delimiter );

	size_t sizeCurrent = 0, stringSize = 0;
	while ( _delimiter[ stringSize ] != 0 )
	{
		++stringSize;
	};

	_inputIterator _first = _from, _cur = _from;

	for ( ; _from != _to; ++_from )
	{
		if ( *_from == _delimiter[ sizeCurrent ] )
		{
			tag.push_back( *_from );
		}
		else
		{

			if ( tag.size() > 0 )
			{
				_function( tag );
			}
			tag.clear();
			sizeCurrent = 0;
		}
	}
	if ( tag.size() > 0 )
	{
		_function( tag );
	}
}

int main(int argc, char* argv[])
{
	std::string test( " 498924782h7 nuncinsiunuc 77826376276572  nu736736473467 sdfsdfw344224 d" );
	std::wstring wtest( L" 498nu924782h7 nuncinsiunc 778263762765nu72  73673nuu6473467 fefsdf22234 " );

#pragma region single char slices

	size_t count = 0;
	std::cout << "char:" << std::endl;
	each_tag( test.begin(), test.end(), ' ', [&count]( std::string& tag )
	{
		std::cout << tag << std::endl;
		++count;
	});
	std::cout << "total tags: " << count << std::endl;

	std::cout << std::endl << "char + outputIterator:" << std::endl;
	std::vector< std::string > slices;
	std::back_insert_iterator<std::vector< std::string >>  output( slices );
	each_tag_push( test.begin(), test.end(), ' ', output ); // <- char to wchar implict convertsion is possible

	for_each( slices.begin(), slices.end(), []( std::string& tag )
	{
		std::cout << tag << std::endl;
	} );
	std::cout << "total tags: " << slices.size() << std::endl;

	size_t wcount = 0;
	std::cout << std::endl << "wchar:" << std::endl;
	each_tag( wtest.begin(), wtest.end(), L' ', [ &wcount ]( std::wstring& tag )
	{
		std::wcout << tag << std::endl;
		++wcount;
	});
	std::cout << "total tags: " << wcount << std::endl;

	std::cout << std::endl << "wchar + outputIterator:" << std::endl;
	std::vector< std::wstring > wslices;
	std::back_insert_iterator<std::vector< std::wstring >> woutput( wslices );
	each_tag_push( wtest.begin(), wtest.end(), L' ', woutput );

	for_each( wslices.begin(), wslices.end(), []( std::wstring& tag )
	{
		std::wcout << tag << std::endl;
	} );
	std::cout << "total tags: " << wslices.size() << std::endl;
#pragma endregion

	/*
	size_t mcount = 0;
	std::cout << "char:" << std::endl;
	each_tag( test.begin(), test.end(), "nu", [ &mcount ]( std::string& tag )
	{
		std::cout << tag << std::endl;
		++mcount;
	} );
	std::cout << "total tags: " << count << std::endl;
	*/
	return 0;
}

<commit_msg>multichar slicer<commit_after>#include "stdafx.h"

#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>

template < typename _inputIterator, typename _outputIterator>
void each_slice_push( _inputIterator _begin, _inputIterator _end, typename _inputIterator::value_type _delimiter, _outputIterator _output )
{
	_inputIterator _first = _begin, _cur = _begin;
	for ( ; _begin != _end; ++_begin )
	{
		if ( *_begin == _delimiter )
		{
			if ( _first != _cur )
			{
				_output = std::basic_string<typename _inputIterator::value_type>( _first, _cur );
			}
			_first = ++_cur;
		}
		else
		{
			++_cur;
		}
	}
	if ( _first != _cur )
	{
		_output = std::basic_string<typename _inputIterator::value_type>( _first, _cur );
	}
}

template < typename _inputIterator, typename _unaryFunction >
void each_slice( _inputIterator _begin, _inputIterator _end, typename _inputIterator::value_type _delimiter, _unaryFunction _function )
{
	_inputIterator _first = _begin, _cur = _begin;
	for ( ; _begin != _end; ++_begin )
	{
		if ( *_begin == _delimiter )
		{
			if ( _first != _cur )
			{
				_function( std::basic_string<typename _inputIterator::value_type>( _first, _cur ));
			}
			_first = ++_cur;
		}
		else
		{
			++_cur;
		}
	}
	if ( _first != _cur )
	{
		_function( std::basic_string<typename _inputIterator::value_type>( _first, _cur ));
	}
}

template < typename _inputIterator, typename _unaryFunction >
void each_slice( _inputIterator _begin, _inputIterator _end, typename _inputIterator::value_type* _delimiter, _unaryFunction _function )
{
	size_t indexCurrent = 0, stringSize = 0;
	while ( _delimiter[ stringSize ] != 0 )
	{
		++stringSize;
	};

	if ( stringSize > 1 )
	{
		--stringSize;
		_inputIterator _first = _begin, _final = _begin, _last, _fromPattern;
		for ( ; _begin != _end; ++_begin )
		{
			if ( *_begin == _delimiter[ indexCurrent ] )
			{
				_last = _fromPattern = _begin;
				while ( ++_fromPattern != _end && *_fromPattern == _delimiter[ ++indexCurrent ] )
				{
					if ( indexCurrent == stringSize )
					{
						if ( _first != _last )
						{
							_function( std::basic_string<typename _inputIterator::value_type>( _first, _last ) );
						}
						_begin = _fromPattern++;
						_final = _first = _fromPattern;
						break;
					}
				};
				indexCurrent = 0;
			}
		}

		// last slice
		if ( _final != _end )
		{
			_function( std::basic_string<typename _inputIterator::value_type>( _final, _end ) );
		}
	}
	else if ( stringSize == 1 )
	{
		// only one symbol in delimiter, use simplier variant
		each_slice( _begin, _end, _delimiter[ 0 ], _function );
	}
	/*
	else
	{
		// only one slice, no delimiters supplied
		_function( std::basic_string<typename _inputIterator::value_type>( _begin, _end ));
	}
	*/
}

int main(int argc, char* argv[])
{
	std::string test( "cpp.kw1 source.cpp.kw2 source.cpp.kw3 sourcesource.cpp.kw4_source.cpp.co1 source.cpp.co2 source.cpp source.cpp.es0 source" );
	std::wstring wtest( test.begin(), test.end() );

	size_t count = 0;

#pragma region single char slices

	std::cout << std::endl << "char (' '):" << std::endl;
	each_slice( test.begin(), test.end(), ' ', [&count]( std::string& tag )
	{
		std::cout << tag << std::endl;
		++count;
	});
	std::cout << "total tags: " << count << std::endl;

	std::cout << std::endl << "char + outputIterator (' '):" << std::endl;
	std::vector< std::string > slices;
	std::back_insert_iterator<std::vector< std::string >>  output( slices );
	each_slice_push( test.begin(), test.end(), ' ', output ); // <- char to wchar implict convertsion is possible

	for_each( slices.begin(), slices.end(), []( std::string& tag )
	{
		std::cout << tag << std::endl;
	} );
	std::cout << "total tags: " << slices.size() << std::endl;

	count = 0;
	std::cout << std::endl << std::endl << "wchar (' '):" << std::endl;
	each_slice( wtest.begin(), wtest.end(), ' ', [ &count ]( std::wstring& tag )
	{
		std::wcout << tag << std::endl;
		++count;
	});
	std::cout << "total tags: " << count << std::endl;

	std::cout << std::endl << "wchar + outputIterator (' '):" << std::endl;
	std::vector< std::wstring > wslices;
	std::back_insert_iterator<std::vector< std::wstring >> woutput( wslices );
	each_slice_push( wtest.begin(), wtest.end(), L' ', woutput );

	for_each( wslices.begin(), wslices.end(), []( std::wstring& tag )
	{
		std::wcout << tag << std::endl;
	} );
	std::cout << "total tags: " << wslices.size() << std::endl;
#pragma endregion

#pragma region multi chars slices

	count = 0;
	std::cout << std::endl << "multi char 1 (cpp):" << std::endl;
	each_slice( test.begin(), test.end(), "cpp", [ &count ]( std::string& tag )
	{
		std::cout << tag << std::endl;
		++count;
	} );
	std::cout << "total tags: " << count << std::endl;

	count = 0;
	std::cout << std::endl << "multi char 2 (source):" << std::endl;
	each_slice( test.begin(), test.end(), "source", [ &count ]( std::string& tag )
	{
		std::cout << tag << std::endl;
		++count;
	} );
	std::cout << "total tags: " << count << std::endl;

	count = 0;
	std::cout << std::endl << "multi char as one (' '):" << std::endl;
	each_slice( test.begin(), test.end(), " ", [ &count ]( std::string& tag )
	{
		std::cout << tag << std::endl;
		++count;
	} );
	std::cout << "total tags: " << count << std::endl;

#pragma endregion

	return 0;
}

<|endoftext|>


<commit_before>#include "mantella_bits/optimisationAlgorithm/trajectoryBasedOptimisationAlgorithm/hillClimbing.hpp"

// Mantella
#include "mantella_bits/helper/assert.hpp"

// TODO Add restarting
namespace mant {
  HillClimbing::HillClimbing(
      const std::shared_ptr<OptimisationProblem> optimisationProblem)
      : TrajectoryBasedOptimisationAlgorithm(optimisationProblem) {
    setMinimalStepSize(arma::zeros<arma::Col<double>>(numberOfDimensions_));
    setMaximalStepSize((getUpperBounds() - getLowerBounds()) * 0.1);
  }

  void HillClimbing::optimiseImplementation() {
    ++numberOfIterations_;

    bestParameter_ = initialParameter_;
    bestObjectiveValue_ = getObjectiveValue(initialParameter_);

    while (!isFinished() && !isTerminated()) {
      ++numberOfIterations_;

      arma::Col<double> candidateParameter = getRandomNeighbour(bestParameter_, minimalStepSize_, maximalStepSize_);

      const arma::Col<arma::uword>& belowLowerBound = arma::find(candidateParameter < getLowerBounds());
      const arma::Col<arma::uword>& aboveUpperBound = arma::find(candidateParameter > getUpperBounds());

      candidateParameter.elem(belowLowerBound) = getLowerBounds().elem(belowLowerBound);
      candidateParameter.elem(aboveUpperBound) = getUpperBounds().elem(aboveUpperBound);

      updateBestParameter(candidateParameter, getObjectiveValue(candidateParameter));
    }
  }

  void HillClimbing::setMinimalStepSize(
      const arma::Col<double>& minimalStepSize) {
    verify(minimalStepSize.n_elem == numberOfDimensions_, "The number of dimensions of the minimal step size must match the number of dimensions of the optimisation problem.");
    verify(arma::all(minimalStepSize >= 0), "The minimal step size must be at least 0 for each dimension.");

    minimalStepSize_ = minimalStepSize;
  }

  void HillClimbing::setMaximalStepSize(
      const arma::Col<double>& maximalStepSize) {
    verify(maximalStepSize.n_elem == numberOfDimensions_, "The number of dimensions of the maximal step size must match the number of dimensions of the optimisation problem.");
    verify(arma::all(maximalStepSize > 0), "The maximal step size must be strict greater than 0 for each dimension.");

    maximalStepSize_ = maximalStepSize;
  }

  std::string HillClimbing::toString() const {
    return "hill_climbing";
  }
}
<commit_msg>Fixed code style format<commit_after>#include "mantella_bits/optimisationAlgorithm/trajectoryBasedOptimisationAlgorithm/hillClimbing.hpp"

// Mantella
#include "mantella_bits/helper/assert.hpp"

// TODO Add restarting
namespace mant {
  HillClimbing::HillClimbing(
      const std::shared_ptr<OptimisationProblem> optimisationProblem)
      : TrajectoryBasedOptimisationAlgorithm(optimisationProblem) {
    setMinimalStepSize(arma::zeros<arma::Col<double>>(numberOfDimensions_));
    setMaximalStepSize((getUpperBounds() - getLowerBounds()) * 0.1);
  }

  void HillClimbing::optimiseImplementation() {
    ++numberOfIterations_;

    bestParameter_ = initialParameter_;
    bestObjectiveValue_ = getObjectiveValue(initialParameter_);

    while (!isFinished() && !isTerminated()) {
      ++numberOfIterations_;

      arma::Col<double> candidateParameter = getRandomNeighbour(bestParameter_, minimalStepSize_, maximalStepSize_);

      const arma::Col<arma::uword>& belowLowerBound = arma::find(candidateParameter < getLowerBounds());
      const arma::Col<arma::uword>& aboveUpperBound = arma::find(candidateParameter > getUpperBounds());

      candidateParameter.elem(belowLowerBound) = getLowerBounds().elem(belowLowerBound);
      candidateParameter.elem(aboveUpperBound) = getUpperBounds().elem(aboveUpperBound);

      updateBestParameter(candidateParameter, getObjectiveValue(candidateParameter));
    }
  }

  void HillClimbing::setMinimalStepSize(
      const arma::Col<double>& minimalStepSize) {
    verify(minimalStepSize.n_elem == numberOfDimensions_, "The number of dimensions of the minimal step size must match the number of dimensions of the optimisation problem.");
    verify(arma::all(minimalStepSize >= 0), "The minimal step size must be at least 0 for each dimension.");

    minimalStepSize_ = minimalStepSize;
  }

  void HillClimbing::setMaximalStepSize(
      const arma::Col<double>& maximalStepSize) {
    verify(maximalStepSize.n_elem == numberOfDimensions_, "The number of dimensions of the maximal step size must match the number of dimensions of the optimisation problem.");
    verify(arma::all(maximalStepSize > 0), "The maximal step size must be strict greater than 0 for each dimension.");

    maximalStepSize_ = maximalStepSize;
  }

  std::string HillClimbing::toString() const {
    return "hill_climbing";
  }
}
<|endoftext|>