<commit_before>#include <Python.h>
#include <string>
#include <vector>

#include "cc/misc/unicode.h"
#include "cc/analysis/analyzer.h"

using std::string;
using std::vector;

namespace {

char PHRASER_DOC[] =
    "Python extension that detects phrases in text.\n";

Analyzer* ANALYZER = NULL;

char INIT_DOC[] =
    "phrase config texts -> error str or None.\n"
    "\n"
    "Initialize the module.  Must call this first.\n"
    "\n"
    "    phrase_config_ff = [...]\n"
    "    phrases = map(lambda f: open(f).read(), phrase_config_ff)\n"
    "    err = phraser.Init(phrases)\n"
    "    assert not err\n";

PyObject* Init(PyObject* self, PyObject* args) {
    // Get args.
    PyObject* list;
    if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &list)) {
        return NULL;
    }

    // Extract phrase configs from list.
    vector<string> phrase_configs;
    Py_ssize_t length = PyList_Size(list);
    for (Py_ssize_t i = 0; i < length; ++i) {
        PyObject* s = PyList_GetItem(list, i);
        if (!PyString_Check(s)) {
            return PyUnicode_FromFormat(
                "[Phraser] List item at index %ld was not a string.", i);
        }
        phrase_configs.emplace_back(PyString_AsString(s));
    }

    // Allocate the Analyzer.
    if (!ANALYZER) {
        ANALYZER = new Analyzer();
    }

    // Call Init().
    string error;
    if (!ANALYZER->Init(phrase_configs, &error)) {
        return PyUnicode_FromString(error.data());
    }

    return Py_None;
}

char TO_D_DOC[] =
    "-> dict.\n"
    "\n"
    "Dump my state as a recursive dict.\n"
    "\n"
    "You can call phrase_detector_json_to_html.py to visualize the output as\n"
    "pretty HTML.\n"
    "\n"
    "    d = phrasser.to_d()\n"
    "    print d\n";

PyObject* ToD(PyObject* self, PyObject* args) {
    return NULL;
}

char ANALYZE_DOC[] =
    "text, options -> phrase detection result dict, error str.\n"
    "\n"
    "Analyze the text.  Returns a pair.  Either the dict or the error str\n"
    "will be None.\n"
    "\n"
    "    text = u'This is a comment.'\n"
    "    options = {\n"
    "        'destutter_max_consecutive': 3,\n"
    "        'replace_html_entities: True,\n"
    "    }\n"
    "    err = phraser.Analyze(text, options)\n"
    "    assert not err\n";

bool AnalysisOptionsFromDict(
        PyObject* obj, AnalysisOptions* options, string* error) {
    Py_ssize_t pos = 0;
    PyObject* key;
    PyObject* value;
    while (PyDict_Next(obj, &pos, &key, &value)) {
        if (!PyString_Check(key)) {
            *error = "[Phraser] Analysis options key is not a string.";
            return false;
        }
        const char* key_s = PyString_AsString(key);
        if (!strcmp(key_s, "destutter_max_consecutive")) {
            if (!PyInt_Check(value)) {
                *error = "[Phraser] Analysis option "
                         "'destutter_max_consecutive' is an integer.";
                return false;
            }
            Py_ssize_t size = PyInt_AsSsize_t(value);
            options->destutter_max_consecutive = static_cast<size_t>(size);
        } else if (!strcmp(key_s, "replace_html_entities")) {
            if (!PyBool_Check(value)) {
                *error = "[Phraser] Analysis option 'replace_html_entities' is "
                         "a bool.";
                return false;
            }
            options->replace_html_entities = PyObject_IsTrue(value);
        } else {
            *error = "[Phraser] Unknown analysis option.";
            return false;
        }
    }
    return true;
}

PyObject* UnicodeFromUstring(const ustring& s) {
#ifdef Py_UNICODE_WIDE
    // UCS 4 (eg, Linux).
    return PyUnicode_FromUnicode(s.data(), s.size());
#else
    // UCS 2 (eg, Mac OS X).
    vector<Py_UNICODE> v;
    for (auto& c : s) {
        v.emplace_back(static_cast<Py_UNICODE>(c));
    }
    return PyUnicode_FromUnicode(v.data(), v.size());
#endif
}

PyObject* MakeDict(const vector<PyObject*>& keys,
                   const vector<PyObject*>& values) {
    if (keys.size() != values.size()) {
        return NULL;
    }

    PyObject* d = PyDict_New();
    for (auto i = 0u; i < keys.size(); ++i) {
        PyObject* k = keys[i];
        PyObject* v = values[i];
        if (!k) {
            return NULL;
        }
        if (!v) {
            return NULL;
        }
        if (PyDict_SetItem(d, k, v)) {
            return NULL;
        }
    }

    return d;
}

// Returned dicts look like
//
// {
//     'original_text':  'Some texxxxxxxt',
//     'clean_text':     'Some texxxt',
//     'tokens':         ['some', 'text'],
//     'phrase_results': [...],
// }
//
// where 'phrase_results' is a list like
//
// {
//     'phrase_name': 'threat_statement',
//     'subsequence_names': ['subject', 'aux', 'verb'],
//     'index_lists': [...]
// }
PyObject* DictFromAnalysisResult(const AnalysisResult& result, string* error) {
    PyObject* key;
    PyObject* value;
    vector<PyObject*> keys;
    vector<PyObject*> values;

    key = PyString_FromString("original_text");
    value = UnicodeFromUstring(result.original_text);
    keys.emplace_back(key);
    values.emplace_back(value);

    key = PyString_FromString("clean_text");
    value = UnicodeFromUstring(result.clean_text);
    keys.emplace_back(key);
    values.emplace_back(value);

    key = PyString_FromString("tokens");
    value = PyList_New(result.tokens.size());
    for (auto i = 0u; i < result.tokens.size(); ++i) {
        PyObject* token = PyString_FromString(result.tokens[i].data());
        PyList_SET_ITEM(value, i, token);
    }
    keys.emplace_back(key);
    values.emplace_back(value);

    key = PyString_FromString("phrase_matches");
    value = PyList_New(result.phrase_results.size());
    for (auto i = 0u; i < result.phrase_results.size(); ++i) {
        auto& phrase_result = result.phrase_results[i];

        vector<PyObject*> tmp_keys;
        vector<PyObject*> tmp_values;

        PyObject* tmp_key = PyString_FromString("phrase_name");
        PyObject* tmp_value = PyString_FromString(
            phrase_result.phrase_name.data());
        tmp_keys.emplace_back(tmp_key);
        tmp_values.emplace_back(tmp_value);

        tmp_key = PyString_FromString("subsequence_names");
        tmp_value = PyList_New(phrase_result.piece_names.size());
        for (auto j = 0u; j < phrase_result.piece_names.size(); ++j) {
            PyObject* subsequence_name =
                PyString_FromString(phrase_result.piece_names[j].data());
            PyList_SET_ITEM(tmp_value, j, subsequence_name);
        }
        tmp_keys.emplace_back(tmp_key);
        tmp_values.emplace_back(tmp_value);

        tmp_key = PyString_FromString("index_lists");
        tmp_value = PyList_New(phrase_result.matches.size());
        for (auto j = 0u; j < phrase_result.matches.size(); ++j) {
            auto& match = phrase_result.matches[j];
            PyObject* index_list = PyList_New(
                match.piece_begin_indexes.size() + 1);
            for (auto k = 0u; k < match.piece_begin_indexes.size(); ++k) {
                PyObject* item = PyInt_FromLong(match.piece_begin_indexes[k]);
                PyList_SET_ITEM(index_list, k, item);
            }
            PyObject* item = PyInt_FromLong(match.end_excl);
            PyList_SET_ITEM(index_list, match.piece_begin_indexes.size(), item);
            PyList_SET_ITEM(tmp_value, j, index_list);
        }
        tmp_keys.emplace_back(tmp_key);
        tmp_values.emplace_back(tmp_value);

        PyObject* tmp_d = MakeDict(tmp_keys, tmp_values);
        PyList_SET_ITEM(value, i, tmp_d);
    }
    keys.emplace_back(key);
    values.emplace_back(value);

    return MakeDict(keys, values);
}

PyObject* MakeTuple(PyObject* first, PyObject* second) {
    PyObject* r = PyTuple_New(2);
    PyTuple_SetItem(r, 0, first);
    PyTuple_SetItem(r, 1, second);
    return r;
}

PyObject* Analyze(PyObject* self, PyObject* args) {
    // Get args.
    PyObject* py_text;
    PyObject* options_dict;
    if (!PyArg_ParseTuple(args, "UO!", &py_text, &PyDict_Type, &options_dict)) {
        return NULL;
    }

    // Check if initialized.
    if (!ANALYZER) {
        return MakeTuple(
            Py_None, PyUnicode_FromString("[Phraser] Call init() first."));
    }

    // Get the input text to analyze.
    ustring text;
    Py_ssize_t size = PyUnicode_GetSize(py_text);
    for (Py_ssize_t i = 0; i < size; ++i) {
        text.emplace_back(PyUnicode_AsUnicode(py_text)[i]);
    }

    // Set the analysis options.
    AnalysisOptions options;
    string error;
    if (!AnalysisOptionsFromDict(options_dict, &options, &error)) {
        return MakeTuple(
            Py_None, PyUnicode_FromString(error.data()));
    }

    // Analyze the text.
    AnalysisResult result;
    if (!ANALYZER->Analyze(text, options, &result, &error)) {
        return MakeTuple(
            Py_None, PyUnicode_FromString(error.data()));
    }

    // Convert the results to a python dict.
    PyObject* result_dict;
    if (!(result_dict = DictFromAnalysisResult(result, &error))) {
        return MakeTuple(
            Py_None, PyUnicode_FromString(error.data()));
    }

    return MakeTuple(result_dict, Py_None);
}

PyMethodDef PHRASER_METHODS[] = {
    {"init",    Init,    METH_VARARGS, INIT_DOC},
    {"to_d",    ToD,     METH_VARARGS, TO_D_DOC},
    {"analyze", Analyze, METH_VARARGS, ANALYZE_DOC},
};

}  // namespace

extern "C" void initphraser(void);

PyMODINIT_FUNC initphraser(void) {
    Py_InitModule3("phraser", PHRASER_METHODS, PHRASER_DOC);
}
<commit_msg>Python extension method defs: add NULL def at end.<commit_after>#include <Python.h>
#include <string>
#include <vector>

#include "cc/misc/unicode.h"
#include "cc/analysis/analyzer.h"

using std::string;
using std::vector;

namespace {

char PHRASER_DOC[] =
    "Python extension that detects phrases in text.\n";

Analyzer* ANALYZER = NULL;

char INIT_DOC[] =
    "phrase config texts -> error str or None.\n"
    "\n"
    "Initialize the module.  Must call this first.\n"
    "\n"
    "    phrase_config_ff = [...]\n"
    "    phrases = map(lambda f: open(f).read(), phrase_config_ff)\n"
    "    err = phraser.Init(phrases)\n"
    "    assert not err\n";

PyObject* Init(PyObject* self, PyObject* args) {
    // Get args.
    PyObject* list;
    if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &list)) {
        return NULL;
    }

    // Extract phrase configs from list.
    vector<string> phrase_configs;
    Py_ssize_t length = PyList_Size(list);
    for (Py_ssize_t i = 0; i < length; ++i) {
        PyObject* s = PyList_GetItem(list, i);
        if (!PyString_Check(s)) {
            return PyUnicode_FromFormat(
                "[Phraser] List item at index %ld was not a string.", i);
        }
        phrase_configs.emplace_back(PyString_AsString(s));
    }

    // Allocate the Analyzer.
    if (!ANALYZER) {
        ANALYZER = new Analyzer();
    }

    // Call Init().
    string error;
    if (!ANALYZER->Init(phrase_configs, &error)) {
        return PyUnicode_FromString(error.data());
    }

    return Py_None;
}

char TO_D_DOC[] =
    "-> dict.\n"
    "\n"
    "Dump my state as a recursive dict.\n"
    "\n"
    "You can call phrase_detector_json_to_html.py to visualize the output as\n"
    "pretty HTML.\n"
    "\n"
    "    d = phrasser.to_d()\n"
    "    print d\n";

PyObject* ToD(PyObject* self, PyObject* args) {
    return NULL;
}

char ANALYZE_DOC[] =
    "text, options -> phrase detection result dict, error str.\n"
    "\n"
    "Analyze the text.  Returns a pair.  Either the dict or the error str\n"
    "will be None.\n"
    "\n"
    "    text = u'This is a comment.'\n"
    "    options = {\n"
    "        'destutter_max_consecutive': 3,\n"
    "        'replace_html_entities: True,\n"
    "    }\n"
    "    err = phraser.Analyze(text, options)\n"
    "    assert not err\n";

bool AnalysisOptionsFromDict(
        PyObject* obj, AnalysisOptions* options, string* error) {
    Py_ssize_t pos = 0;
    PyObject* key;
    PyObject* value;
    while (PyDict_Next(obj, &pos, &key, &value)) {
        if (!PyString_Check(key)) {
            *error = "[Phraser] Analysis options key is not a string.";
            return false;
        }
        const char* key_s = PyString_AsString(key);
        if (!strcmp(key_s, "destutter_max_consecutive")) {
            if (!PyInt_Check(value)) {
                *error = "[Phraser] Analysis option "
                         "'destutter_max_consecutive' is an integer.";
                return false;
            }
            Py_ssize_t size = PyInt_AsSsize_t(value);
            options->destutter_max_consecutive = static_cast<size_t>(size);
        } else if (!strcmp(key_s, "replace_html_entities")) {
            if (!PyBool_Check(value)) {
                *error = "[Phraser] Analysis option 'replace_html_entities' is "
                         "a bool.";
                return false;
            }
            options->replace_html_entities = PyObject_IsTrue(value);
        } else {
            *error = "[Phraser] Unknown analysis option.";
            return false;
        }
    }
    return true;
}

PyObject* UnicodeFromUstring(const ustring& s) {
#ifdef Py_UNICODE_WIDE
    // UCS 4 (eg, Linux).
    return PyUnicode_FromUnicode(s.data(), s.size());
#else
    // UCS 2 (eg, Mac OS X).
    vector<Py_UNICODE> v;
    for (auto& c : s) {
        v.emplace_back(static_cast<Py_UNICODE>(c));
    }
    return PyUnicode_FromUnicode(v.data(), v.size());
#endif
}

PyObject* MakeDict(const vector<PyObject*>& keys,
                   const vector<PyObject*>& values) {
    if (keys.size() != values.size()) {
        return NULL;
    }

    PyObject* d = PyDict_New();
    for (auto i = 0u; i < keys.size(); ++i) {
        PyObject* k = keys[i];
        PyObject* v = values[i];
        if (!k) {
            return NULL;
        }
        if (!v) {
            return NULL;
        }
        if (PyDict_SetItem(d, k, v)) {
            return NULL;
        }
    }

    return d;
}

// Returned dicts look like
//
// {
//     'original_text':  'Some texxxxxxxt',
//     'clean_text':     'Some texxxt',
//     'tokens':         ['some', 'text'],
//     'phrase_results': [...],
// }
//
// where 'phrase_results' is a list like
//
// {
//     'phrase_name': 'threat_statement',
//     'subsequence_names': ['subject', 'aux', 'verb'],
//     'index_lists': [...]
// }
PyObject* DictFromAnalysisResult(const AnalysisResult& result, string* error) {
    PyObject* key;
    PyObject* value;
    vector<PyObject*> keys;
    vector<PyObject*> values;

    key = PyString_FromString("original_text");
    value = UnicodeFromUstring(result.original_text);
    keys.emplace_back(key);
    values.emplace_back(value);

    key = PyString_FromString("clean_text");
    value = UnicodeFromUstring(result.clean_text);
    keys.emplace_back(key);
    values.emplace_back(value);

    key = PyString_FromString("tokens");
    value = PyList_New(result.tokens.size());
    for (auto i = 0u; i < result.tokens.size(); ++i) {
        PyObject* token = PyString_FromString(result.tokens[i].data());
        PyList_SET_ITEM(value, i, token);
    }
    keys.emplace_back(key);
    values.emplace_back(value);

    key = PyString_FromString("phrase_matches");
    value = PyList_New(result.phrase_results.size());
    for (auto i = 0u; i < result.phrase_results.size(); ++i) {
        auto& phrase_result = result.phrase_results[i];

        vector<PyObject*> tmp_keys;
        vector<PyObject*> tmp_values;

        PyObject* tmp_key = PyString_FromString("phrase_name");
        PyObject* tmp_value = PyString_FromString(
            phrase_result.phrase_name.data());
        tmp_keys.emplace_back(tmp_key);
        tmp_values.emplace_back(tmp_value);

        tmp_key = PyString_FromString("subsequence_names");
        tmp_value = PyList_New(phrase_result.piece_names.size());
        for (auto j = 0u; j < phrase_result.piece_names.size(); ++j) {
            PyObject* subsequence_name =
                PyString_FromString(phrase_result.piece_names[j].data());
            PyList_SET_ITEM(tmp_value, j, subsequence_name);
        }
        tmp_keys.emplace_back(tmp_key);
        tmp_values.emplace_back(tmp_value);

        tmp_key = PyString_FromString("index_lists");
        tmp_value = PyList_New(phrase_result.matches.size());
        for (auto j = 0u; j < phrase_result.matches.size(); ++j) {
            auto& match = phrase_result.matches[j];
            PyObject* index_list = PyList_New(
                match.piece_begin_indexes.size() + 1);
            for (auto k = 0u; k < match.piece_begin_indexes.size(); ++k) {
                PyObject* item = PyInt_FromLong(match.piece_begin_indexes[k]);
                PyList_SET_ITEM(index_list, k, item);
            }
            PyObject* item = PyInt_FromLong(match.end_excl);
            PyList_SET_ITEM(index_list, match.piece_begin_indexes.size(), item);
            PyList_SET_ITEM(tmp_value, j, index_list);
        }
        tmp_keys.emplace_back(tmp_key);
        tmp_values.emplace_back(tmp_value);

        PyObject* tmp_d = MakeDict(tmp_keys, tmp_values);
        PyList_SET_ITEM(value, i, tmp_d);
    }
    keys.emplace_back(key);
    values.emplace_back(value);

    return MakeDict(keys, values);
}

PyObject* MakeTuple(PyObject* first, PyObject* second) {
    PyObject* r = PyTuple_New(2);
    PyTuple_SetItem(r, 0, first);
    PyTuple_SetItem(r, 1, second);
    return r;
}

PyObject* Analyze(PyObject* self, PyObject* args) {
    // Get args.
    PyObject* py_text;
    PyObject* options_dict;
    if (!PyArg_ParseTuple(args, "UO!", &py_text, &PyDict_Type, &options_dict)) {
        return NULL;
    }

    // Check if initialized.
    if (!ANALYZER) {
        return MakeTuple(
            Py_None, PyUnicode_FromString("[Phraser] Call init() first."));
    }

    // Get the input text to analyze.
    ustring text;
    Py_ssize_t size = PyUnicode_GetSize(py_text);
    for (Py_ssize_t i = 0; i < size; ++i) {
        text.emplace_back(PyUnicode_AsUnicode(py_text)[i]);
    }

    // Set the analysis options.
    AnalysisOptions options;
    string error;
    if (!AnalysisOptionsFromDict(options_dict, &options, &error)) {
        return MakeTuple(
            Py_None, PyUnicode_FromString(error.data()));
    }

    // Analyze the text.
    AnalysisResult result;
    if (!ANALYZER->Analyze(text, options, &result, &error)) {
        return MakeTuple(
            Py_None, PyUnicode_FromString(error.data()));
    }

    // Convert the results to a python dict.
    PyObject* result_dict;
    if (!(result_dict = DictFromAnalysisResult(result, &error))) {
        return MakeTuple(
            Py_None, PyUnicode_FromString(error.data()));
    }

    return MakeTuple(result_dict, Py_None);
}

PyMethodDef PHRASER_METHODS[] = {
    {"init",    Init,    METH_VARARGS, INIT_DOC},
    {"to_d",    ToD,     METH_VARARGS, TO_D_DOC},
    {"analyze", Analyze, METH_VARARGS, ANALYZE_DOC},
    {nullptr,   nullptr, 0,            nullptr},
};

}  // namespace

extern "C" void initphraser(void);

PyMODINIT_FUNC initphraser(void) {
    Py_InitModule3("phraser", PHRASER_METHODS, PHRASER_DOC);
}
<|endoftext|>


<commit_before>#include <catch.hpp>
#include <chrono>
#include "../physics/phys_system.h"
#include "../physics/vec2.h"
#include "../physics/ball.h"

using clk = std::chrono::system_clock;
using namespace std::chrono_literals;
using namespace std::chrono;

SCENARIO("id progression") {
	GIVEN("empty system") {
		phys_system s;
		const vec2 p1{1,1}, p2{22,22}, p3{333,333};

		WHEN("add 3 balls") {
			auto i1 = s.add(p1),
				i2 = s.add(p2),
				i3 = s.add(p3);
			THEN("i1 < i2 < i3") {
				REQUIRE(i1 < i2);
				REQUIRE(i2 < i3);
			}
		}

		WHEN("add 3 balls one by one and immediately get them") {
			auto i1 = s.add(p1);
			auto b1 = s.get(i1);
			auto i2 = s.add(p2);
			auto b2 = s.get(i2);
			auto i3 = s.add(p3);
			auto b3 = s.get(i3);
			THEN("they are on same positions as originally") {
				REQUIRE(b1.pos() == p1);
				REQUIRE(b2.pos() == p2);
				REQUIRE(b3.pos() == p3);
			}
		}
	}
}

SCENARIO("single ball system") {
	GIVEN("empty system") {
		phys_system system;
		SECTION("size is 0")
			REQUIRE(system.size() == 0);

		WHEN("add a ball") {
			const vec2 original_pos{5.2, 5.3};
			const auto i = system.add(original_pos);
			THEN("size increased")
				REQUIRE(system.size() == 1);
			WHEN("get ball by id") {
				const auto b = system.get(i);
				THEN("it is same ball") {
					REQUIRE(b.pos() == original_pos);
				}
			}

			AND_WHEN("simulate for a second at 60fps") {
				constexpr auto frames = 60;
				constexpr milliseconds delta = 1s/frames;
				for (int i = 0; i < frames; ++i) {
					system.simulate(delta);
				}
				THEN("ball is in same position")
					REQUIRE(system.get(i).pos() == original_pos);
			}
		}
	}
}

SCENARIO("three-ball-line system") {
	GIVEN("empty system") {
		phys_system system;
		SECTION("size is 0")
			REQUIRE(system.size() == 0);

		WHEN("add line of three balls") {
			const vec2 original_1{-10,0},
				original_m{0,0},
				original_2{10,0};
			const auto b1 = system.add(original_1),
				bm = system.add(original_m),
				b2 = system.add(original_2);
			THEN("their ids differ") {
				REQUIRE(b1 != b2);
				REQUIRE(b1 != bm);
				REQUIRE(b2 != bm);
			}
			THEN("size increased")
				REQUIRE(system.size() == 3);
			AND_WHEN("simulate for a second at 60fps") {
				constexpr auto frames = 60;
				constexpr milliseconds delta = 1s/frames;
				for (int i = 0; i < frames; ++i) {
					system.simulate(delta);
				}
				THEN("middle ball is in same position")
					REQUIRE(system.get(bm).pos() == original_m);
				THEN("side ones have moved for same distance") {
					const auto b1_pos = system.get(b1).pos(),
						b2_pos = system.get(b2).pos();
					auto b1_vec = vec2_from_two_points(original_1, b1_pos),
						b2_vec = vec2_from_two_points(original_2, {10,0});
					REQUIRE(b1_vec.length() == b2_vec.length());
					SECTION("and are on same line")
						REQUIRE(b1_vec == b2_vec);
					SECTION("and the distance is positive")
						REQUIRE(glm::length(b1_vec) > 0);
				}
			}
		}
	}
}
<commit_msg>fix phys_system "on same line" test<commit_after>#include <catch.hpp>
#include <chrono>
#include "../physics/phys_system.h"
#include "../physics/vec2.h"
#include "../physics/ball.h"
#include <glm/gtx/vector_angle.hpp>

using clk = std::chrono::system_clock;
using namespace std::chrono_literals;
using namespace std::chrono;

SCENARIO("id progression") {
	GIVEN("empty system") {
		phys_system s;
		const vec2 p1{1,1}, p2{22,22}, p3{333,333};

		WHEN("add 3 balls") {
			auto i1 = s.add(p1),
				i2 = s.add(p2),
				i3 = s.add(p3);
			THEN("i1 < i2 < i3") {
				REQUIRE(i1 < i2);
				REQUIRE(i2 < i3);
			}
		}

		WHEN("add 3 balls one by one and immediately get them") {
			auto i1 = s.add(p1);
			auto b1 = s.get(i1);
			auto i2 = s.add(p2);
			auto b2 = s.get(i2);
			auto i3 = s.add(p3);
			auto b3 = s.get(i3);
			THEN("they are on same positions as originally") {
				REQUIRE(b1.pos() == p1);
				REQUIRE(b2.pos() == p2);
				REQUIRE(b3.pos() == p3);
			}
		}
	}
}

SCENARIO("single ball system") {
	GIVEN("empty system") {
		phys_system system;
		SECTION("size is 0")
			REQUIRE(system.size() == 0);

		WHEN("add a ball") {
			const vec2 original_pos{5.2, 5.3};
			const auto i = system.add(original_pos);
			THEN("size increased")
				REQUIRE(system.size() == 1);
			WHEN("get ball by id") {
				const auto b = system.get(i);
				THEN("it is same ball") {
					REQUIRE(b.pos() == original_pos);
				}
			}

			AND_WHEN("simulate for a second at 60fps") {
				constexpr auto frames = 60;
				constexpr milliseconds delta = 1s/frames;
				for (int i = 0; i < frames; ++i) {
					system.simulate(delta);
				}
				THEN("ball is in same position")
					REQUIRE(system.get(i).pos() == original_pos);
			}
		}
	}
}

SCENARIO("three-ball-line system") {
	GIVEN("empty system") {
		phys_system system;
		SECTION("size is 0")
			REQUIRE(system.size() == 0);

		WHEN("add line of three balls") {
			const vec2 original_1{-10,0},
				original_m{0,0},
				original_2{10,0};
			const auto b1 = system.add(original_1),
				bm = system.add(original_m),
				b2 = system.add(original_2);
			THEN("their ids differ") {
				REQUIRE(b1 != b2);
				REQUIRE(b1 != bm);
				REQUIRE(b2 != bm);
			}
			THEN("size increased")
				REQUIRE(system.size() == 3);
			AND_WHEN("simulate for a second at 60fps") {
				constexpr auto frames = 60;
				constexpr milliseconds delta = 1s/frames;
				for (int i = 0; i < frames; ++i) {
					system.simulate(delta);
				}
				THEN("middle ball is in same position")
					REQUIRE(system.get(bm).pos() == original_m);
				THEN("side ones have moved for same distance") {
					const auto b1_pos = system.get(b1).pos(),
						b2_pos = system.get(b2).pos();
					auto b1_vec = vec2_from_two_points(original_1, b1_pos),
						b2_vec = -vec2_from_two_points(original_2, b2_pos);
					REQUIRE(b1_vec.length() == b2_vec.length());
					SECTION("and are on same line")
						REQUIRE(glm::angle(b1_vec, b2_vec) == Approx(0));
					SECTION("and the distance is positive")
						REQUIRE(glm::length(b1_vec) > 0);
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>#include <map>
#include <algorithm>
#include "cantera/oneD/Domain1D.h"

#include "cantera/oneD/refine.h"

using namespace std;

namespace Cantera
{

template<class M>
bool has_key(const M& m, size_t j)
{
    if (m.find(j) != m.end()) {
        return true;
    }
    return false;
}

static void r_drawline()
{
    string s(78,'#');
    s += '\n';
    writelog(s.c_str());
}

/**
 * Return the square root of machine precision.
 */
static doublereal eps()
{
    doublereal e = 1.0;
    while (1.0 + e != 1.0) {
        e *= 0.5;
    }
    return sqrt(e);
}

Refiner::Refiner(Domain1D& domain) :
    m_ratio(10.0), m_slope(0.8), m_curve(0.8), m_prune(-0.001),
    m_min_range(0.01), m_domain(&domain), m_npmax(3000)
{
    m_nv = m_domain->nComponents();
    m_active.resize(m_nv, true);
    m_thresh = eps();
}

int Refiner::analyze(size_t n, const doublereal* z,
                     const doublereal* x)
{

    if (n >= m_npmax) {
        writelog("max number of grid points reached ("+int2str(m_npmax)+".\n");
        return -2;
    }

    if (m_domain->nPoints() <= 1) {
        //writelog("can't refine a domain with 1 point: "+m_domain->id()+"\n");
        return 0;
    }

    m_loc.clear();
    m_c.clear();
    m_keep.clear();

    m_keep[0] = 1;
    m_keep[n-1] = 1;

    m_nv = m_domain->nComponents();

    // check consistency
    if (n != m_domain->nPoints()) {
        throw CanteraError("analyze","inconsistent");
    }

    /**
     * find locations where cell size ratio is too large.
     */
    size_t j;
    string name;
    doublereal vmin, vmax, smin, smax, aa, ss;
    doublereal dmax, r;
    vector_fp v(n), s(n-1);

    vector_fp dz(n-1);
    for (j = 0; j < n-1; j++) {
        dz[j] = z[j+1] - z[j];
    }

    for (size_t i = 0; i < m_nv; i++) {
        if (m_active[i]) {
            name = m_domain->componentName(i);
            //writelog("refine: examining "+name+"\n");
            // get component i at all points
            for (j = 0; j < n; j++) {
                v[j] = value(x, i, j);
            }

            // slope of component i
            for (j = 0; j < n-1; j++)
                s[j] = (value(x, i, j+1) - value(x, i, j))/
                       (z[j+1] - z[j]);

            // find the range of values and slopes

            vmin = *min_element(v.begin(), v.end());
            vmax = *max_element(v.begin(), v.end());
            smin = *min_element(s.begin(), s.end());
            smax = *max_element(s.begin(), s.end());

            // max absolute values of v and s
            aa = std::max(fabs(vmax), fabs(vmin));
            ss = std::max(fabs(smax), fabs(smin));

            // refine based on component i only if the range of v is
            // greater than a fraction 'min_range' of max |v|. This
            // eliminates components that consist of small fluctuations
            // on a constant background.

            if ((vmax - vmin) > m_min_range*aa) {

                // maximum allowable difference in value between
                // adjacent points.

                dmax = m_slope*(vmax - vmin) + m_thresh;
                for (j = 0; j < n-1; j++) {
                    r = fabs(v[j+1] - v[j])/dmax;
                    if (r > 1.0) {
                        m_loc[j] = 1;
                        m_c[name] = 1;
                        //if (int(m_loc.size()) + n > m_npmax) goto done;
                    }
                    if (r >= m_prune) {
                        m_keep[j] = 1;
                        m_keep[j+1] = 1;
                    } else {
                        //writelog(string("r = ")+fp2str(r)+"\n");
                        if (m_keep[j] == 0) {
                            //if (m_keep[j-1] > -1 && m_keep[j+1] > -1)
                            m_keep[j] = -1;
                        }
                        //if (m_keep[j+1] == 0) m_keep[j+1] = -1;
                    }
                }
            }

            // refine based on the slope of component i only if the
            // range of s is greater than a fraction 'min_range' of max
            // |s|. This eliminates components that consist of small
            // fluctuations on a constant slope background.

            if ((smax - smin) > m_min_range*ss) {

                // maximum allowable difference in slope between
                // adjacent points.
                dmax = m_curve*(smax - smin); // + 0.5*m_curve*(smax + smin);
                for (j = 0; j < n-2; j++) {
                    r = fabs(s[j+1] - s[j]) / (dmax + m_thresh/dz[j]);
                    if (r > 1.0) {
                        m_c[name] = 1;
                        m_loc[j] = 1;
                        m_loc[j+1] = 1;
                        //if (int(m_loc.size()) + n > m_npmax) goto done;
                    }
                    if (r >= m_prune) {
                        m_keep[j+1] = 1;
                    } else {
                        //writelog(string("r slope = ")+fp2str(r)+"\n");
                        if (m_keep[j+1] == 0) {
                            //if (m_keep[j] > -1 && m_keep[j+2] > -1)
                            m_keep[j+1] = -1;
                        }
                    }
                }
            }

        }
    }

    for (j = 1; j < n-1; j++) {
        if (dz[j] > m_ratio*dz[j-1]) {
            m_loc[j] = 1;
            m_c["point "+int2str(j)] = 1;
        }
        if (dz[j] < dz[j-1]/m_ratio) {
            m_loc[j-1] = 1;
            m_c["point "+int2str(j-1)] = 1;
        }
        //if (m_loc.size() + n > m_npmax) goto done;
    }

    //done:
    //m_did_analysis = true;
    return int(m_loc.size());
}

double Refiner::value(const double* x, size_t i, size_t j)
{
    return x[m_domain->index(i,j)];
}

void Refiner::show()
{
    int nnew = static_cast<int>(m_loc.size());
    if (nnew > 0) {
        r_drawline();
        writelog(string("Refining grid in ") +
                 m_domain->id()+".\n"
                 +"    New points inserted after grid points ");
        map<size_t, int>::const_iterator b = m_loc.begin();
        for (; b != m_loc.end(); ++b) {
            writelog(int2str(b->first)+" ");
        }
        writelog("\n");
        writelog("    to resolve ");
        map<string, int>::const_iterator bb = m_c.begin();
        for (; bb != m_c.end(); ++bb) {
            writelog(string(bb->first)+" ");
        }
        writelog("\n");
    } else if (m_domain->nPoints() > 1) {
        writelog("no new points needed in "+m_domain->id()+"\n");
        //writelog("curve = "+fp2str(m_curve)+"\n");
        //writelog("slope = "+fp2str(m_slope)+"\n");
        //writelog("prune = "+fp2str(m_prune)+"\n");
    }
}

int Refiner::getNewGrid(int n, const doublereal* z,
                        int nn, doublereal* zn)
{
    int j;
    int nnew = static_cast<int>(m_loc.size());
    if (nnew + n > nn) {
        throw CanteraError("Refine::getNewGrid",
                           "array size too small.");
        return -1;
    }

    int jn = 0;
    if (m_loc.empty()) {
        copy(z, z + n,  zn);
        return 0;
    }

    for (j = 0; j < n - 1; j++) {
        zn[jn] = z[j];
        jn++;
        if (has_key(m_loc, j)) {
            zn[jn] = 0.5*(z[j] + z[j+1]);
            jn++;
        }
    }
    zn[jn] = z[n-1];
    return 0;
}
}
<commit_msg>Replaced a couple of unnecessary local functions in refine.cpp<commit_after>#include "cantera/oneD/refine.h"
#include "cantera/oneD/Domain1D.h"

#include <algorithm>
#include <limits>

using namespace std;

namespace Cantera
{

static void r_drawline()
{
    string s(78,'#');
    s += '\n';
    writelog(s.c_str());
}

Refiner::Refiner(Domain1D& domain) :
    m_ratio(10.0), m_slope(0.8), m_curve(0.8), m_prune(-0.001),
    m_min_range(0.01), m_domain(&domain), m_npmax(3000)
{
    m_nv = m_domain->nComponents();
    m_active.resize(m_nv, true);
    m_thresh = std::sqrt(std::numeric_limits<double>::epsilon());
}

int Refiner::analyze(size_t n, const doublereal* z,
                     const doublereal* x)
{

    if (n >= m_npmax) {
        writelog("max number of grid points reached ("+int2str(m_npmax)+".\n");
        return -2;
    }

    if (m_domain->nPoints() <= 1) {
        //writelog("can't refine a domain with 1 point: "+m_domain->id()+"\n");
        return 0;
    }

    m_loc.clear();
    m_c.clear();
    m_keep.clear();

    m_keep[0] = 1;
    m_keep[n-1] = 1;

    m_nv = m_domain->nComponents();

    // check consistency
    if (n != m_domain->nPoints()) {
        throw CanteraError("analyze","inconsistent");
    }

    /**
     * find locations where cell size ratio is too large.
     */
    size_t j;
    string name;
    doublereal vmin, vmax, smin, smax, aa, ss;
    doublereal dmax, r;
    vector_fp v(n), s(n-1);

    vector_fp dz(n-1);
    for (j = 0; j < n-1; j++) {
        dz[j] = z[j+1] - z[j];
    }

    for (size_t i = 0; i < m_nv; i++) {
        if (m_active[i]) {
            name = m_domain->componentName(i);
            //writelog("refine: examining "+name+"\n");
            // get component i at all points
            for (j = 0; j < n; j++) {
                v[j] = value(x, i, j);
            }

            // slope of component i
            for (j = 0; j < n-1; j++)
                s[j] = (value(x, i, j+1) - value(x, i, j))/
                       (z[j+1] - z[j]);

            // find the range of values and slopes

            vmin = *min_element(v.begin(), v.end());
            vmax = *max_element(v.begin(), v.end());
            smin = *min_element(s.begin(), s.end());
            smax = *max_element(s.begin(), s.end());

            // max absolute values of v and s
            aa = std::max(fabs(vmax), fabs(vmin));
            ss = std::max(fabs(smax), fabs(smin));

            // refine based on component i only if the range of v is
            // greater than a fraction 'min_range' of max |v|. This
            // eliminates components that consist of small fluctuations
            // on a constant background.

            if ((vmax - vmin) > m_min_range*aa) {

                // maximum allowable difference in value between
                // adjacent points.

                dmax = m_slope*(vmax - vmin) + m_thresh;
                for (j = 0; j < n-1; j++) {
                    r = fabs(v[j+1] - v[j])/dmax;
                    if (r > 1.0) {
                        m_loc[j] = 1;
                        m_c[name] = 1;
                        //if (int(m_loc.size()) + n > m_npmax) goto done;
                    }
                    if (r >= m_prune) {
                        m_keep[j] = 1;
                        m_keep[j+1] = 1;
                    } else {
                        //writelog(string("r = ")+fp2str(r)+"\n");
                        if (m_keep[j] == 0) {
                            //if (m_keep[j-1] > -1 && m_keep[j+1] > -1)
                            m_keep[j] = -1;
                        }
                        //if (m_keep[j+1] == 0) m_keep[j+1] = -1;
                    }
                }
            }

            // refine based on the slope of component i only if the
            // range of s is greater than a fraction 'min_range' of max
            // |s|. This eliminates components that consist of small
            // fluctuations on a constant slope background.

            if ((smax - smin) > m_min_range*ss) {

                // maximum allowable difference in slope between
                // adjacent points.
                dmax = m_curve*(smax - smin); // + 0.5*m_curve*(smax + smin);
                for (j = 0; j < n-2; j++) {
                    r = fabs(s[j+1] - s[j]) / (dmax + m_thresh/dz[j]);
                    if (r > 1.0) {
                        m_c[name] = 1;
                        m_loc[j] = 1;
                        m_loc[j+1] = 1;
                        //if (int(m_loc.size()) + n > m_npmax) goto done;
                    }
                    if (r >= m_prune) {
                        m_keep[j+1] = 1;
                    } else {
                        //writelog(string("r slope = ")+fp2str(r)+"\n");
                        if (m_keep[j+1] == 0) {
                            //if (m_keep[j] > -1 && m_keep[j+2] > -1)
                            m_keep[j+1] = -1;
                        }
                    }
                }
            }

        }
    }

    for (j = 1; j < n-1; j++) {
        if (dz[j] > m_ratio*dz[j-1]) {
            m_loc[j] = 1;
            m_c["point "+int2str(j)] = 1;
        }
        if (dz[j] < dz[j-1]/m_ratio) {
            m_loc[j-1] = 1;
            m_c["point "+int2str(j-1)] = 1;
        }
        //if (m_loc.size() + n > m_npmax) goto done;
    }

    //done:
    //m_did_analysis = true;
    return int(m_loc.size());
}

double Refiner::value(const double* x, size_t i, size_t j)
{
    return x[m_domain->index(i,j)];
}

void Refiner::show()
{
    int nnew = static_cast<int>(m_loc.size());
    if (nnew > 0) {
        r_drawline();
        writelog(string("Refining grid in ") +
                 m_domain->id()+".\n"
                 +"    New points inserted after grid points ");
        map<size_t, int>::const_iterator b = m_loc.begin();
        for (; b != m_loc.end(); ++b) {
            writelog(int2str(b->first)+" ");
        }
        writelog("\n");
        writelog("    to resolve ");
        map<string, int>::const_iterator bb = m_c.begin();
        for (; bb != m_c.end(); ++bb) {
            writelog(string(bb->first)+" ");
        }
        writelog("\n");
    } else if (m_domain->nPoints() > 1) {
        writelog("no new points needed in "+m_domain->id()+"\n");
        //writelog("curve = "+fp2str(m_curve)+"\n");
        //writelog("slope = "+fp2str(m_slope)+"\n");
        //writelog("prune = "+fp2str(m_prune)+"\n");
    }
}

int Refiner::getNewGrid(int n, const doublereal* z,
                        int nn, doublereal* zn)
{
    int j;
    int nnew = static_cast<int>(m_loc.size());
    if (nnew + n > nn) {
        throw CanteraError("Refine::getNewGrid",
                           "array size too small.");
        return -1;
    }

    int jn = 0;
    if (m_loc.empty()) {
        copy(z, z + n,  zn);
        return 0;
    }

    for (j = 0; j < n - 1; j++) {
        zn[jn] = z[j];
        jn++;
        if (m_loc.count(j)) {
            zn[jn] = 0.5*(z[j] + z[j+1]);
            jn++;
        }
    }
    zn[jn] = z[n-1];
    return 0;
}
}
<|endoftext|>


<commit_before>#ifndef SRC_ONLINE_ADAM_HPP_
#define SRC_ONLINE_ADAM_HPP_

#include <Eigen/Core>

class ADAM {
private :
  const int kDim;

private :
  const double kAlpha = 0.001;
  const double kBeta1 = 0.9;
  const double kBeta2 = 0.999;
  const double kEpsilon = 0.00000001;
  const double kLambda = 0.99999999;

private :
  Eigen::VectorXd _w;
  Eigen::VectorXd _m;
  Eigen::VectorXd _v;
  int _timestep;

public :
  ADAM(const int dim)
    : kDim(dim),
      _timestep(0) {
    _w = _m = _v = Eigen::VectorXd::Zero(kDim);
  }

  double suffer_loss(const Eigen::VectorXd& x, const int y) const {
    return std::max(0.0, 1.0 - y * _w.dot(x));
  }

  double calculate_margin(const Eigen::VectorXd& x) const {
    return _w.dot(x);
  }

  void update(const Eigen::VectorXd& feature, const int label) {
    if (suffer_loss(feature, label) <= 0.0) { return; }
    _timestep++;
    const Eigen::VectorXd gradiant = -label * feature;
    const double beta1_t = kLambda * kBeta1;
    for (std::size_t i = 0; i < kDim; i++) {
      _m[i] = beta1_t * _m[i] + (1.0 - beta1_t) * gradiant[i];
      _v[i] = kBeta2 * _v[i] + (1.0 - kBeta2) * gradiant[i] * gradiant[i];
      const double m_t = _m[i] / (1.0 - std::pow(kBeta1, _timestep));
      const double v_t = _v[i] / (1.0 - std::pow(kBeta2, _timestep));
      _w[i] -= kAlpha * m_t / (std::sqrt(v_t) + kEpsilon);
    }
  }

  int predict(const Eigen::VectorXd& feature) const {
    return calculate_margin(feature) >= 0.0 ? 1 : -1;
  }

};

#endif //SRC_ONLINE_ADAM_HPP_
<commit_msg>実装の一部に誤りがあったため修正<commit_after>#ifndef SRC_ONLINE_ADAM_HPP_
#define SRC_ONLINE_ADAM_HPP_

#include <Eigen/Core>

class ADAM {
private :
  const int kDim;

private :
  const double kAlpha = 0.001;
  const double kBeta1 = 0.9;
  const double kBeta2 = 0.999;
  const double kEpsilon = 0.00000001;
  const double kLambda = 0.99999999;

private :
  Eigen::VectorXd _w;
  Eigen::VectorXd _m;
  Eigen::VectorXd _v;
  int _timestep;

public :
  ADAM(const int dim)
    : kDim(dim),
      _timestep(0) {
    _w = _m = _v = Eigen::VectorXd::Zero(kDim);
  }

  double suffer_loss(const Eigen::VectorXd& x, const int y) const {
    return std::max(0.0, 1.0 - y * _w.dot(x));
  }

  double calculate_margin(const Eigen::VectorXd& x) const {
    return _w.dot(x);
  }

  void update(const Eigen::VectorXd& feature, const int label) {

    if (suffer_loss(feature, label) <= 0.0)
      return ;

    _timestep++;
    const Eigen::VectorXd gradiant = -label * feature;
    const double beta1_t = std::pow(kLambda, _timestep - 1) * kBeta1;
    for (std::size_t i = 0; i < kDim; i++) {
      _m[i] = beta1_t * _m[i] + (1.0 - beta1_t) * gradiant[i];
      _v[i] = kBeta2 * _v[i] + (1.0 - kBeta2) * gradiant[i] * gradiant[i];
      const double m_t = _m[i] / (1.0 - std::pow(kBeta1, _timestep));
      const double v_t = _v[i] / (1.0 - std::pow(kBeta2, _timestep));
      _w[i] -= kAlpha * m_t / (std::sqrt(v_t) + kEpsilon);
    }
  }

  int predict(const Eigen::VectorXd& feature) const {
    return calculate_margin(feature) >= 0.0 ? 1 : -1;
  }

};

#endif //SRC_ONLINE_ADAM_HPP_
<|endoftext|>


<commit_before>/**
 * \file nblock.cc
 *
 *
 *
 * \author Seth Lemons
 * \date 2009-04-18
 */

#include <assert.h>

#include <limits>
#include <vector>
#include <set>

#include "nblock.h"
#include "../open_list.h"
#include "../queue_open_list.h"
#include "../closed_list.h"

using namespace std;
using namespace OPBNF;

/**
 * Create a new NBlock structure.
 */
NBlock::NBlock(const Projection *project, unsigned int ident)
	: id(ident),
	  sigma(0),
	  closed(1000),
	  sigma_hot(0),
	  hot(false),
	  inuse(false),
	  best_f(fp_infinity),
	  best_fp(fp_infinity),
	  local_f_min(fp_infinity)
{
	assert(id < project->get_num_nblocks());

	vector<unsigned int>::iterator i, j;
	vector<unsigned int> preds_vec = project->get_predecessors(id);
	vector<unsigned int> succs_vec = project->get_successors(id);
	// predecessors, successors and the predecessors of the successors.
	vector<unsigned int> interferes_vec = preds_vec;
	for (i = succs_vec.begin(); i != succs_vec.end(); i++) {
		interferes_vec.push_back(*i);
		vector<unsigned int> spreds = project->get_predecessors(*i);
		for (j = spreds.begin(); j != spreds.end(); j++) {
			interferes_vec.push_back(*j);
		}
	}
	for (i = preds_vec.begin(); i != preds_vec.end(); i++)
		if (*i != id)
			preds.insert(*i);
	for (i = succs_vec.begin(); i != succs_vec.end(); i++)
		if (*i != id)
			succs.insert(*i);
	for (i = interferes_vec.begin(); i != interferes_vec.end(); i++)
		if (*i != id)
			interferes.insert(*i);
}

/**
 * Destroy an NBlock and all of its states.
 */
NBlock::~NBlock(void)
{
	closed.delete_all_states();
}

/**
 * Print an NBlock to the given stream.
 */
void NBlock::print(ostream &o)
{
	fp_type best_fp;
	set<unsigned int>::const_iterator iter;

	best_fp = open_fp.empty() ? fp_infinity : open_fp.peek()->get_f_prime();

	o << "nblock " << id << endl;
	o << "\tsigma: " << sigma << endl;
	o << "\tsigma_hot: " << sigma_hot << endl;
	o << "\thot: " << hot << endl;
	o << "\tinuse: " << inuse << endl;
	o << "\topen: " << (open_fp.empty() ? "false" : "true") << endl;
	o << "\tbest f(n): " << best_fp << endl;

	o << "\tinterferes with: ";
	for (iter = interferes.begin(); iter != interferes.end(); iter++)
		o << (*iter) << " ";
	o << endl;

	o << "\tpreds: ";
	for (iter = preds.begin(); iter != preds.end(); iter++)
		o << (*iter) << " ";
	o << endl;

	o << "\tsuccs: ";
	for (iter = succs.begin(); iter != succs.end(); iter++)
		o << (*iter) << " ";
	o << endl;

}

bool NBlock::better(NBlock* a, NBlock* b, fp_type bound){
	fp_type a_f, a_fp, b_f, b_fp;

	a_fp = a->open_fp.get_best_val();
	b_fp = b->open_fp.get_best_val();

	if (a_fp < bound)
		return a_fp < b_fp;

	if (b_fp < bound)	// (a_fp >= bound) and is therefore worse
		return false;

	a_f = a->open_f.get_best_val();
	b_f = b->open_f.get_best_val();

	return a_f < b_f;

}

void NBlock::add(State *s)
{
	open_fp.add(s);
	open_f.add(s);
	set_best_values();
}

void NBlock::see_update(State *s)
{
	open_fp.see_update(s);
	open_f.see_update(s);
	set_best_values();
}

State *NBlock::take_f(void)
{
	State *s = open_f.take();
	if (!s)
		return NULL;

	open_fp.remove(s);
	set_best_values();

	return s;
}

State *NBlock::take_fp(void)
{
	State *s = open_fp.take();
	if (!s)
		return NULL;

	open_f.remove(s);
	set_best_values();

	return s;
}

void NBlock::prune(void)
{
	open_fp.prune();
	open_f.prune();
}

fp_type NBlock::get_best_f(void)
{
	return best_f.read();
}

fp_type NBlock::get_best_fp(void)
{
	return best_fp.read();
}

void NBlock::set_best_values(void)
{
	if (!empty()) {
		best_f.set(open_f.get_best_val());
		best_fp.set(open_fp.get_best_val());
	} else {
		best_f.set(fp_infinity);
		best_fp.set(fp_infinity);
	}
}

bool NBlock::empty(void)
{
	assert(!open_f.empty() || open_fp.empty());
	assert(!open_fp.empty() || open_f.empty());

	return open_f.empty();
}

fp_type NBlock::get_local_f_min()
{
	return local_f_min;
}

void NBlock::update_local_f_min()
{
	local_f_min = best_f.read();
}
<commit_msg>Check for NULL nblocks in the better function.<commit_after>/**
 * \file nblock.cc
 *
 *
 *
 * \author Seth Lemons
 * \date 2009-04-18
 */

#include <assert.h>

#include <limits>
#include <vector>
#include <set>

#include "nblock.h"
#include "../open_list.h"
#include "../queue_open_list.h"
#include "../closed_list.h"

using namespace std;
using namespace OPBNF;

/**
 * Create a new NBlock structure.
 */
NBlock::NBlock(const Projection *project, unsigned int ident)
	: id(ident),
	  sigma(0),
	  closed(1000),
	  sigma_hot(0),
	  hot(false),
	  inuse(false),
	  best_f(fp_infinity),
	  best_fp(fp_infinity),
	  local_f_min(fp_infinity)
{
	assert(id < project->get_num_nblocks());

	vector<unsigned int>::iterator i, j;
	vector<unsigned int> preds_vec = project->get_predecessors(id);
	vector<unsigned int> succs_vec = project->get_successors(id);
	// predecessors, successors and the predecessors of the successors.
	vector<unsigned int> interferes_vec = preds_vec;
	for (i = succs_vec.begin(); i != succs_vec.end(); i++) {
		interferes_vec.push_back(*i);
		vector<unsigned int> spreds = project->get_predecessors(*i);
		for (j = spreds.begin(); j != spreds.end(); j++) {
			interferes_vec.push_back(*j);
		}
	}
	for (i = preds_vec.begin(); i != preds_vec.end(); i++)
		if (*i != id)
			preds.insert(*i);
	for (i = succs_vec.begin(); i != succs_vec.end(); i++)
		if (*i != id)
			succs.insert(*i);
	for (i = interferes_vec.begin(); i != interferes_vec.end(); i++)
		if (*i != id)
			interferes.insert(*i);
}

/**
 * Destroy an NBlock and all of its states.
 */
NBlock::~NBlock(void)
{
	closed.delete_all_states();
}

/**
 * Print an NBlock to the given stream.
 */
void NBlock::print(ostream &o)
{
	fp_type best_fp;
	set<unsigned int>::const_iterator iter;

	best_fp = open_fp.empty() ? fp_infinity : open_fp.peek()->get_f_prime();

	o << "nblock " << id << endl;
	o << "\tsigma: " << sigma << endl;
	o << "\tsigma_hot: " << sigma_hot << endl;
	o << "\thot: " << hot << endl;
	o << "\tinuse: " << inuse << endl;
	o << "\topen: " << (open_fp.empty() ? "false" : "true") << endl;
	o << "\tbest f(n): " << best_fp << endl;

	o << "\tinterferes with: ";
	for (iter = interferes.begin(); iter != interferes.end(); iter++)
		o << (*iter) << " ";
	o << endl;

	o << "\tpreds: ";
	for (iter = preds.begin(); iter != preds.end(); iter++)
		o << (*iter) << " ";
	o << endl;

	o << "\tsuccs: ";
	for (iter = succs.begin(); iter != succs.end(); iter++)
		o << (*iter) << " ";
	o << endl;

}

bool NBlock::better(NBlock* a, NBlock* b, fp_type bound){
	fp_type a_f, a_fp, b_f, b_fp;

	if (!a)
		return false;
	if (!b)
		return true;

	a_fp = a->open_fp.get_best_val();
	b_fp = b->open_fp.get_best_val();

	if (a_fp < bound)
		return a_fp < b_fp;

	if (b_fp < bound)	// (a_fp >= bound) and is therefore worse
		return false;

	a_f = a->open_f.get_best_val();
	b_f = b->open_f.get_best_val();

	return a_f < b_f;

}

void NBlock::add(State *s)
{
	open_fp.add(s);
	open_f.add(s);
	set_best_values();
}

void NBlock::see_update(State *s)
{
	open_fp.see_update(s);
	open_f.see_update(s);
	set_best_values();
}

State *NBlock::take_f(void)
{
	State *s = open_f.take();
	if (!s)
		return NULL;

	open_fp.remove(s);
	set_best_values();

	return s;
}

State *NBlock::take_fp(void)
{
	State *s = open_fp.take();
	if (!s)
		return NULL;

	open_f.remove(s);
	set_best_values();

	return s;
}

void NBlock::prune(void)
{
	open_fp.prune();
	open_f.prune();
}

fp_type NBlock::get_best_f(void)
{
	return best_f.read();
}

fp_type NBlock::get_best_fp(void)
{
	return best_fp.read();
}

void NBlock::set_best_values(void)
{
	if (!empty()) {
		best_f.set(open_f.get_best_val());
		best_fp.set(open_fp.get_best_val());
	} else {
		best_f.set(fp_infinity);
		best_fp.set(fp_infinity);
	}
}

bool NBlock::empty(void)
{
	assert(!open_f.empty() || open_fp.empty());
	assert(!open_fp.empty() || open_f.empty());

	return open_f.empty();
}

fp_type NBlock::get_local_f_min()
{
	return local_f_min;
}

void NBlock::update_local_f_min()
{
	local_f_min = best_f.read();
}
<|endoftext|>


<commit_before><commit_msg>Ensure that the BiasGelu op test runs on CPU. (#8671)<commit_after><|endoftext|>


<commit_before>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef ACCESS_LOG_DATAGRAM_HXX
#define ACCESS_LOG_DATAGRAM_HXX

#include <http/method.h>
#include <http/status.h>

#include <stdint.h>

struct AccessLogDatagram {
    uint64_t timestamp;

    const char *remote_host, *host, *site;

    http_method_t http_method;

    const char *http_uri, *http_referer, *user_agent;

    http_status_t http_status;

    uint64_t length;

    uint64_t traffic_received, traffic_sent;

    uint64_t duration;

    bool valid_timestamp, valid_http_method, valid_http_status;
    bool valid_length, valid_traffic;
    bool valid_duration;
};

#endif
<commit_msg>access_log/Datagram: add initializing constructor<commit_after>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef ACCESS_LOG_DATAGRAM_HXX
#define ACCESS_LOG_DATAGRAM_HXX

#include <http/method.h>
#include <http/status.h>

#include <stdint.h>

struct AccessLogDatagram {
    uint64_t timestamp;

    const char *remote_host, *host, *site;

    http_method_t http_method;

    const char *http_uri, *http_referer, *user_agent;

    http_status_t http_status;

    uint64_t length;

    uint64_t traffic_received, traffic_sent;

    uint64_t duration;

    bool valid_timestamp, valid_http_method, valid_http_status;
    bool valid_length, valid_traffic;
    bool valid_duration;

    AccessLogDatagram() = default;

    AccessLogDatagram(uint64_t _timestamp,
                      http_method_t _method, const char *_uri,
                      const char *_remote_host,
                      const char *_host, const char *_site,
                      const char *_referer, const char *_user_agent,
                      http_status_t _status, int64_t _length,
                      uint64_t _traffic_received, uint64_t _traffic_sent,
                      uint64_t _duration)
        :timestamp(_timestamp),
         remote_host(_remote_host), host(_host), site(_site),
         http_method(_method),
         http_uri(_uri), http_referer(_referer), user_agent(_user_agent),
         http_status(_status),
         length(_length),
         traffic_received(_traffic_received), traffic_sent(_traffic_sent),
         duration(_duration),
         valid_timestamp(true),
         valid_http_method(true), valid_http_status(true),
         valid_length(_length >= 0), valid_traffic(true),
         valid_duration(true) {}
};

#endif
<|endoftext|>


<commit_before>#include<iostream>
#include<cmath>
#include <kv/interval.hpp>
#include <kv/rdouble.hpp>
#include<iomanip> // include this to set digits
using namespace std;
int main(void)
{
  // verfication program for the Hahn-Exton q-Bessel function
  // properties of the q-Pochhammer symbol were used
  int K=1000;
  int j=1;
  kv::interval<double> q;
  kv::interval<double> nu; // nu is a real number
  kv::interval<double> x;
  q=0.1;// q must be positive
  nu=3.5;
  x=1.4;
  kv::interval<double> a;
  kv::interval<double> b;
  kv::interval<double> c;
  a=1.;
  b=1.;
  c=1.;
 // derived from the definition of q-Pochhammer symbol
  for (int k=1; k<=K; k++){
    j = -1*j;
    b=b*(1-pow(q,k));
    c=c*(1-pow(q,k+nu));
    a = a+j*pow(q,k*(k+1)/2)*pow(x,2*k)/(b*c);
  }
  b=b*(1-pow(q,K+1));
  c=c*(1-pow(q,K+nu+1));
  double rad=abs(pow(-1,K+1)*pow(q,(K+1)*(K+2)/2)*pow(x,2*K+2)/(b*c)).upper();
  // .upper() allows to output supremum
  kv::interval<double> series=a+rad; // result must be an interval

  kv::interval<double> z;
  z=pow(q,nu+1);
  kv::interval<double> f;
  kv::interval<double> g;
  f=1/(1-z);
  g=1.;
  int m=1;
 // derived from the definition of q-Pochhammer symbol
  for (int l=1; l<=K; l++){
    m = -1*m;
    g=g*(1-pow(q,l));
    f=f+m*pow(q,l*(l+1)/2)/(g*(1-z*pow(q,l)));
  }
  g=g*(1-pow(q,K+1));
  double rad2=abs(pow(-1,K+1)*pow(q,(K+1)*(K+2)/2)/(g*(1-z*pow(q,K+1)))).upper();
  kv::interval<double> denom=f+rad2; // result must be an interval
  kv::interval<double> res=pow(x,nu)*series/denom;
  cout << fixed << setprecision(16) <<res << endl;
}
<commit_msg>Delete Hahn-Exton-q-Bessel.cc<commit_after><|endoftext|>


<commit_before>#include "PedalManager.h"

#define SENSOR_CHANGE_PALETTE 7
#define SENSOR_TOGGLE_ECHO 8
#define SENSOR_TOGGLE_FADE 9

PedalManager::PedalManager() {

}

void PedalManager::begin() {

}

void PedalManager::depress(uint8_t touchIndex) {
	switch(touchIndex) {
		case SENSOR_CHANGE_PALETTE: {
			_function = PedalChangePalette;
			break;
		}
		case SENSOR_TOGGLE_ECHO: {
			_function = PedalToggleEcho;
			break;
		}
		case SENSOR_TOGGLE_FADE: {
			_function = PedalToggleFade;
			break;
		}
		default: {
			_function = PedalNoFunction;
			break;
		}
	}
}

void PedalManager::release(uint8_t touchIndex) {

}

PedalFunction PedalManager::update() {
	return _function;
}<commit_msg>debugging statements, declare _function<commit_after>#include "PedalManager.h"

#define SENSOR_CHANGE_PALETTE 7
#define SENSOR_TOGGLE_ECHO 8
#define SENSOR_TOGGLE_FADE 9

PedalFunction PedalManager::_function = PedalNoFunction;

PedalManager::PedalManager() {

}

void PedalManager::begin() {

}

void PedalManager::depress(uint8_t touchIndex) {
	switch(touchIndex) {
		case SENSOR_CHANGE_PALETTE: {
			_function = PedalChangePalette;
			Serial.println("PED | Palette chg");
			break;
		}
		case SENSOR_TOGGLE_ECHO: {
			_function = PedalToggleEcho;
			break;
		}
		case SENSOR_TOGGLE_FADE: {
			_function = PedalToggleFade;
			break;
		}
		default: {
			_function = PedalNoFunction;
			break;
		}
	}
}

void PedalManager::release(uint8_t touchIndex) {

}

PedalFunction PedalManager::update() {
	PedalFunction temp = _function;
	_function = PedalNoFunction;
	return temp;
}<|endoftext|>


<commit_before>/*
 * game: the game of arithmetic - interactive gui - implementation
 * Copyright(c) 2005 by wave++ "Yuri D'Elia" <wavexx@users.sf.net>
 */

/*
 * Headers
 */

#include "game.hh"
#include "interp.hh"
using std::string;

#include <algorithm>
using std::max;

#include <cstdlib>
using std::sprintf;

#include <GL/freeglut.h>

/*
 * Implementation
 */

void
Game::drawFWString(const char* str, const Point& pos)
{
  // draws a fixed with strings. useful for numbers.
  glPushMatrix();
  glTranslatef(pos.x, pos.y, 0.);

  for(int c = 0; *str; ++str, ++c)
  {
    // center the character
    glPushMatrix();

    const Bounds& cur = resources.cm->getChar(*str).metrics.bounds;
    glTranslatef(
	(nmHSpace * c) + (nmHSpace - (cur.ur.x - cur.ll.x)) / 2 - cur.ll.x,
	(nmVSpace - (cur.ur.y - cur.ll.y)) / 2 - cur.ll.y, 0.);

    resources.cm->draw(*str);
    glPopMatrix();
  }

  glPopMatrix();
}

void
Game::drawRString(const char* str, const Point& pos)
{
  // right aligned string
  Bounds bounds;
  resources.cm->bounds(bounds, str);

  glPushMatrix();

  glTranslatef(pos.x - (bounds.ur.x - bounds.ll.x) - bounds.ll.x,
      pos.y - bounds.ll.y, 0.);
  resources.cm->draw(str);

  glPopMatrix();
}

void
Game::drawStackElem(const Question& q, const Point& pos)
{
  // get the correct color
  Color color = (q.errs? resources.error:
      interpolate(q.cum / max(1., avgTime),
	  resources.normal, resources.timeout));

  // background
  color.rgba[3] = 0.5;
  glColor4fv(color);
  glBegin(GL_QUADS);
  glVertex2f(pos.x, pos.y);
  glVertex2f(pos.x, pos.y + nmVSpace);
  glVertex2f(pos.x + stackW, pos.y + nmVSpace);
  glVertex2f(pos.x + stackW, pos.y);
  glEnd();

  // contour
  color.rgba[3] = 1.;
  glColor4fv(color);
  glBegin(GL_LINE_STRIP);
  glVertex2f(pos.x, pos.y + nmVSpace);
  glVertex2f(pos.x + stackW, pos.y + nmVSpace);
  glVertex2f(pos.x + stackW, pos.y);
  glEnd();

  // string
  char fmt[32];
  sprintf(fmt, "%%%dd%%c%%-%dd", maxLenA, maxLenB);

  char* buf = new char[maxLen + 1];
  sprintf(buf, fmt, q.na, q.kernel->first.o->sym(), q.kernel->first.b);

  glColor4fv(resources.foreground);
  drawFWString(buf, pos);
  delete []buf;
}

void
Game::drawBar()
{
  Color color;

  // background
  glBegin(GL_QUADS);

  color = resources.bar[0];
  color.rgba[3] = 0.5;
  glColor4fv(color);
  glVertex2f(urGeom.x - nmVSpace, urGeom.y);
  glVertex2f(urGeom.x, urGeom.y);

  color = resources.bar[1];
  color.rgba[3] = 0.5;
  glColor4fv(color);
  glVertex2f(urGeom.x, 0);
  glVertex2f(urGeom.x - nmVSpace, 0);

  glEnd();

  if(state == playing)
  {
    float r = interpLinear(frame, now);
    float ry = urGeom.y - r * urGeom.y;

    // hilight
    color = interpolate(r, resources.bar[0], resources.bar[1]);
    glColor4fv(color);
    glBegin(GL_QUADS);
    glVertex2f(urGeom.x - nmVSpace, 0);
    glVertex2f(urGeom.x - nmVSpace, ry);
    glVertex2f(urGeom.x, ry);
    glVertex2f(urGeom.x, 0);
    glEnd();

    // timer
    glPushMatrix();
    const Font& font = resources.cm->getFont();
    glTranslatef(urGeom.x - nmVSpace - font.bounds.ll.y,
	urGeom.y + font.bounds.ll.x, 0);
    glRotatef(-90., 0., 0., 1.);
    char buf[sizeof(int) * 4];
    sprintf(buf, "%d", static_cast<int>(frame.end - now));
    glColor4fv(resources.background);
    resources.cm->draw(buf);
    glPopMatrix();
  }

  // separator
  glColor4fv(resources.foreground);
  glBegin(GL_LINES);
  glVertex2f(urGeom.x - nmVSpace, 0);
  glVertex2f(urGeom.x - nmVSpace, urGeom.y);
  glEnd();
}

void
Game::drawStats()
{
  // some useful data
  int num = 1;
  float anchor = urGeom.x - nmVSpace - nmHSpace;
  char buf[32];
  int len;

  glColor4fv(resources.foreground);

  // playing time
  int seconds = static_cast<int>(playingTime);
  len = sprintf(buf, "%d:%02d", seconds / 60, seconds % 60) - 1;
  drawRString("playing time:", Point(anchor, urGeom.y - nmVSpace * num++));
  drawFWString(buf, Point(anchor - nmHSpace * len,
	  urGeom.y - nmVSpace * num++));

  // questions
  len = sprintf(buf, "%d", questions) - 1;
  drawRString("questions:", Point(anchor, urGeom.y - nmVSpace * num++));
  drawFWString(buf, Point(anchor - nmHSpace * len,
	  urGeom.y - nmVSpace * num++));

  // max size
  len = sprintf(buf, "%d", maxSize) - 1;
  drawRString("max size:", Point(anchor, urGeom.y - nmVSpace * num++));
  drawFWString(buf, Point(anchor - nmHSpace * len,
	  urGeom.y - nmVSpace * num++));

  // gameOver/paused
  if(paused())
  {
    glColor4fv(resources.bar[0]);
    drawRString("paused", Point(anchor, urGeom.y - nmVSpace * num++));
  }
  else if(state == gameOver)
  {
    glColor4fv(resources.bar[1]);
    drawRString("game over", Point(anchor, urGeom.y - nmVSpace * num++));
  }
}

void
Game::drawAnswer(const float y)
{
  string buf("=");
  buf += answer;

  glColor4fv(resources.foreground);
  drawFWString(buf.c_str(), Point(stackW, y));
}

void
Game::updateAvg()
{
  // time averages
  AvgTime res;
  for(TimeMap::iterator it = data.times.begin(); it != data.times.end(); ++it)
  {
    // only for the active operators
    if(data.ops.find(it->first) != data.ops.end())
      res.add(it->second.avg());
  }
  avgTime = res.avg();
}

void
Game::updateTimes(const Time shift)
{
  playingTime += shift;
  question.cum += shift;
}

void
Game::resetQuestion()
{
  question.kernel = randFind(data.kernels, NrPred(*this));
  const Kernel& kernel(question.kernel->first);
  question.r = kernel.o->result(kernel.a, kernel.b, question.na);
  question.cum = 0.;
  question.errs = 0;
}

void
Game::initAnim()
{
  // basic animation data
  state = animating;
  frame.begin = now;
  frame.end = now + resources.animTime;
}

void
Game::initGame()
{
  // basic animation data
  state = playing;

  if(lastResult && data.mode == GameData::hard &&
      static_cast<int>(stack.size()) < oldSize)
  {
    // only continue when an element was successfully removed
    frame.end = now + lastRTime;
    frame.begin = frame.end - avgTime;
  }
  else
  {
    frame.begin = now;
    frame.end = now + avgTime;
  }
}

void
Game::drawState()
{
  // always draw the stack
  QDeque::iterator it = stack.begin();
  for(int i = 0; it != stack.end(); ++i, ++it)
    drawStackElem(*it, Point(0, nmVSpace * i));

  // common variables
  float stackHead = nmVSpace * stack.size();

  if(state == animating)
  {
    // animating parts
    float oldHead = nmVSpace * oldSize;
    float ci = interpCubic(frame, now);

    // dropping element
    if(static_cast<int>(stack.size()) >= oldSize)
      drawStackElem(question, interpolate(ci,
	      Point(0, urGeom.y), Point(0, stackHead)));
    else
      drawStackElem(question, Point(0, stackHead));

    // removing element
    if(lastResult)
      drawStackElem(lastQuestion, Point(-ci * stackW * 2, oldHead));

    // answer symbol
    drawAnswer(interpolate(ci, oldHead, stackHead));
  }
  else
  {
    // current element and answer
    drawStackElem(question, Point(0, stackHead));
    drawAnswer(stackHead);
  }

  // remaining time and stats
  drawBar();
  drawStats();
}

void
Game::nextState()
{
  if(state == animating)
    initGame();
  else if(state == playing && data.mode != GameData::practice)
    timeOut();
}

void
Game::contGame()
{
  // check game status
  if(static_cast<int>(stack.size()) == data.stackSize)
    stopGame();
  else
  {
    // update statistics
    ++questions;
    if(maxSize < static_cast<int>(stack.size()))
      maxSize = stack.size();

    // continue
    answer.clear();
    initAnim();
  }
}

void
Game::stopGame()
{
  // change the state
  state = gameOver;

  // commit errors on the stack
  for(QDeque::const_iterator it = stack.begin(); it != stack.end(); ++it)
  {
    if(it->errs)
      data.update(it->kernel, it->errs, it->cum);
  }
}

void
Game::timeOut()
{
  // update stack
  lastResult = false;
  lastRTime = 0.;
  oldSize = stack.size();
  stack.push_back(question);
  resetQuestion();
  contGame();
}

void
Game::submitAnswer()
{
  // check result
  int r = strtol(answer.c_str(), NULL, 10);
  lastResult = (r == question.r);
  lastRTime = frame.end - now;
  oldSize = stack.size();

  if(lastResult)
  {
    // correct, update the stack
    lastQuestion = question;
    data.update(question.kernel, question.errs, question.cum);
    updateAvg();

    if(stack.size() &&
	(data.mode != GameData::hard || lastRTime > resources.minTime) &&
	(data.mode != GameData::veryHard))
    {
      // recover and old question
      question = stack.back();
      stack.pop_back();
    }
    else
      resetQuestion();
  }
  else
  {
    // wrong answers
    ++question.errs;
    stack.push_back(question);
    resetQuestion();
  }

  contGame();
}

bool
Game::NrPred::operator()(const Kernel& kernel) const
{
  // exclude disabled operations
  if(ref.data.ops.find(kernel.o) == ref.data.ops.end())
    return false;

  // when in veryHard and/or limit conditions the stack is ignored
  if(ref.data.mode == GameData::veryHard ||
      ref.stack.size() >= ref.data.kernels.size())
    return true;

  // exclude all kernels already present in the stack
  for(QDeque::const_iterator it = ref.stack.begin();
      it != ref.stack.end(); ++it)
    if(kernel == it->kernel->first)
      return false;

  return true;
}

Game::Game(const Resources& resources, const Time now, GameData& data)
: State(resources, now, data)
{
  // font spacing
  Bounds nmBounds;
  resources.cm->maxOf(nmBounds, "0123456789+-*/=~");
  nmHSpace = nmBounds.ur.x - nmBounds.ll.x;
  nmHSpace += nmHSpace * 0.1;
  nmVSpace = 1.1;

  // sizes
  maxLenA = maxLenB = maxLenR = 0;
  for(KernMap::iterator it = data.kernels.begin();
      it != data.kernels.end(); ++it)
  {
    // only consider active operations
    if(data.ops.find(it->first.o) == data.ops.end())
      continue;

    int na;
    char buf[sizeof(int) * 4];
    int r = it->first.o->result(it->first.a, it->first.b, na);
    maxLenA = max(maxLenA, sprintf(buf, "%d", na));
    maxLenB = max(maxLenB, sprintf(buf, "%d", it->first.b));
    maxLenR = max(maxLenR, sprintf(buf, "%d", r));
  }

  // misc geometry
  maxLen = maxLenA + 1 + maxLenB;
  stackW = nmHSpace * maxLen;

  // initial stats
  questions = 0;
  maxSize = 0;
  playingTime = 0.;

  // initial state
  this->now = now;
  lastResult = false;
  lastRTime = 0.;
  oldSize = -1;
  updateAvg();
  resetQuestion();
  initAnim();
}

void
Game::reshape(const int w, const int h)
{
  // calculate enough vertical space to fit the stack exactly
  urGeom.y = nmVSpace * data.stackSize;
  urGeom.x = urGeom.y * static_cast<float>(w) / h * resources.videoRatio;
  gluOrtho2D(0, urGeom.x, 0, urGeom.y);
}

void
Game::display(const Time now)
{
  // update times
  if(state == playing)
    updateTimes(now - this->now);
  this->now = now;

  // update status
  if(now > frame.end)
    nextState();

  // actual drawing
  drawState();
}

void
Game::keyboard(const unsigned char key)
{
  // quit
  if(key == 27 || key == 'q' || key == 'Q')
  {
    stopGame();
    quit();
    return;
  }

  // pause
  if(state != gameOver && (key == 'p' || key == 'P'))
  {
    pause();
    return;
  }

  // the following only works when actively playing
  if(state != playing || paused())
    return;

  if(key == 8)
  {
    // backspace
    if(answer.size())
      answer.resize(answer.size() - 1);
  }
  else if(key >= '0' && key <= '9')
  {
    // number
    if(static_cast<int>(answer.size()) < maxLenR)
      answer += key;
  }
  else if(key == 13)
  {
    // empty answers as timeouts
    if(answer.size())
      submitAnswer();
    else
      timeOut();
  }
}
<commit_msg>Only increase maxSize on success.<commit_after>/*
 * game: the game of arithmetic - interactive gui - implementation
 * Copyright(c) 2005 by wave++ "Yuri D'Elia" <wavexx@users.sf.net>
 */

/*
 * Headers
 */

#include "game.hh"
#include "interp.hh"
using std::string;

#include <algorithm>
using std::max;

#include <cstdlib>
using std::sprintf;

#include <GL/freeglut.h>

/*
 * Implementation
 */

void
Game::drawFWString(const char* str, const Point& pos)
{
  // draws a fixed with strings. useful for numbers.
  glPushMatrix();
  glTranslatef(pos.x, pos.y, 0.);

  for(int c = 0; *str; ++str, ++c)
  {
    // center the character
    glPushMatrix();

    const Bounds& cur = resources.cm->getChar(*str).metrics.bounds;
    glTranslatef(
	(nmHSpace * c) + (nmHSpace - (cur.ur.x - cur.ll.x)) / 2 - cur.ll.x,
	(nmVSpace - (cur.ur.y - cur.ll.y)) / 2 - cur.ll.y, 0.);

    resources.cm->draw(*str);
    glPopMatrix();
  }

  glPopMatrix();
}

void
Game::drawRString(const char* str, const Point& pos)
{
  // right aligned string
  Bounds bounds;
  resources.cm->bounds(bounds, str);

  glPushMatrix();

  glTranslatef(pos.x - (bounds.ur.x - bounds.ll.x) - bounds.ll.x,
      pos.y - bounds.ll.y, 0.);
  resources.cm->draw(str);

  glPopMatrix();
}

void
Game::drawStackElem(const Question& q, const Point& pos)
{
  // get the correct color
  Color color = (q.errs? resources.error:
      interpolate(q.cum / max(1., avgTime),
	  resources.normal, resources.timeout));

  // background
  color.rgba[3] = 0.5;
  glColor4fv(color);
  glBegin(GL_QUADS);
  glVertex2f(pos.x, pos.y);
  glVertex2f(pos.x, pos.y + nmVSpace);
  glVertex2f(pos.x + stackW, pos.y + nmVSpace);
  glVertex2f(pos.x + stackW, pos.y);
  glEnd();

  // contour
  color.rgba[3] = 1.;
  glColor4fv(color);
  glBegin(GL_LINE_STRIP);
  glVertex2f(pos.x, pos.y + nmVSpace);
  glVertex2f(pos.x + stackW, pos.y + nmVSpace);
  glVertex2f(pos.x + stackW, pos.y);
  glEnd();

  // string
  char fmt[32];
  sprintf(fmt, "%%%dd%%c%%-%dd", maxLenA, maxLenB);

  char* buf = new char[maxLen + 1];
  sprintf(buf, fmt, q.na, q.kernel->first.o->sym(), q.kernel->first.b);

  glColor4fv(resources.foreground);
  drawFWString(buf, pos);
  delete []buf;
}

void
Game::drawBar()
{
  Color color;

  // background
  glBegin(GL_QUADS);

  color = resources.bar[0];
  color.rgba[3] = 0.5;
  glColor4fv(color);
  glVertex2f(urGeom.x - nmVSpace, urGeom.y);
  glVertex2f(urGeom.x, urGeom.y);

  color = resources.bar[1];
  color.rgba[3] = 0.5;
  glColor4fv(color);
  glVertex2f(urGeom.x, 0);
  glVertex2f(urGeom.x - nmVSpace, 0);

  glEnd();

  if(state == playing)
  {
    float r = interpLinear(frame, now);
    float ry = urGeom.y - r * urGeom.y;

    // hilight
    color = interpolate(r, resources.bar[0], resources.bar[1]);
    glColor4fv(color);
    glBegin(GL_QUADS);
    glVertex2f(urGeom.x - nmVSpace, 0);
    glVertex2f(urGeom.x - nmVSpace, ry);
    glVertex2f(urGeom.x, ry);
    glVertex2f(urGeom.x, 0);
    glEnd();

    // timer
    glPushMatrix();
    const Font& font = resources.cm->getFont();
    glTranslatef(urGeom.x - nmVSpace - font.bounds.ll.y,
	urGeom.y + font.bounds.ll.x, 0);
    glRotatef(-90., 0., 0., 1.);
    char buf[sizeof(int) * 4];
    sprintf(buf, "%d", static_cast<int>(frame.end - now));
    glColor4fv(resources.background);
    resources.cm->draw(buf);
    glPopMatrix();
  }

  // separator
  glColor4fv(resources.foreground);
  glBegin(GL_LINES);
  glVertex2f(urGeom.x - nmVSpace, 0);
  glVertex2f(urGeom.x - nmVSpace, urGeom.y);
  glEnd();
}

void
Game::drawStats()
{
  // some useful data
  int num = 1;
  float anchor = urGeom.x - nmVSpace - nmHSpace;
  char buf[32];
  int len;

  glColor4fv(resources.foreground);

  // playing time
  int seconds = static_cast<int>(playingTime);
  len = sprintf(buf, "%d:%02d", seconds / 60, seconds % 60) - 1;
  drawRString("playing time:", Point(anchor, urGeom.y - nmVSpace * num++));
  drawFWString(buf, Point(anchor - nmHSpace * len,
	  urGeom.y - nmVSpace * num++));

  // questions
  len = sprintf(buf, "%d", questions) - 1;
  drawRString("questions:", Point(anchor, urGeom.y - nmVSpace * num++));
  drawFWString(buf, Point(anchor - nmHSpace * len,
	  urGeom.y - nmVSpace * num++));

  // max size
  len = sprintf(buf, "%d", maxSize) - 1;
  drawRString("max size:", Point(anchor, urGeom.y - nmVSpace * num++));
  drawFWString(buf, Point(anchor - nmHSpace * len,
	  urGeom.y - nmVSpace * num++));

  // gameOver/paused
  if(paused())
  {
    glColor4fv(resources.bar[0]);
    drawRString("paused", Point(anchor, urGeom.y - nmVSpace * num++));
  }
  else if(state == gameOver)
  {
    glColor4fv(resources.bar[1]);
    drawRString("game over", Point(anchor, urGeom.y - nmVSpace * num++));
  }
}

void
Game::drawAnswer(const float y)
{
  string buf("=");
  buf += answer;

  glColor4fv(resources.foreground);
  drawFWString(buf.c_str(), Point(stackW, y));
}

void
Game::updateAvg()
{
  // time averages
  AvgTime res;
  for(TimeMap::iterator it = data.times.begin(); it != data.times.end(); ++it)
  {
    // only for the active operators
    if(data.ops.find(it->first) != data.ops.end())
      res.add(it->second.avg());
  }
  avgTime = res.avg();
}

void
Game::updateTimes(const Time shift)
{
  playingTime += shift;
  question.cum += shift;
}

void
Game::resetQuestion()
{
  question.kernel = randFind(data.kernels, NrPred(*this));
  const Kernel& kernel(question.kernel->first);
  question.r = kernel.o->result(kernel.a, kernel.b, question.na);
  question.cum = 0.;
  question.errs = 0;
}

void
Game::initAnim()
{
  // basic animation data
  state = animating;
  frame.begin = now;
  frame.end = now + resources.animTime;
}

void
Game::initGame()
{
  // basic animation data
  state = playing;

  if(lastResult && data.mode == GameData::hard &&
      static_cast<int>(stack.size()) < oldSize)
  {
    // only continue when an element was successfully removed
    frame.end = now + lastRTime;
    frame.begin = frame.end - avgTime;
  }
  else
  {
    frame.begin = now;
    frame.end = now + avgTime;
  }
}

void
Game::drawState()
{
  // always draw the stack
  QDeque::iterator it = stack.begin();
  for(int i = 0; it != stack.end(); ++i, ++it)
    drawStackElem(*it, Point(0, nmVSpace * i));

  // common variables
  float stackHead = nmVSpace * stack.size();

  if(state == animating)
  {
    // animating parts
    float oldHead = nmVSpace * oldSize;
    float ci = interpCubic(frame, now);

    // dropping element
    if(static_cast<int>(stack.size()) >= oldSize)
      drawStackElem(question, interpolate(ci,
	      Point(0, urGeom.y), Point(0, stackHead)));
    else
      drawStackElem(question, Point(0, stackHead));

    // removing element
    if(lastResult)
      drawStackElem(lastQuestion, Point(-ci * stackW * 2, oldHead));

    // answer symbol
    drawAnswer(interpolate(ci, oldHead, stackHead));
  }
  else
  {
    // current element and answer
    drawStackElem(question, Point(0, stackHead));
    drawAnswer(stackHead);
  }

  // remaining time and stats
  drawBar();
  drawStats();
}

void
Game::nextState()
{
  if(state == animating)
    initGame();
  else if(state == playing && data.mode != GameData::practice)
    timeOut();
}

void
Game::contGame()
{
  // check game status
  if(static_cast<int>(stack.size()) == data.stackSize)
    stopGame();
  else
  {
    // update statistics
    ++questions;

    // only update on success. this could be used for calculating correctly
    // a better score in the future.
    if(static_cast<int>(stack.size()) <= oldSize && oldSize > maxSize)
      maxSize = oldSize;

    // continue
    answer.clear();
    initAnim();
  }
}

void
Game::stopGame()
{
  // change the state
  state = gameOver;

  // commit errors on the stack
  for(QDeque::const_iterator it = stack.begin(); it != stack.end(); ++it)
  {
    if(it->errs)
      data.update(it->kernel, it->errs, it->cum);
  }
}

void
Game::timeOut()
{
  // update stack
  lastResult = false;
  lastRTime = 0.;
  oldSize = stack.size();
  stack.push_back(question);
  resetQuestion();
  contGame();
}

void
Game::submitAnswer()
{
  // check result
  int r = strtol(answer.c_str(), NULL, 10);
  lastResult = (r == question.r);
  lastRTime = frame.end - now;
  oldSize = stack.size();

  if(lastResult)
  {
    // correct, update the stack
    lastQuestion = question;
    data.update(question.kernel, question.errs, question.cum);
    updateAvg();

    if(stack.size() &&
	(data.mode != GameData::hard || lastRTime > resources.minTime) &&
	(data.mode != GameData::veryHard))
    {
      // recover and old question
      question = stack.back();
      stack.pop_back();
    }
    else
      resetQuestion();
  }
  else
  {
    // wrong answers
    ++question.errs;
    stack.push_back(question);
    resetQuestion();
  }

  contGame();
}

bool
Game::NrPred::operator()(const Kernel& kernel) const
{
  // exclude disabled operations
  if(ref.data.ops.find(kernel.o) == ref.data.ops.end())
    return false;

  // when in veryHard and/or limit conditions the stack is ignored
  if(ref.data.mode == GameData::veryHard ||
      ref.stack.size() >= ref.data.kernels.size())
    return true;

  // exclude all kernels already present in the stack
  for(QDeque::const_iterator it = ref.stack.begin();
      it != ref.stack.end(); ++it)
    if(kernel == it->kernel->first)
      return false;

  return true;
}

Game::Game(const Resources& resources, const Time now, GameData& data)
: State(resources, now, data)
{
  // font spacing
  Bounds nmBounds;
  resources.cm->maxOf(nmBounds, "0123456789+-*/=~");
  nmHSpace = nmBounds.ur.x - nmBounds.ll.x;
  nmHSpace += nmHSpace * 0.1;
  nmVSpace = 1.1;

  // sizes
  maxLenA = maxLenB = maxLenR = 0;
  for(KernMap::iterator it = data.kernels.begin();
      it != data.kernels.end(); ++it)
  {
    // only consider active operations
    if(data.ops.find(it->first.o) == data.ops.end())
      continue;

    int na;
    char buf[sizeof(int) * 4];
    int r = it->first.o->result(it->first.a, it->first.b, na);
    maxLenA = max(maxLenA, sprintf(buf, "%d", na));
    maxLenB = max(maxLenB, sprintf(buf, "%d", it->first.b));
    maxLenR = max(maxLenR, sprintf(buf, "%d", r));
  }

  // misc geometry
  maxLen = maxLenA + 1 + maxLenB;
  stackW = nmHSpace * maxLen;

  // initial stats
  questions = 0;
  maxSize = 0;
  playingTime = 0.;

  // initial state
  this->now = now;
  lastResult = false;
  lastRTime = 0.;
  oldSize = -1;
  updateAvg();
  resetQuestion();
  initAnim();
}

void
Game::reshape(const int w, const int h)
{
  // calculate enough vertical space to fit the stack exactly
  urGeom.y = nmVSpace * data.stackSize;
  urGeom.x = urGeom.y * static_cast<float>(w) / h * resources.videoRatio;
  gluOrtho2D(0, urGeom.x, 0, urGeom.y);
}

void
Game::display(const Time now)
{
  // update times
  if(state == playing)
    updateTimes(now - this->now);
  this->now = now;

  // update status
  if(now > frame.end)
    nextState();

  // actual drawing
  drawState();
}

void
Game::keyboard(const unsigned char key)
{
  // quit
  if(key == 27 || key == 'q' || key == 'Q')
  {
    stopGame();
    quit();
    return;
  }

  // pause
  if(state != gameOver && (key == 'p' || key == 'P'))
  {
    pause();
    return;
  }

  // the following only works when actively playing
  if(state != playing || paused())
    return;

  if(key == 8)
  {
    // backspace
    if(answer.size())
      answer.resize(answer.size() - 1);
  }
  else if(key >= '0' && key <= '9')
  {
    // number
    if(static_cast<int>(answer.size()) < maxLenR)
      answer += key;
  }
  else if(key == 13)
  {
    // empty answers as timeouts
    if(answer.size())
      submitAnswer();
    else
      timeOut();
  }
}
<|endoftext|>