<commit_before>/** \file    extract_normdata_translations.cc
 *  \brief   Extract IxTheo and MACS translations from the normdata file and write it to
 *           language specific text files
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2016, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* The German term is found in Field 150
   Currently there are two different kinds of translations:
   IxTheo-Translations with the following definitions:

   710: Körperschaft - fremdsprachige Äquivalenz
   711: Konferenz - fremdsprachige Äquivalenz
   700: Person - fremdsprachige Äquivalenz
   730: Titel - fremdsprachige Äquivalenz
   750: Sachbegriff - fremdsprachige Äquivalenz
   751: Geografikum - fremdsprachige Äquivalenz

   LoC/Rameau Translations:
   700: Person - Bevorzugter Name in einem anderen Datenbestand
   710: Körperschaft - Bevorzugter Name in einem anderen Datenbestand
   711: Konferenz - Bevorzugte Benennung in einem anderen Datenbestand
   730: Einheitstitel - Bevorzugter Name in einem anderen Datenbestand
   750: Sachbegriff - Bevorzugte Benennung in einem anderen Datenbestand
   751: Geografikum - Bevorzugter Name in einem anderen Datenbestand
*/
#include <iostream>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "MarcUtil.h"
#include "MediaTypeUtil.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

// Languages to handle
const unsigned int NUMBER_OF_LANGUAGES = 2;
const std::vector<std::string> languages_to_create{ "en", "fr" };
enum Languages { EN, FR };

void Usage() {
    std::cerr << "Usage: " << ::progname << " norm_data_marc_input extracted_translations\n";
    std::exit(EXIT_FAILURE);
}

void AugmentIxTheoTagWithLanguage(const MarcUtil::Record &record, const std::string &tag, std::vector<std::string> * const translations) {
    auto ixtheo_pos(std::find(translations->begin(), translations->end(), "IxTheo"));
    if (ixtheo_pos != translations->end()) {
        std::vector<std::string> ixtheo_lang_codes;
        record.extractSubfields(tag, "9", &ixtheo_lang_codes);
        bool already_found_ixtheo_translation(false);
        for (const auto &lang_code : ixtheo_lang_codes) {
            if (lang_code[0] != 'L')
                continue;
            if (already_found_ixtheo_translation)
                continue;
            if (lang_code.find("eng") != std::string::npos and *ixtheo_pos != "IxTheo_eng") {
                *ixtheo_pos += + "_eng";
                already_found_ixtheo_translation = true;
            } else if (lang_code.find("fra") != std::string::npos and *ixtheo_pos != "IxTheo_fra") {
                *ixtheo_pos += "_fra";
                already_found_ixtheo_translation = true;
            } else
                Warning("Unsupported language code \"" + lang_code + "\" for PPN " + record.getFields()[0]);
        }
    }
}

void ExtractTranslations(File* const marc_norm_input,
                         const std::string german_term_field_spec,
                         const std::string translation_field_spec,
                         std::map<std::string, std::string> term_to_translation_maps[])
{
    std::set<std::string> german_tags_and_subfield_codes;
    if (unlikely(StringUtil::Split(german_term_field_spec, ':', &german_tags_and_subfield_codes) < 1))
        Error("ExtractTranslations: Need at least one translation field");

    std::set<std::string> translation_tags_and_subfield_codes;
    if (unlikely(StringUtil::Split(translation_field_spec, ':', &translation_tags_and_subfield_codes) < 1))
        Error("ExtractTranslations: Need at least one translation field");

    if (unlikely(not(german_tags_and_subfield_codes.size() == translation_tags_and_subfield_codes.size())))
        Error("ExtractTranslations: Number of german fields and number of translation fields must be equal");

    unsigned count(0);

    while (const MarcUtil::Record record = MarcUtil::Record::XmlFactory(marc_norm_input)) {
        std::map<std::string, std::vector<std::string>> all_translations;

        for (auto it = std::make_pair(german_tags_and_subfield_codes.cbegin(), translation_tags_and_subfield_codes.cbegin());
             it.first != german_tags_and_subfield_codes.cend();
             ++it.first, ++it.second) {

             const std::string german_tag((*it.first).substr(0, 3));
             const std::string german_subfields((*it.first).substr(3));
             const std::string translation_tag((*it.second).substr(0, 3));
             const std::string translation_subfields((*it.second).substr(3));

             for (auto subfield_iterator = std::make_pair(german_subfields.begin(), translation_subfields.cbegin());
                  subfield_iterator.first != german_subfields.cend();
                  ++subfield_iterator.first, ++subfield_iterator.second) {
                  std::vector<std::string> german_term_for_one_field;
                  record.extractSubfields(german_tag, std::string(1, *subfield_iterator.first), &german_term_for_one_field);

                  std::vector<std::string> translations;
                  // Always extract subfield 2 where "IxTheo" is located
                  record.extractSubfields(translation_tag, std::string(1, *subfield_iterator.second) + "2", &translations);

                  // For IxTheo-Translations add the language code in the same field
                  AugmentIxTheoTagWithLanguage(record, translation_tag, &translations);
                  if (not(german_term_for_one_field.empty()))
                      all_translations.insert(std::make_pair(StringUtil::Join(german_term_for_one_field, ' '), translations));
            }
        }

        for (auto it = all_translations.begin(); it != all_translations.end(); ++it) {
            std::string german_term = it->first;

            for (auto translation_vector_it = it->second.begin(); translation_vector_it != it->second.end(); ++translation_vector_it) {

                if (*translation_vector_it == "IxTheo_eng") {
                    term_to_translation_maps[EN].emplace(german_term, *(++translation_vector_it));
                } else if (*translation_vector_it == "IxTheo_fra") {
                    term_to_translation_maps[FR].emplace(german_term, *(++translation_vector_it));
                } else if (*translation_vector_it == "lcsh") {
                    term_to_translation_maps[EN].emplace(german_term, *(++translation_vector_it));
                } else if (*translation_vector_it == "ram") {
                    term_to_translation_maps[FR].emplace(german_term, *(++translation_vector_it));
                }
           }
       }
    ++count;
    }
}

std::unique_ptr<File> OpenInputFile(const std::string &filename) {
    std::string mode("r");
    if (MediaTypeUtil::GetFileMediaType(filename) == "application/lz4")
        mode += "u";
    std::unique_ptr<File> file(new File(filename, mode));
    if (file->fail())
        Error("can't open \"" + filename + "\" for reading!");

    return file;
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 3)
        Usage();

    const std::string norm_data_marc_input_filename(argv[1]);
    std::unique_ptr<File> norm_data_marc_input(OpenInputFile(norm_data_marc_input_filename));

    const std::string extracted_translations_filename(argv[2]);
    if (unlikely(norm_data_marc_input_filename == extracted_translations_filename))
        Error("Norm data input file name equals output file name!");

    std::string output_mode("w");
    if (norm_data_marc_input->isCompressingOrUncompressing())
        output_mode += 'c';

    // Create a file for each language
    std::vector<std::string> output_file_components;
    if (unlikely(StringUtil::Split(extracted_translations_filename, ".", &output_file_components) < 1))
        Error("extracted_translations_filename " + extracted_translations_filename + " is not valid");

    File *lang_files[NUMBER_OF_LANGUAGES];
    unsigned i(0);

    // Derive output components from given input filename
    std::string extension = (output_file_components.size() > 1) ? output_file_components.back() : "";
    std::string basename;
    if (not extension.empty())
        output_file_components.pop_back();
    basename = StringUtil::Join(output_file_components, ".");

    // Assemble output filename
    for (auto lang : languages_to_create) {
         lang = StringUtil::Trim(lang);

         std::string lang_file_name_str =
             (extension != "") ? basename + "_" + lang + "." + extension : basename + "_" + lang;

         lang_files[i] = new File(lang_file_name_str, output_mode);
         if (lang_files[i]->fail())
             Error("can't open \"" + lang_file_name_str + "\" for writing!");
         ++i;
    }

    try {
        std::map<std::string, std::string> term_to_translation_maps[NUMBER_OF_LANGUAGES];

        ExtractTranslations(norm_data_marc_input.get(),
                            "100a:110a:111a:130a:150a:151a",
                            "700a:710a:711a:730a:750a:751a",
                            term_to_translation_maps);
        for (auto line : term_to_translation_maps[EN]) {

             *(lang_files[EN]) << line.first << "|" << line.second << "\n";
        }

        for (auto line : term_to_translation_maps[FR]) {
             *(lang_files[FR]) << line.first << "|" << line.second << "\n";
        }

    } catch (const std::exception &x) {
      Error("caught exception: " + std::string(x.what()));
    }
}

<commit_msg>Clarifications in naming<commit_after>/** \file    extract_normdata_translations.cc
 *  \brief   Extract IxTheo and MACS translations from the normdata file and write it to
 *           language specific text files
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2016, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* The German term is found in Field 150
   Currently there are two different kinds of translations:
   IxTheo-Translations with the following definitions:

   710: Körperschaft - fremdsprachige Äquivalenz
   711: Konferenz - fremdsprachige Äquivalenz
   700: Person - fremdsprachige Äquivalenz
   730: Titel - fremdsprachige Äquivalenz
   750: Sachbegriff - fremdsprachige Äquivalenz
   751: Geografikum - fremdsprachige Äquivalenz

   LoC/Rameau Translations:
   700: Person - Bevorzugter Name in einem anderen Datenbestand
   710: Körperschaft - Bevorzugter Name in einem anderen Datenbestand
   711: Konferenz - Bevorzugte Benennung in einem anderen Datenbestand
   730: Einheitstitel - Bevorzugter Name in einem anderen Datenbestand
   750: Sachbegriff - Bevorzugte Benennung in einem anderen Datenbestand
   751: Geografikum - Bevorzugter Name in einem anderen Datenbestand
*/
#include <iostream>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "MarcUtil.h"
#include "MediaTypeUtil.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

// Languages to handle
const unsigned int NUMBER_OF_LANGUAGES = 2;
const std::vector<std::string> languages_to_create{ "en", "fr" };
enum Languages { EN, FR };

void Usage() {
    std::cerr << "Usage: " << ::progname << " norm_data_marc_input extracted_translations\n";
    std::exit(EXIT_FAILURE);
}

void AugmentIxTheoTagWithLanguage(const MarcUtil::Record &record, const std::string &tag, std::vector<std::string> * const translations) {
    auto ixtheo_pos(std::find(translations->begin(), translations->end(), "IxTheo"));
    if (ixtheo_pos != translations->end()) {
        std::vector<std::string> ixtheo_lang_codes;
        record.extractSubfields(tag, "9", &ixtheo_lang_codes);
        bool already_found_ixtheo_translation(false);
        for (const auto &lang_code : ixtheo_lang_codes) {
            if (lang_code[0] != 'L')
                continue;
            if (already_found_ixtheo_translation)
                continue;
            if (lang_code.find("eng") != std::string::npos and *ixtheo_pos != "IxTheo_eng") {
                *ixtheo_pos += + "_eng";
                already_found_ixtheo_translation = true;
            } else if (lang_code.find("fra") != std::string::npos and *ixtheo_pos != "IxTheo_fra") {
                *ixtheo_pos += "_fra";
                already_found_ixtheo_translation = true;
            } else
                Warning("Unsupported language code \"" + lang_code + "\" for PPN " + record.getFields()[0]);
        }
    }
}

void ExtractTranslations(File* const marc_norm_input,
                         const std::string german_term_field_spec,
                         const std::string translation_field_spec,
                         std::map<std::string, std::string> term_to_translation_maps[])
{
    std::set<std::string> german_tags_and_subfield_codes;
    if (unlikely(StringUtil::Split(german_term_field_spec, ':', &german_tags_and_subfield_codes) < 1))
        Error("ExtractTranslations: Need at least one translation field");

    std::set<std::string> translation_tags_and_subfield_codes;
    if (unlikely(StringUtil::Split(translation_field_spec, ':', &translation_tags_and_subfield_codes) < 1))
        Error("ExtractTranslations: Need at least one translation field");

    if (unlikely(not(german_tags_and_subfield_codes.size() == translation_tags_and_subfield_codes.size())))
        Error("ExtractTranslations: Number of German fields and number of translation fields must be equal");

    unsigned count(0);

    while (const MarcUtil::Record record = MarcUtil::Record::XmlFactory(marc_norm_input)) {
        std::map<std::string, std::vector<std::string>> all_translations;

        for (const auto german_and_translations_it = std::make_pair(german_tags_and_subfield_codes.cbegin(), translation_tags_and_subfield_codes.cbegin());
             german_and_translations_it.first != german_tags_and_subfield_codes.cend();
             ++german_and_translations_it.first, ++german_and_translations_it.second) {

             const std::string german_tag((*german_and_translations_it.first).substr(0, 3));
             const std::string german_subfields((*german_and_translations_it.first).substr(3));
             const std::string translation_tag((*german_and_translations_it.second).substr(0, 3));
             const std::string translation_subfields((*german_and_translations_it.second).substr(3));

             for (auto subfield_iterator = std::make_pair(german_subfields.begin(), translation_subfields.cbegin());
                  subfield_iterator.first != german_subfields.cend();
                  ++subfield_iterator.first, ++subfield_iterator.second) {
                  std::vector<std::string> german_term_for_one_field;
                  record.extractSubfields(german_tag, std::string(1, *subfield_iterator.first), &german_term_for_one_field);

                  std::vector<std::string> translations;
                  // Always extract subfield 2 where "IxTheo" is located
                  record.extractSubfields(translation_tag, std::string(1, *subfield_iterator.second) + "2", &translations);

                  // For IxTheo-Translations add the language code in the same field
                  AugmentIxTheoTagWithLanguage(record, translation_tag, &translations);
                  if (not(german_term_for_one_field.empty()))
                      all_translations.insert(std::make_pair(StringUtil::Join(german_term_for_one_field, ' '), translations));
            }
        }

        for (auto all_translations_it = all_translations.begin(); all_translations_it != all_translations.end(); ++all_translations_it) {
            std::string german_term = all_translations_it->first;

            for (auto translation_vector_it = all_translations_it->second.begin(); translation_vector_it != all_translations_it->second.end(); ++translation_vector_it) {

                if (*translation_vector_it == "IxTheo_eng") {
                    term_to_translation_maps[EN].emplace(german_term, *(++translation_vector_it));
                } else if (*translation_vector_it == "IxTheo_fra") {
                    term_to_translation_maps[FR].emplace(german_term, *(++translation_vector_it));
                } else if (*translation_vector_it == "lcsh") {
                    term_to_translation_maps[EN].emplace(german_term, *(++translation_vector_it));
                } else if (*translation_vector_it == "ram") {
                    term_to_translation_maps[FR].emplace(german_term, *(++translation_vector_it));
                }
           }
       }
    ++count;
    }
}

std::unique_ptr<File> OpenInputFile(const std::string &filename) {
    std::string mode("r");
    if (MediaTypeUtil::GetFileMediaType(filename) == "application/lz4")
        mode += "u";
    std::unique_ptr<File> file(new File(filename, mode));
    if (file->fail())
        Error("can't open \"" + filename + "\" for reading!");

    return file;
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 3)
        Usage();

    const std::string norm_data_marc_input_filename(argv[1]);
    std::unique_ptr<File> norm_data_marc_input(OpenInputFile(norm_data_marc_input_filename));

    const std::string extracted_translations_filename(argv[2]);
    if (unlikely(norm_data_marc_input_filename == extracted_translations_filename))
        Error("Norm data input file name equals output file name!");

    std::string output_mode("w");
    if (norm_data_marc_input->isCompressingOrUncompressing())
        output_mode += 'c';

    // Create a file for each language
    std::vector<std::string> output_file_components;
    if (unlikely(StringUtil::Split(extracted_translations_filename, ".", &output_file_components) < 1))
        Error("extracted_translations_filename " + extracted_translations_filename + " is not valid");

    File *lang_files[NUMBER_OF_LANGUAGES];
    unsigned i(0);

    // Derive output components from given input filename
    std::string extension = (output_file_components.size() > 1) ? output_file_components.back() : "";
    std::string basename;
    if (not extension.empty())
        output_file_components.pop_back();
    basename = StringUtil::Join(output_file_components, ".");

    // Assemble output filename
    for (auto lang : languages_to_create) {
         lang = StringUtil::Trim(lang);

         std::string lang_file_name_str =
             (extension != "") ? basename + "_" + lang + "." + extension : basename + "_" + lang;

         lang_files[i] = new File(lang_file_name_str, output_mode);
         if (lang_files[i]->fail())
             Error("can't open \"" + lang_file_name_str + "\" for writing!");
         ++i;
    }

    try {
        std::map<std::string, std::string> term_to_translation_maps[NUMBER_OF_LANGUAGES];

        ExtractTranslations(norm_data_marc_input.get(),
                            "100a:110a:111a:130a:150a:151a",
                            "700a:710a:711a:730a:750a:751a",
                            term_to_translation_maps);
        for (auto line : term_to_translation_maps[EN]) {

             *(lang_files[EN]) << line.first << "|" << line.second << "\n";
        }

        for (auto line : term_to_translation_maps[FR]) {
             *(lang_files[FR]) << line.first << "|" << line.second << "\n";
        }

    } catch (const std::exception &x) {
      Error("caught exception: " + std::string(x.what()));
    }
}

<|endoftext|>


<commit_before>// -*- mode: c++; coding: utf-8 -*-
/*! @file coord.hpp
    @brief Coordinate system
*/
#pragma once
#ifndef COORD_HPP_
#define COORD_HPP_

#include <cassert>
#include <cmath>
#include <vector>
#include <algorithm>
#include <numeric>

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

template <class T>
std::vector<T>& operator+=(std::vector<T>& lhs, const std::vector<T>& rhs) {
    assert(lhs.size() == rhs.size());
    std::transform(lhs.begin(), lhs.end(), rhs.begin(),
                   lhs.begin(), std::plus<T>());
    return lhs;
}

template <class T>
std::vector<T>& operator-=(std::vector<T>& lhs, const std::vector<T>& rhs) {
    assert(lhs.size() == rhs.size());
    std::transform(lhs.begin(), lhs.end(), rhs.begin(),
                   lhs.begin(), std::minus<T>());
    return lhs;
}

template <class T>
std::vector<T> operator+(std::vector<T> lhs, const std::vector<T>& rhs) {
    return lhs += rhs;
}

template <class T>
std::vector<T> operator-(std::vector<T> lhs, const std::vector<T>& rhs) {
    return lhs -= rhs;
}

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

class Coord {
  public:
    Coord() = delete;
    explicit Coord(const size_t d): dimensions(d) {}
    virtual ~Coord() = default;
    const size_t dimensions;
    const std::vector<std::vector<int>>& directions() const {return directions_;}
    std::vector<std::vector<int>> neighbors(const std::vector<int>& v) const {
        std::vector<std::vector<int>> output = directions_;
        for (auto& d: output) {
            d += v;
        }
        return output;
    }
    std::vector<int> outward(const std::vector<int>& v) const {
        const auto candidates = neighbors(v);
        return *std::max_element(candidates.begin(), candidates.end(),
                                 [this](const std::vector<int>& lhs, const std::vector<int>& rhs) {
            return distance(lhs) < distance(rhs);
        });
    }
    virtual size_t distance(const std::vector<int>& v) const = 0;
    virtual std::vector<std::vector<int>> origins() const {
        const size_t n = std::pow(2, dimensions);
        std::vector<std::vector<int>> output;
        output.reserve(n);
        for (size_t i=0; i<n; ++i) {
            std::bitset<3> bs(i);
            std::vector<int> v(dimensions);
            for (size_t j=0; j<dimensions; ++j) {
                v[j] = static_cast<int>(bs[j]);
            }
            output.push_back(v);
        }
        return output;
    }
  protected:
    std::vector<std::vector<int>> directions_;
};

class Neumann: public Coord {
  public:
    Neumann() = delete;
    explicit Neumann(const size_t d): Coord(d) {
        directions_.reserve(2 * dimensions);
        std::vector<int> v(dimensions, 0);
        v.back() += 1;
        do {
            directions_.push_back(v);
        } while (std::next_permutation(v.begin(), v.end()));
        v.assign(dimensions, 0);
        v.front() -= 1;
        do {
            directions_.push_back(v);
        } while (std::next_permutation(v.begin(), v.end()));
    }
    size_t distance(const std::vector<int>& v) const {
        return std::accumulate(v.begin(), v.end(), 0, [](const int lhs, const int rhs) {
            return std::abs(lhs) + std::abs(rhs);
        });
    }
};

class Moore: public Coord {
  public:
    Moore() = delete;
    explicit Moore(const size_t d): Coord(d) {
        directions_.reserve(std::pow(3, dimensions) - 1);
        for (const int x: {-1, 0, 1}) {
            for (const int y: {-1, 0, 1}) {
                if (dimensions == 2) {
                    if (x == 0 && y == 0) continue;
                    directions_.push_back({x, y});
                    continue;
                }
                for (const int z: {-1, 0, 1}) {
                    if (x == 0 && y == 0 && z == 0) continue;
                    directions_.push_back({x, y, z});
                }
            }
        }
    }
    size_t distance(const std::vector<int>& v) const {
        return std::abs(*std::max_element(v.begin(), v.end(), [](const int lhs, const int rhs) {
            return std::abs(lhs) < std::abs(rhs);
        }));
    }
};

class Hexagonal: public Coord {
  public:
    Hexagonal() = delete;
    explicit Hexagonal(const size_t d): Coord(d) {
        std::vector<int> v{-1, 0, 1};
        if (dimensions == 2) {
            directions_.reserve(6);
            do {
                directions_.push_back({v[0], v[1]});
            } while (std::next_permutation(v.begin(), v.end()));
        }
        else {
            directions_.reserve(12);
            do {
                directions_.push_back({v[0], v[1], 0});
            } while (std::next_permutation(v.begin(), v.end()));
            directions_.push_back({0, 0, -1});
            directions_.push_back({1, 0, -1});
            directions_.push_back({1, -1, -1});
            directions_.push_back({0, 0, 1});
            directions_.push_back({-1, 0, 1});
            directions_.push_back({-1, 1, 1});
        }
    }
    size_t distance(const std::vector<int>& v) const {
        std::vector<size_t> absv;
        absv.reserve(v.size() * 2);
        for (auto x: v) {
            absv.push_back(std::abs(x));
        }
        absv.push_back(std::abs(v[0] + v[1]));
        if (v.size() == 3) {
            absv.push_back(std::abs(v[0] + v[2]));
        }
        return *std::max_element(absv.begin(), absv.end());
    }

    std::vector<std::vector<int>> origins() const {
        std::vector<std::vector<int>> output = Neumann(dimensions).origins();
        if (dimensions == 3) {
            output.resize(3);
            output.push_back({1, 0, -1});
        }
        return output;
    }
};

#endif /* COORD_HPP_ */
<commit_msg>Initialize max_dimensions in Coord::Ctor()<commit_after>// -*- mode: c++; coding: utf-8 -*-
/*! @file coord.hpp
    @brief Coordinate system
*/
#pragma once
#ifndef COORD_HPP_
#define COORD_HPP_

#include <cassert>
#include <cmath>
#include <vector>
#include <algorithm>
#include <numeric>

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

template <class T>
std::vector<T>& operator+=(std::vector<T>& lhs, const std::vector<T>& rhs) {
    assert(lhs.size() == rhs.size());
    std::transform(lhs.begin(), lhs.end(), rhs.begin(),
                   lhs.begin(), std::plus<T>());
    return lhs;
}

template <class T>
std::vector<T>& operator-=(std::vector<T>& lhs, const std::vector<T>& rhs) {
    assert(lhs.size() == rhs.size());
    std::transform(lhs.begin(), lhs.end(), rhs.begin(),
                   lhs.begin(), std::minus<T>());
    return lhs;
}

template <class T>
std::vector<T> operator+(std::vector<T> lhs, const std::vector<T>& rhs) {
    return lhs += rhs;
}

template <class T>
std::vector<T> operator-(std::vector<T> lhs, const std::vector<T>& rhs) {
    return lhs -= rhs;
}

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

class Coord {
  public:
    Coord() = delete;
    Coord(const size_t d): dimensions(d) {}
    virtual ~Coord() = default;
    const size_t dimensions;
    const std::vector<std::vector<int>>& directions() const {return directions_;}
    size_t max_neighbors() const {return max_neighbors_;}
    std::vector<std::vector<int>> neighbors(const std::vector<int>& v) const {
        std::vector<std::vector<int>> output = directions_;
        for (auto& d: output) {
            d += v;
        }
        return output;
    }
    std::vector<int> outward(const std::vector<int>& v) const {
        const auto candidates = neighbors(v);
        return *std::max_element(candidates.begin(), candidates.end(),
                                 [this](const std::vector<int>& lhs, const std::vector<int>& rhs) {
            return distance(lhs) < distance(rhs);
        });
    }
    virtual size_t distance(const std::vector<int>& v) const = 0;
    virtual std::vector<std::vector<int>> origins() const {
        const size_t n = std::pow(2, dimensions);
        std::vector<std::vector<int>> output;
        output.reserve(n);
        for (size_t i=0; i<n; ++i) {
            std::bitset<3> bs(i);
            std::vector<int> v(dimensions);
            for (size_t j=0; j<dimensions; ++j) {
                v[j] = static_cast<int>(bs[j]);
            }
            output.push_back(v);
        }
        return output;
    }
  protected:
    std::vector<std::vector<int>> directions_;
    size_t max_neighbors_;
};

class Neumann: public Coord {
  public:
    Neumann() = delete;
    explicit Neumann(const size_t d): Coord(d) {
        max_neighbors_ = 2 * d;
        directions_.reserve(max_neighbors_);
        std::vector<int> v(dimensions, 0);
        v.back() += 1;
        do {
            directions_.push_back(v);
        } while (std::next_permutation(v.begin(), v.end()));
        v.assign(dimensions, 0);
        v.front() -= 1;
        do {
            directions_.push_back(v);
        } while (std::next_permutation(v.begin(), v.end()));
    }
    size_t distance(const std::vector<int>& v) const {
        return std::accumulate(v.begin(), v.end(), 0, [](const int lhs, const int rhs) {
            return std::abs(lhs) + std::abs(rhs);
        });
    }
};

//! Neumann + diagonal cells
class Moore: public Coord {
  public:
    Moore() = delete;
    explicit Moore(const size_t d): Coord(d) {
        max_neighbors_ = std::pow(3, dimensions) - 1;
        directions_.reserve(max_neighbors_);
        for (const int x: {-1, 0, 1}) {
            for (const int y: {-1, 0, 1}) {
                if (dimensions == 2) {
                    if (x == 0 && y == 0) continue;
                    directions_.push_back({x, y});
                    continue;
                }
                for (const int z: {-1, 0, 1}) {
                    if (x == 0 && y == 0 && z == 0) continue;
                    directions_.push_back({x, y, z});
                }
            }
        }
    }
    size_t distance(const std::vector<int>& v) const {
        return std::abs(*std::max_element(v.begin(), v.end(), [](const int lhs, const int rhs) {
            return std::abs(lhs) < std::abs(rhs);
        }));
    }
};

class Hexagonal: public Coord {
  public:
    Hexagonal() = delete;
    explicit Hexagonal(const size_t d): Coord(d) {
        max_neighbors_ = 6 * (d - 1);
        std::vector<int> v{-1, 0, 1};
        directions_.reserve(max_neighbors_);
        if (dimensions == 2) {
            do {
                directions_.push_back({v[0], v[1]});
            } while (std::next_permutation(v.begin(), v.end()));
        }
        else {
            do {
                directions_.push_back({v[0], v[1], 0});
            } while (std::next_permutation(v.begin(), v.end()));
            directions_.push_back({0, 0, -1});
            directions_.push_back({1, 0, -1});
            directions_.push_back({1, -1, -1});
            directions_.push_back({0, 0, 1});
            directions_.push_back({-1, 0, 1});
            directions_.push_back({-1, 1, 1});
        }
    }
    size_t distance(const std::vector<int>& v) const {
        std::vector<size_t> absv;
        absv.reserve(v.size() * 2);
        for (auto x: v) {
            absv.push_back(std::abs(x));
        }
        absv.push_back(std::abs(v[0] + v[1]));
        if (v.size() == 3) {
            absv.push_back(std::abs(v[0] + v[2]));
        }
        return *std::max_element(absv.begin(), absv.end());
    }

    std::vector<std::vector<int>> origins() const {
        std::vector<std::vector<int>> output = Neumann(dimensions).origins();
        if (dimensions == 3) {
            output.resize(3);
            output.push_back({1, 0, -1});
        }
        return output;
    }
};

#endif /* COORD_HPP_ */
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include <fb/fbjni/CoreClasses.h>

#include <fb/assert.h>
#include <fb/log.h>

#include <alloca.h>
#include <cstdlib>
#include <ios>
#include <stdexcept>
#include <stdio.h>
#include <string>
#include <system_error>

#include <jni.h>

namespace facebook {
namespace jni {

namespace {
class JRuntimeException : public JavaClass<JRuntimeException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/lang/RuntimeException;";

  static local_ref<JRuntimeException> create(const char* str) {
    return newInstance(make_jstring(str));
  }

  static local_ref<JRuntimeException> create() {
    return newInstance();
  }
};

class JIOException : public JavaClass<JIOException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/io/IOException;";

  static local_ref<JIOException> create(const char* str) {
    return newInstance(make_jstring(str));
  }
};

class JOutOfMemoryError : public JavaClass<JOutOfMemoryError, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/lang/OutOfMemoryError;";

  static local_ref<JOutOfMemoryError> create(const char* str) {
    return newInstance(make_jstring(str));
  }
};

class JArrayIndexOutOfBoundsException : public JavaClass<JArrayIndexOutOfBoundsException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/lang/ArrayIndexOutOfBoundsException;";

  static local_ref<JArrayIndexOutOfBoundsException> create(const char* str) {
    return newInstance(make_jstring(str));
  }
};

class JUnknownCppException : public JavaClass<JUnknownCppException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/UnknownCppException;";

  static local_ref<JUnknownCppException> create() {
    return newInstance();
  }

  static local_ref<JUnknownCppException> create(const char* str) {
    return newInstance(make_jstring(str));
  }
};

class JCppSystemErrorException : public JavaClass<JCppSystemErrorException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/CppSystemErrorException;";

  static local_ref<JCppSystemErrorException> create(const std::system_error& e) {
    return newInstance(make_jstring(e.what()), e.code().value());
  }
};

// Exception throwing & translating functions //////////////////////////////////////////////////////

// Functions that throw Java exceptions

void setJavaExceptionAndAbortOnFailure(alias_ref<JThrowable> throwable) {
  auto env = Environment::current();
  if (throwable) {
    env->Throw(throwable.get());
  }
  if (env->ExceptionCheck() != JNI_TRUE) {
    std::abort();
  }
}

}

// Functions that throw C++ exceptions

// TODO(T6618159) Take a stack dump here to save context if it results in a crash when propagated
void throwPendingJniExceptionAsCppException() {
  JNIEnv* env = Environment::current();
  if (env->ExceptionCheck() == JNI_FALSE) {
    return;
  }

  auto throwable = adopt_local(env->ExceptionOccurred());
  if (!throwable) {
    throw std::runtime_error("Unable to get pending JNI exception.");
  }
  env->ExceptionClear();

  throw JniException(throwable);
}

void throwCppExceptionIf(bool condition) {
  if (!condition) {
    return;
  }

  auto env = Environment::current();
  if (env->ExceptionCheck() == JNI_TRUE) {
    throwPendingJniExceptionAsCppException();
    return;
  }

  throw JniException();
}

void throwNewJavaException(jthrowable throwable) {
  throw JniException(wrap_alias(throwable));
}

void throwNewJavaException(const char* throwableName, const char* msg) {
  // If anything of the fbjni calls fail, an exception of a suitable
  // form will be thrown, which is what we want.
  auto throwableClass = findClassLocal(throwableName);
  auto throwable = throwableClass->newObject(
    throwableClass->getConstructor<jthrowable(jstring)>(),
    make_jstring(msg).release());
  throwNewJavaException(throwable.get());
}

// Translate C++ to Java Exception

namespace {

// The implementation std::rethrow_if_nested uses a dynamic_cast to determine
// if the exception is a nested_exception. If the exception is from a library
// built with -fno-rtti, then that will crash. This avoids that.
void rethrow_if_nested() {
  try {
    throw;
  } catch (const std::nested_exception& e) {
    e.rethrow_nested();
  } catch (...) {
  }
}

// For each exception in the chain of the currently handled exception, func
// will be called with that exception as the currently handled exception (in
// reverse order, i.e. innermost first).
void denest(std::function<void()> func) {
  try {
    throw;
  } catch (const std::exception& e) {
    try {
      rethrow_if_nested();
    } catch (...) {
      denest(func);
    }
    func();
  } catch (...) {
    func();
  }
}
}

void translatePendingCppExceptionToJavaException() noexcept {
  local_ref<JThrowable> previous;
  auto func = [&previous] () {
    local_ref<JThrowable> current;
    try {
      throw;
    } catch(const JniException& ex) {
      current = ex.getThrowable();
    } catch(const std::ios_base::failure& ex) {
      current = JIOException::create(ex.what());
    } catch(const std::bad_alloc& ex) {
      current = JOutOfMemoryError::create(ex.what());
    } catch(const std::out_of_range& ex) {
      current = JArrayIndexOutOfBoundsException::create(ex.what());
    } catch(const std::system_error& ex) {
      current = JCppSystemErrorException::create(ex);
    } catch(const std::runtime_error& ex) {
      current = JRuntimeException::create(ex.what());
    } catch(const std::exception& ex) {
      current = JCppException::create(ex.what());
    } catch(const char* msg) {
      current = JUnknownCppException::create(msg);
    } catch(...) {
<commit_msg>Lines authored by mhorowitz<commit_after>/*
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include <fb/fbjni/CoreClasses.h>

#include <fb/assert.h>
#include <fb/log.h>

#include <alloca.h>
#include <cstdlib>
#include <ios>
#include <stdexcept>
#include <stdio.h>
#include <string>
#include <system_error>

#include <jni.h>

namespace facebook {
namespace jni {

namespace {
class JRuntimeException : public JavaClass<JRuntimeException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/lang/RuntimeException;";

  static local_ref<JRuntimeException> create(const char* str) {
    return newInstance(make_jstring(str));
  }

  static local_ref<JRuntimeException> create() {
    return newInstance();
  }
};

class JIOException : public JavaClass<JIOException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/io/IOException;";

  static local_ref<JIOException> create(const char* str) {
    return newInstance(make_jstring(str));
  }
};

class JOutOfMemoryError : public JavaClass<JOutOfMemoryError, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/lang/OutOfMemoryError;";

  static local_ref<JOutOfMemoryError> create(const char* str) {
    return newInstance(make_jstring(str));
  }
};

class JArrayIndexOutOfBoundsException : public JavaClass<JArrayIndexOutOfBoundsException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/lang/ArrayIndexOutOfBoundsException;";

  static local_ref<JArrayIndexOutOfBoundsException> create(const char* str) {
    return newInstance(make_jstring(str));
  }
};

class JUnknownCppException : public JavaClass<JUnknownCppException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/UnknownCppException;";

  static local_ref<JUnknownCppException> create() {
    return newInstance();
  }

  static local_ref<JUnknownCppException> create(const char* str) {
    return newInstance(make_jstring(str));
  }
};

class JCppSystemErrorException : public JavaClass<JCppSystemErrorException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/CppSystemErrorException;";

  static local_ref<JCppSystemErrorException> create(const std::system_error& e) {
    return newInstance(make_jstring(e.what()), e.code().value());
  }
};

// Exception throwing & translating functions //////////////////////////////////////////////////////

// Functions that throw Java exceptions

void setJavaExceptionAndAbortOnFailure(alias_ref<JThrowable> throwable) {
  auto env = Environment::current();
  if (throwable) {
    env->Throw(throwable.get());
  }
  if (env->ExceptionCheck() != JNI_TRUE) {
    std::abort();
  }
}

}

// Functions that throw C++ exceptions

// TODO(T6618159) Take a stack dump here to save context if it results in a crash when propagated
void throwPendingJniExceptionAsCppException() {
  JNIEnv* env = Environment::current();
  if (env->ExceptionCheck() == JNI_FALSE) {
    return;
  }

  auto throwable = adopt_local(env->ExceptionOccurred());
  if (!throwable) {
    throw std::runtime_error("Unable to get pending JNI exception.");
  }
  env->ExceptionClear();

  throw JniException(throwable);
}

void throwCppExceptionIf(bool condition) {
  if (!condition) {
    return;
  }

  auto env = Environment::current();
  if (env->ExceptionCheck() == JNI_TRUE) {
    throwPendingJniExceptionAsCppException();
    return;
  }

  throw JniException();
}

void throwNewJavaException(jthrowable throwable) {
  throw JniException(wrap_alias(throwable));
}

void throwNewJavaException(const char* throwableName, const char* msg) {
  // If anything of the fbjni calls fail, an exception of a suitable
  // form will be thrown, which is what we want.
  auto throwableClass = findClassLocal(throwableName);
  auto throwable = throwableClass->newObject(
    throwableClass->getConstructor<jthrowable(jstring)>(),
    make_jstring(msg).release());
  throwNewJavaException(throwable.get());
}

// Translate C++ to Java Exception

namespace {

// The implementation std::rethrow_if_nested uses a dynamic_cast to determine
// if the exception is a nested_exception. If the exception is from a library
// built with -fno-rtti, then that will crash. This avoids that.
void rethrow_if_nested() {
  try {
    throw;
  } catch (const std::nested_exception& e) {
    e.rethrow_nested();
  } catch (...) {
  }
}

// For each exception in the chain of the currently handled exception, func
// will be called with that exception as the currently handled exception (in
// reverse order, i.e. innermost first).
void denest(std::function<void()> func) {
  try {
    throw;
  } catch (const std::exception& e) {
    try {
      rethrow_if_nested();
    } catch (...) {
      denest(func);
    }
    func();
  } catch (...) {
    func();
  }
}
}

void translatePendingCppExceptionToJavaException() noexcept {
  local_ref<JThrowable> previous;
  auto func = [&previous] () {
    local_ref<JThrowable> current;
    try {
      throw;
    } catch(const JniException& ex) {
      current = ex.getThrowable();
    } catch(const std::ios_base::failure& ex) {
      current = JIOException::create(ex.what());
    } catch(const std::bad_alloc& ex) {
      current = JOutOfMemoryError::create(ex.what());
    } catch(const std::out_of_range& ex) {
      current = JArrayIndexOutOfBoundsException::create(ex.what());
    } catch(const std::system_error& ex) {
      current = JCppSystemErrorException::create(ex);
    } catch(const std::runtime_error& ex) {
      current = JRuntimeException::create(ex.what());
    } catch(const std::exception& ex) {
      current = JCppException::create(ex.what());
    } catch(const char* msg) {
      current = JUnknownCppException::create(msg);
    } catch(...) {
      current = JUnknownCppException::create();
    }
    if (previous) {
      current->initCause(previous);
<|endoftext|>


<commit_before>// $Id$
# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_CSUM_HPP
# define CPPAD_LOCAL_OPTIMIZE_RECORD_CSUM_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell

CppAD is distributed under multiple licenses. This distribution is under
the terms of the
                    Eclipse Public License Version 1.0.

A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
/*!
\file record_csum.hpp
Recording a cummulative cummulative summation.
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize  {
/*!
Recording a cummulative cummulative summation.

<!-- replace prototype -->
\param tape
is a vector that maps a variable index, in the old operation sequence,
to the corresponding struct_old_variable information.
Note that the old variable index must be greater than or equal zero and
less than tape.size().

\param current
is the index in the old operation sequence for
the variable corresponding to the result for the current operator.
It follows that current < tape.size() and NumRes( tape[current].op ) > 0.
Suppose i <= current, j < NumArg( tape[i] ), and k = tape[i].arg[j],
It is assumed that tape[i].arg[j] is connected to the dependent variables
and tape[k].new_var has been set to the corresponding variable.
Note that tape[i].arg[j] < i <= current and
tape[k].new_var <= k < current.

\param npar
is the number of parameters corresponding to the old operation sequence.

\param par
is a vector of length npar containing the parameters
the old operation sequence; i.e.,
given a parameter index i < npar, the corresponding parameter value is par[i].
<!-- end prototype -->

\param rec
is the object that will record the operations.

\param work
Is temporary work space. On input and output,
work.op_stack, work.add_stack, and work.sub_stack, are all empty.
These stacks are passed in so that they are created once
and then be reused with calls to record_csum.

\param var2op
mapping from old variable index to old operator index
(only used for error checking)

\param op_info
mapping from old index to operator information
(only used for error checking)

\par Assumptions
tape[i].new_var is not yet defined for any node i that is csum_connected
to the current node; i.e., tape[i].new_var = tape.size() for all such nodes.
For example; suppose j is an argument in the old operation sequence for the
current operator, i = tape[current].arg[j], and
tape[arg[j]].connect_type == csum_connected. It follows that
tape[i].new_var == tape.size().

\par Restriction:
tape[current].op
must be one of AddpvOp, AddvvOp, SubpvOp, SubvpOp, SubvvOp.
tape[current].connect_type must be yes_connected.
tape[j].connect_type == csum_connected for some index
j that is a variable argument for the current operation.
*/

template <class Base>
struct_size_pair record_csum(
	const CppAD::vector<struct struct_old_variable>&   tape           ,
	size_t                                             current        ,
	size_t                                             npar           ,
	const Base*                                        par            ,
	recorder<Base>*                                    rec            ,
	// local information passed so stacks need not be allocated for every call
	struct_csum_stacks&                                work           ,
	const vector<size_t>&                              var2op         ,
	const vector<struct_op_info>&                      op_info        )
{
	// check assumption about work space
	CPPAD_ASSERT_UNKNOWN( work.op_stack.empty() );
	CPPAD_ASSERT_UNKNOWN( work.add_stack.empty() );
	CPPAD_ASSERT_UNKNOWN( work.sub_stack.empty() );
	//
	CPPAD_ASSERT_UNKNOWN( tape[current].connect_type == yes_connected );
# ifndef NDEBUG
	{	size_t i_op = var2op[current];
		CPPAD_ASSERT_UNKNOWN( ! op_info[i_op].csum_connected );
	}
# endif

	size_t                        i;
	OpCode                        op;
	const addr_t*                 arg;
	bool                          add;
	struct struct_csum_variable var;
	//
	// information corresponding to the root node in the cummulative summation
	var.op  = tape[current].op;   // this operator
	var.arg = tape[current].arg;  // arguments for this operator
	var.add = true;               // was parrent operator positive or negative
	//
	// initialize stack as containing this one operator
	work.op_stack.push( var );
	//
	// initialize sum of parameter values as zero
	Base sum_par(0);
	//
# ifndef NDEBUG
	bool ok = false;
	if( var.op == SubvpOp )
		ok = tape[ tape[current].arg[0] ].connect_type == csum_connected;
	if( var.op == AddpvOp || var.op == SubpvOp )
		ok = tape[ tape[current].arg[1] ].connect_type == csum_connected;
	if( var.op == AddvvOp || var.op == SubvvOp )
	{	ok  = tape[ tape[current].arg[0] ].connect_type == csum_connected;
		ok |= tape[ tape[current].arg[1] ].connect_type == csum_connected;
	}
	CPPAD_ASSERT_UNKNOWN( ok );
# endif
	//
	// while there are operators left on the stack
	while( ! work.op_stack.empty() )
	{	// get this summation operator
		var     = work.op_stack.top();
		work.op_stack.pop();
		op      = var.op;
		arg     = var.arg;
		add     = var.add;
		//
		// process first argument to this operator
		switch(op)
		{	// cases where first argument is a parameter
			case AddpvOp:
			case SubpvOp:
			CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < npar );
			// first argument has same sign as parent node
			if( add )
				sum_par += par[arg[0]];
			else	sum_par -= par[arg[0]];
			break;

			// cases where first argument is a variable
			case AddvvOp:
			case SubvpOp:
			case SubvvOp:
			//
			// check if the first argument is csum_connected
# ifndef NDEBUG
			{	bool flag1 = tape[arg[0]].connect_type == csum_connected;
				bool flag2 = op_info[ var2op[ arg[0] ] ].csum_connected;
				CPPAD_ASSERT_UNKNOWN( flag1 == flag2 );
			}
# endif
			if( tape[arg[0]].connect_type == csum_connected )
			{	CPPAD_ASSERT_UNKNOWN(
					size_t(tape[arg[0]].new_var) == tape.size()
				);
				// push the operator corresponding to the first argument
				var.op  = tape[arg[0]].op;
				var.arg = tape[arg[0]].arg;
				// first argument has same sign as parent node
				var.add = add;
				work.op_stack.push( var );
			}
			else
			{	// there are no nodes below this one
				CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < current );
				CPPAD_ASSERT_UNKNOWN( tape[arg[0]].new_var <= arg[0] );
				if( add )
					work.add_stack.push(arg[0]);
				else	work.sub_stack.push(arg[0]);
			}
			break;

			default:
			CPPAD_ASSERT_UNKNOWN(false);
		}
		// process second argument to this operator
		switch(op)
		{	// cases where second argument is a parameter
			case SubvpOp:
			CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < npar );
			// second argument has opposite sign of parent node
			if( add )
				sum_par -= par[arg[1]];
			else	sum_par += par[arg[1]];
			break;

			// cases where second argument is a variable and has opposite sign
			case SubvvOp:
			case SubpvOp:
			add = ! add;

			// cases where second argument is a variable and has same sign
			case AddvvOp:
			case AddpvOp:
			// check if the second argument is csum_connected
# ifndef NDEBUG
			{	bool flag1 = tape[arg[1]].connect_type == csum_connected;
				bool flag2 = op_info[ var2op[ arg[1] ] ].csum_connected;
				CPPAD_ASSERT_UNKNOWN( flag1 == flag2 );
			}
# endif
			if( tape[arg[1]].connect_type == csum_connected )
			{	CPPAD_ASSERT_UNKNOWN(
					size_t(tape[arg[1]].new_var) == tape.size()
				);
				// push the operator corresoponding to the second arugment
				var.op   = tape[arg[1]].op;
				var.arg  = tape[arg[1]].arg;
				var.add  = add;
				work.op_stack.push( var );
			}
			else
			{	// there are no nodes below this one
				CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < current );
				CPPAD_ASSERT_UNKNOWN( tape[arg[1]].new_var <=  arg[1] );
				if( add )
					work.add_stack.push(arg[1]);
				else	work.sub_stack.push(arg[1]);
			}
			break;

			default:
			CPPAD_ASSERT_UNKNOWN(false);
		}
	}
	// number of variables to add in this cummulative sum operator
	size_t n_add = work.add_stack.size();
	// number of variables to subtract in this cummulative sum operator
	size_t n_sub = work.sub_stack.size();
	//
	rec->PutArg(n_add);                // arg[0]
	rec->PutArg(n_sub);                // arg[1]
	size_t new_arg = rec->PutPar(sum_par);
	rec->PutArg(new_arg);              // arg[2]
	// addition arguments
	for(i = 0; i < n_add; i++)
	{	CPPAD_ASSERT_UNKNOWN( ! work.add_stack.empty() );
		size_t old_arg = work.add_stack.top();
		new_arg        = tape[old_arg].new_var;
		CPPAD_ASSERT_UNKNOWN( new_arg < current );
		rec->PutArg(new_arg);         // arg[3+i]
		work.add_stack.pop();
	}
	// subtraction arguments
	for(i = 0; i < n_sub; i++)
	{	CPPAD_ASSERT_UNKNOWN( ! work.sub_stack.empty() );
		size_t old_arg = work.sub_stack.top();
		new_arg        = tape[old_arg].new_var;
		CPPAD_ASSERT_UNKNOWN( new_arg < current );
		rec->PutArg(new_arg);      // arg[3 + arg[0] + i]
		work.sub_stack.pop();
	}
	// number of additions plus number of subtractions
	rec->PutArg(n_add + n_sub);        // arg[3 + arg[0] + arg[1]]
	//
	// return value
	struct_size_pair ret;
	ret.i_op  = rec->num_op_rec();
	ret.i_var = rec->PutOp(CSumOp);
	//
	return ret;
}

} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE

# endif
<commit_msg>optimize branch: record_csum.hpp: remove use of tape csum_connected field.<commit_after>// $Id$
# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_CSUM_HPP
# define CPPAD_LOCAL_OPTIMIZE_RECORD_CSUM_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell

CppAD is distributed under multiple licenses. This distribution is under
the terms of the
                    Eclipse Public License Version 1.0.

A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
/*!
\file record_csum.hpp
Recording a cummulative cummulative summation.
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize  {
/*!
Recording a cummulative cummulative summation.

<!-- replace prototype -->
\param tape
is a vector that maps a variable index, in the old operation sequence,
to the corresponding struct_old_variable information.
Note that the old variable index must be greater than or equal zero and
less than tape.size().

\param current
is the index in the old operation sequence for
the variable corresponding to the result for the current operator.
It follows that current < tape.size() and NumRes( tape[current].op ) > 0.
Suppose i <= current, j < NumArg( tape[i] ), and k = tape[i].arg[j],
It is assumed that tape[i].arg[j] is connected to the dependent variables
and tape[k].new_var has been set to the corresponding variable.
Note that tape[i].arg[j] < i <= current and
tape[k].new_var <= k < current.

\param npar
is the number of parameters corresponding to the old operation sequence.

\param par
is a vector of length npar containing the parameters
the old operation sequence; i.e.,
given a parameter index i < npar, the corresponding parameter value is par[i].
<!-- end prototype -->

\param rec
is the object that will record the operations.

\param work
Is temporary work space. On input and output,
work.op_stack, work.add_stack, and work.sub_stack, are all empty.
These stacks are passed in so that they are created once
and then be reused with calls to record_csum.

\param var2op
mapping from old variable index to old operator index
(only used for error checking)

\param op_info
mapping from old index to operator information
(only used for error checking)

\par Assumptions
tape[i].new_var is not yet defined for any node i that is csum_connected
to the current node; i.e., tape[i].new_var = tape.size() for all such nodes.
For example; suppose j is an argument in the old operation sequence for the
current operator, i = tape[current].arg[j], and
tape[arg[j]].connect_type == csum_connected. It follows that
tape[i].new_var == tape.size().

\par Restriction:
tape[current].op
must be one of AddpvOp, AddvvOp, SubpvOp, SubvpOp, SubvvOp.
tape[current].connect_type must be yes_connected.
tape[j].connect_type == csum_connected for some index
j that is a variable argument for the current operation.
*/

template <class Base>
struct_size_pair record_csum(
	const CppAD::vector<struct struct_old_variable>&   tape           ,
	size_t                                             current        ,
	size_t                                             npar           ,
	const Base*                                        par            ,
	recorder<Base>*                                    rec            ,
	// local information passed so stacks need not be allocated for every call
	struct_csum_stacks&                                work           ,
	const vector<size_t>&                              var2op         ,
	const vector<struct_op_info>&                      op_info        )
{
	// check assumption about work space
	CPPAD_ASSERT_UNKNOWN( work.op_stack.empty() );
	CPPAD_ASSERT_UNKNOWN( work.add_stack.empty() );
	CPPAD_ASSERT_UNKNOWN( work.sub_stack.empty() );
	//
	size_t i_op = var2op[current];
	CPPAD_ASSERT_UNKNOWN( ! op_info[i_op].csum_connected );
	//
	size_t                        i;
	OpCode                        op;
	const addr_t*                 arg;
	bool                          add;
	struct struct_csum_variable var;
	//
	// information corresponding to the root node in the cummulative summation
	var.op  = op_info[i_op].op;   // this operator
	var.arg = op_info[i_op].arg;  // arguments for this operator
	var.add = true;               // was parrent operator positive or negative
	//
	// initialize stack as containing this one operator
	work.op_stack.push( var );
	//
	// initialize sum of parameter values as zero
	Base sum_par(0);
	//
# ifndef NDEBUG
	bool ok = false;
	struct_op_info info = op_info[i_op];
	if( var.op == SubvpOp )
		ok = op_info[ var2op[info.arg[0]] ].csum_connected;
	if( var.op == AddpvOp || var.op == SubpvOp )
		ok = op_info[ var2op[info.arg[1]] ].csum_connected;
	if( var.op == AddvvOp || var.op == SubvvOp )
	{	ok  = op_info[ var2op[info.arg[0]] ].csum_connected;
		ok |= op_info[ var2op[info.arg[1]] ].csum_connected;
	}
	CPPAD_ASSERT_UNKNOWN( ok );
# endif
	//
	// while there are operators left on the stack
	while( ! work.op_stack.empty() )
	{	// get this summation operator
		var     = work.op_stack.top();
		work.op_stack.pop();
		op      = var.op;
		arg     = var.arg;
		add     = var.add;
		//
		// process first argument to this operator
		switch(op)
		{	// cases where first argument is a parameter
			case AddpvOp:
			case SubpvOp:
			CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < npar );
			// first argument has same sign as parent node
			if( add )
				sum_par += par[arg[0]];
			else	sum_par -= par[arg[0]];
			break;

			// cases where first argument is a variable
			case AddvvOp:
			case SubvpOp:
			case SubvvOp:
			//
			// check if the first argument is csum_connected
# ifndef NDEBUG
			{	bool flag1 = op_info[var2op[arg[0]]].csum_connected;
				bool flag2 = op_info[ var2op[ arg[0] ] ].csum_connected;
				CPPAD_ASSERT_UNKNOWN( flag1 == flag2 );
			}
# endif
			if( op_info[var2op[arg[0]]].csum_connected )
			{	CPPAD_ASSERT_UNKNOWN(
					size_t(tape[arg[0]].new_var) == tape.size()
				);
				// push the operator corresponding to the first argument
				var.op  = op_info[ var2op[arg[0]] ].op;
				var.arg = op_info[ var2op[arg[0]] ].arg;
				// first argument has same sign as parent node
				var.add = add;
				work.op_stack.push( var );
			}
			else
			{	// there are no nodes below this one
				CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < current );
				CPPAD_ASSERT_UNKNOWN( tape[arg[0]].new_var <= arg[0] );
				if( add )
					work.add_stack.push(arg[0]);
				else	work.sub_stack.push(arg[0]);
			}
			break;

			default:
			CPPAD_ASSERT_UNKNOWN(false);
		}
		// process second argument to this operator
		switch(op)
		{	// cases where second argument is a parameter
			case SubvpOp:
			CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < npar );
			// second argument has opposite sign of parent node
			if( add )
				sum_par -= par[arg[1]];
			else	sum_par += par[arg[1]];
			break;

			// cases where second argument is a variable and has opposite sign
			case SubvvOp:
			case SubpvOp:
			add = ! add;

			// cases where second argument is a variable and has same sign
			case AddvvOp:
			case AddpvOp:
			// check if the second argument is csum_connected
# ifndef NDEBUG
			{	bool flag1 = op_info[var2op[arg[1]]].csum_connected;
				bool flag2 = op_info[ var2op[ arg[1] ] ].csum_connected;
				CPPAD_ASSERT_UNKNOWN( flag1 == flag2 );
			}
# endif
			if( op_info[var2op[arg[1]]].csum_connected )
			{	CPPAD_ASSERT_UNKNOWN(
					size_t(tape[arg[1]].new_var) == tape.size()
				);
				// push the operator corresoponding to the second arugment
				var.op   = op_info[ var2op[arg[1]] ].op;
				var.arg  = op_info[ var2op[arg[1]] ].arg;
				var.add  = add;
				work.op_stack.push( var );
			}
			else
			{	// there are no nodes below this one
				CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < current );
				CPPAD_ASSERT_UNKNOWN( tape[arg[1]].new_var <=  arg[1] );
				if( add )
					work.add_stack.push(arg[1]);
				else	work.sub_stack.push(arg[1]);
			}
			break;

			default:
			CPPAD_ASSERT_UNKNOWN(false);
		}
	}
	// number of variables to add in this cummulative sum operator
	size_t n_add = work.add_stack.size();
	// number of variables to subtract in this cummulative sum operator
	size_t n_sub = work.sub_stack.size();
	//
	rec->PutArg(n_add);                // arg[0]
	rec->PutArg(n_sub);                // arg[1]
	size_t new_arg = rec->PutPar(sum_par);
	rec->PutArg(new_arg);              // arg[2]
	// addition arguments
	for(i = 0; i < n_add; i++)
	{	CPPAD_ASSERT_UNKNOWN( ! work.add_stack.empty() );
		size_t old_arg = work.add_stack.top();
		new_arg        = tape[old_arg].new_var;
		CPPAD_ASSERT_UNKNOWN( new_arg < current );
		rec->PutArg(new_arg);         // arg[3+i]
		work.add_stack.pop();
	}
	// subtraction arguments
	for(i = 0; i < n_sub; i++)
	{	CPPAD_ASSERT_UNKNOWN( ! work.sub_stack.empty() );
		size_t old_arg = work.sub_stack.top();
		new_arg        = tape[old_arg].new_var;
		CPPAD_ASSERT_UNKNOWN( new_arg < current );
		rec->PutArg(new_arg);      // arg[3 + arg[0] + i]
		work.sub_stack.pop();
	}
	// number of additions plus number of subtractions
	rec->PutArg(n_add + n_sub);        // arg[3 + arg[0] + arg[1]]
	//
	// return value
	struct_size_pair ret;
	ret.i_op  = rec->num_op_rec();
	ret.i_var = rec->PutOp(CSumOp);
	//
	return ret;
}

} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE

# endif
<|endoftext|>


<commit_before>/*
 * Copyright 2015 - 2018 gtalent2@gmail.com
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#if defined(OX_USE_STDLIB)
#include <bitset>
#include <iostream>
#endif

#include "defines.hpp"
#include "stacktrace.hpp"
#include "trace.hpp"

#include "assert.hpp"

namespace ox {

template<>
void assertFunc<bool>([[maybe_unused]]const char *file, [[maybe_unused]]int line, [[maybe_unused]]bool pass, [[maybe_unused]]const char *msg) {
#if defined(OX_USE_STDLIB)
	if (!pass) {
		std::cerr << "\033[31;1;1mASSERT FAILURE:\033[0m (" << file << ':' << line << "): " << msg << std::endl;
		printStackTrace(2);
		oxTrace("assert").del("") << "Failed assert: " << msg << " (" << file << ":" << line << ")";
		std::abort();
	}
#endif
}

template<>
void assertFunc<Error>(const char *file, int line, Error err, const char *assertMsg) {
	if (err) {
		std::cerr << "\033[31;1;1mASSERT FAILURE:\033[0m (" << file << ':' << line << "): " << assertMsg << '\n';
		if (err.msg) {
			std::cerr <<  "\tError Message:\t" << err.msg << '\n';
		}
		std::cerr <<  "\tError Code:\t" << err << '\n';
		if (err.file != nullptr) {
			std::cerr << "\tError Location:\t" << reinterpret_cast<const char*>(err.file) << ':' << err.line << '\n';
		}
		printStackTrace(2);
		oxTrace("panic").del("") << "Panic: " << assertMsg << " (" << file << ":" << line << ")";
		std::abort();
	}
}

#if defined(OX_USE_STDLIB)
void panic(const char *file, int line, const char *panicMsg, Error err) {
	std::cerr << "\033[31;1;1mPANIC:\033[0m (" << file << ':' << line << "): " << panicMsg << '\n';
	if (err.msg) {
		std::cerr <<  "\tError Message:\t" << err.msg << '\n';
	}
	std::cerr <<  "\tError Code:\t" << err << '\n';
	if (err.file != nullptr) {
		std::cerr << "\tError Location:\t" << reinterpret_cast<const char*>(err.file) << ':' << err.line << '\n';
	}
	printStackTrace(2);
	oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << file << ":" << line << ")";
	std::abort();
}
#endif

}
<commit_msg>[ox/std] Fix assert for !OX_USE_STDLIB<commit_after>/*
 * Copyright 2015 - 2018 gtalent2@gmail.com
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#if defined(OX_USE_STDLIB)
#include <bitset>
#include <iostream>
#endif

#include "defines.hpp"
#include "stacktrace.hpp"
#include "trace.hpp"

#include "assert.hpp"

namespace ox {

template<>
void assertFunc<bool>([[maybe_unused]]const char *file, [[maybe_unused]]int line, [[maybe_unused]]bool pass, [[maybe_unused]]const char *msg) {
#if defined(OX_USE_STDLIB)
	if (!pass) {
		std::cerr << "\033[31;1;1mASSERT FAILURE:\033[0m (" << file << ':' << line << "): " << msg << std::endl;
		printStackTrace(2);
		oxTrace("assert").del("") << "Failed assert: " << msg << " (" << file << ":" << line << ")";
		std::abort();
	}
#endif
}

template<>
void assertFunc<Error>(const char *file, int line, Error err, const char *assertMsg) {
	if (err) {
#if defined(OX_USE_STDLIB)
		std::cerr << "\033[31;1;1mASSERT FAILURE:\033[0m (" << file << ':' << line << "): " << assertMsg << '\n';
		if (err.msg) {
			std::cerr <<  "\tError Message:\t" << err.msg << '\n';
		}
		std::cerr <<  "\tError Code:\t" << err << '\n';
		if (err.file != nullptr) {
			std::cerr << "\tError Location:\t" << reinterpret_cast<const char*>(err.file) << ':' << err.line << '\n';
		}
		printStackTrace(2);
		oxTrace("panic").del("") << "Panic: " << assertMsg << " (" << file << ":" << line << ")";
		std::abort();
#else
		panic(file, line, assertMsg);
#endif
	}
}

#if defined(OX_USE_STDLIB)
void panic(const char *file, int line, const char *panicMsg, Error err) {
	std::cerr << "\033[31;1;1mPANIC:\033[0m (" << file << ':' << line << "): " << panicMsg << '\n';
	if (err.msg) {
		std::cerr <<  "\tError Message:\t" << err.msg << '\n';
	}
	std::cerr <<  "\tError Code:\t" << err << '\n';
	if (err.file != nullptr) {
		std::cerr << "\tError Location:\t" << reinterpret_cast<const char*>(err.file) << ':' << err.line << '\n';
	}
	printStackTrace(2);
	oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << file << ":" << line << ")";
	std::abort();
}
#endif

}
<|endoftext|>


<commit_before>// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include <stdio.h>

#include <hwy/tests/test_util-inl.h>

#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/color_management.h"
#include "lib/jxl/dec_xyb.h"
#include "lib/jxl/enc_color_management.h"
#include "lib/jxl/enc_xyb.h"
#include "lib/jxl/image.h"
#include "lib/jxl/linalg.h"
#include "lib/jxl/opsin_params.h"

namespace jxl {
namespace {

class OpsinImageTargetTest : public hwy::TestWithParamTarget {};
HWY_TARGET_INSTANTIATE_TEST_SUITE_P(OpsinImageTargetTest);

// Convert a single linear sRGB color to xyb, using the exact image conversion
// procedure that jpeg xl uses.
void LinearSrgbToOpsin(float rgb_r, float rgb_g, float rgb_b,
                       float* JXL_RESTRICT xyb_x, float* JXL_RESTRICT xyb_y,
                       float* JXL_RESTRICT xyb_b) {
  Image3F linear(1, 1);
  linear.PlaneRow(0, 0)[0] = rgb_r;
  linear.PlaneRow(1, 0)[0] = rgb_g;
  linear.PlaneRow(2, 0)[0] = rgb_b;

  ImageMetadata metadata;
  metadata.SetFloat32Samples();
  metadata.color_encoding = ColorEncoding::LinearSRGB();
  ImageBundle ib(&metadata);
  ib.SetFromImage(std::move(linear), metadata.color_encoding);
  Image3F opsin(1, 1);
  (void)ToXYB(ib, /*pool=*/nullptr, &opsin, GetJxlCms());

  *xyb_x = opsin.PlaneRow(0, 0)[0];
  *xyb_y = opsin.PlaneRow(1, 0)[0];
  *xyb_b = opsin.PlaneRow(2, 0)[0];
}

// Convert a single XYB color to linear sRGB, using the exact image conversion
// procedure that jpeg xl uses.
void OpsinToLinearSrgb(float xyb_x, float xyb_y, float xyb_b,
                       float* JXL_RESTRICT rgb_r, float* JXL_RESTRICT rgb_g,
                       float* JXL_RESTRICT rgb_b) {
  Image3F opsin(1, 1);
  opsin.PlaneRow(0, 0)[0] = xyb_x;
  opsin.PlaneRow(1, 0)[0] = xyb_y;
  opsin.PlaneRow(2, 0)[0] = xyb_b;
  Image3F linear(1, 1);
  OpsinParams opsin_params;
  opsin_params.Init(/*intensity_target=*/255.0f);
  OpsinToLinear(opsin, Rect(opsin), nullptr, &linear, opsin_params);
  *rgb_r = linear.PlaneRow(0, 0)[0];
  *rgb_g = linear.PlaneRow(1, 0)[0];
  *rgb_b = linear.PlaneRow(2, 0)[0];
}

void OpsinRoundtripTestRGB(float r, float g, float b) {
  float xyb_x, xyb_y, xyb_b;
  LinearSrgbToOpsin(r, g, b, &xyb_x, &xyb_y, &xyb_b);
  float r2, g2, b2;
  OpsinToLinearSrgb(xyb_x, xyb_y, xyb_b, &r2, &g2, &b2);
  EXPECT_NEAR(r, r2, 1e-3);
  EXPECT_NEAR(g, g2, 1e-3);
  EXPECT_NEAR(b, b2, 1e-3);
}

TEST(OpsinImageTest, VerifyOpsinAbsorbanceInverseMatrix) {
  float matrix[9];  // writable copy
  for (int i = 0; i < 9; i++) {
    matrix[i] = GetOpsinAbsorbanceInverseMatrix()[i];
  }
  EXPECT_TRUE(Inv3x3Matrix(matrix));
  for (int i = 0; i < 9; i++) {
    EXPECT_NEAR(matrix[i], kOpsinAbsorbanceMatrix[i], 1e-6);
  }
}

TEST(OpsinImageTest, OpsinRoundtrip) {
  OpsinRoundtripTestRGB(0, 0, 0);
  OpsinRoundtripTestRGB(1. / 255, 1. / 255, 1. / 255);
  OpsinRoundtripTestRGB(128. / 255, 128. / 255, 128. / 255);
  OpsinRoundtripTestRGB(1, 1, 1);

  OpsinRoundtripTestRGB(0, 0, 1. / 255);
  OpsinRoundtripTestRGB(0, 0, 128. / 255);
  OpsinRoundtripTestRGB(0, 0, 1);

  OpsinRoundtripTestRGB(0, 1. / 255, 0);
  OpsinRoundtripTestRGB(0, 128. / 255, 0);
  OpsinRoundtripTestRGB(0, 1, 0);

  OpsinRoundtripTestRGB(1. / 255, 0, 0);
  OpsinRoundtripTestRGB(128. / 255, 0, 0);
  OpsinRoundtripTestRGB(1, 0, 0);
}

TEST(OpsinImageTest, VerifyZero) {
  // Test that black color (zero energy) is 0,0,0 in xyb.
  float x, y, b;
  LinearSrgbToOpsin(0, 0, 0, &x, &y, &b);
  EXPECT_NEAR(0, x, 1e-9);
  EXPECT_NEAR(0, y, 1e-7);
  EXPECT_NEAR(0, b, 1e-7);
}

TEST(OpsinImageTest, VerifyGray) {
  // Test that grayscale colors have a fixed y/b ratio and x==0.
  for (size_t i = 1; i < 255; i++) {
    float x, y, b;
    LinearSrgbToOpsin(i / 255., i / 255., i / 255., &x, &y, &b);
    EXPECT_NEAR(0, x, 1e-6);
    EXPECT_NEAR(kYToBRatio, b / y, 3e-5);
  }
}

}  // namespace
}  // namespace jxl
<commit_msg>removing empty test (#1509)<commit_after>// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include <stdio.h>

#include <hwy/tests/test_util-inl.h>

#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/color_management.h"
#include "lib/jxl/dec_xyb.h"
#include "lib/jxl/enc_color_management.h"
#include "lib/jxl/enc_xyb.h"
#include "lib/jxl/image.h"
#include "lib/jxl/linalg.h"
#include "lib/jxl/opsin_params.h"

namespace jxl {
namespace {

// Convert a single linear sRGB color to xyb, using the exact image conversion
// procedure that jpeg xl uses.
void LinearSrgbToOpsin(float rgb_r, float rgb_g, float rgb_b,
                       float* JXL_RESTRICT xyb_x, float* JXL_RESTRICT xyb_y,
                       float* JXL_RESTRICT xyb_b) {
  Image3F linear(1, 1);
  linear.PlaneRow(0, 0)[0] = rgb_r;
  linear.PlaneRow(1, 0)[0] = rgb_g;
  linear.PlaneRow(2, 0)[0] = rgb_b;

  ImageMetadata metadata;
  metadata.SetFloat32Samples();
  metadata.color_encoding = ColorEncoding::LinearSRGB();
  ImageBundle ib(&metadata);
  ib.SetFromImage(std::move(linear), metadata.color_encoding);
  Image3F opsin(1, 1);
  (void)ToXYB(ib, /*pool=*/nullptr, &opsin, GetJxlCms());

  *xyb_x = opsin.PlaneRow(0, 0)[0];
  *xyb_y = opsin.PlaneRow(1, 0)[0];
  *xyb_b = opsin.PlaneRow(2, 0)[0];
}

// Convert a single XYB color to linear sRGB, using the exact image conversion
// procedure that jpeg xl uses.
void OpsinToLinearSrgb(float xyb_x, float xyb_y, float xyb_b,
                       float* JXL_RESTRICT rgb_r, float* JXL_RESTRICT rgb_g,
                       float* JXL_RESTRICT rgb_b) {
  Image3F opsin(1, 1);
  opsin.PlaneRow(0, 0)[0] = xyb_x;
  opsin.PlaneRow(1, 0)[0] = xyb_y;
  opsin.PlaneRow(2, 0)[0] = xyb_b;
  Image3F linear(1, 1);
  OpsinParams opsin_params;
  opsin_params.Init(/*intensity_target=*/255.0f);
  OpsinToLinear(opsin, Rect(opsin), nullptr, &linear, opsin_params);
  *rgb_r = linear.PlaneRow(0, 0)[0];
  *rgb_g = linear.PlaneRow(1, 0)[0];
  *rgb_b = linear.PlaneRow(2, 0)[0];
}

void OpsinRoundtripTestRGB(float r, float g, float b) {
  float xyb_x, xyb_y, xyb_b;
  LinearSrgbToOpsin(r, g, b, &xyb_x, &xyb_y, &xyb_b);
  float r2, g2, b2;
  OpsinToLinearSrgb(xyb_x, xyb_y, xyb_b, &r2, &g2, &b2);
  EXPECT_NEAR(r, r2, 1e-3);
  EXPECT_NEAR(g, g2, 1e-3);
  EXPECT_NEAR(b, b2, 1e-3);
}

TEST(OpsinImageTest, VerifyOpsinAbsorbanceInverseMatrix) {
  float matrix[9];  // writable copy
  for (int i = 0; i < 9; i++) {
    matrix[i] = GetOpsinAbsorbanceInverseMatrix()[i];
  }
  EXPECT_TRUE(Inv3x3Matrix(matrix));
  for (int i = 0; i < 9; i++) {
    EXPECT_NEAR(matrix[i], kOpsinAbsorbanceMatrix[i], 1e-6);
  }
}

TEST(OpsinImageTest, OpsinRoundtrip) {
  OpsinRoundtripTestRGB(0, 0, 0);
  OpsinRoundtripTestRGB(1. / 255, 1. / 255, 1. / 255);
  OpsinRoundtripTestRGB(128. / 255, 128. / 255, 128. / 255);
  OpsinRoundtripTestRGB(1, 1, 1);

  OpsinRoundtripTestRGB(0, 0, 1. / 255);
  OpsinRoundtripTestRGB(0, 0, 128. / 255);
  OpsinRoundtripTestRGB(0, 0, 1);

  OpsinRoundtripTestRGB(0, 1. / 255, 0);
  OpsinRoundtripTestRGB(0, 128. / 255, 0);
  OpsinRoundtripTestRGB(0, 1, 0);

  OpsinRoundtripTestRGB(1. / 255, 0, 0);
  OpsinRoundtripTestRGB(128. / 255, 0, 0);
  OpsinRoundtripTestRGB(1, 0, 0);
}

TEST(OpsinImageTest, VerifyZero) {
  // Test that black color (zero energy) is 0,0,0 in xyb.
  float x, y, b;
  LinearSrgbToOpsin(0, 0, 0, &x, &y, &b);
  EXPECT_NEAR(0, x, 1e-9);
  EXPECT_NEAR(0, y, 1e-7);
  EXPECT_NEAR(0, b, 1e-7);
}

TEST(OpsinImageTest, VerifyGray) {
  // Test that grayscale colors have a fixed y/b ratio and x==0.
  for (size_t i = 1; i < 255; i++) {
    float x, y, b;
    LinearSrgbToOpsin(i / 255., i / 255., i / 255., &x, &y, &b);
    EXPECT_NEAR(0, x, 1e-6);
    EXPECT_NEAR(kYToBRatio, b / y, 3e-5);
  }
}

}  // namespace
}  // namespace jxl
<|endoftext|>


<commit_before>/*
 * This badge clock was coded by none other than Simon Smith and Cameron Kachur.
 * It does clock things such as tell time and.........................
 * You wish you could make a clock badgerooni like this.
 * Happy clocking and turn down for only dead batteries.
 * Boilermake 2014 - All clock no sleep
 */

#define MAX_TERMINAL_LINE_LEN 40
#define MAX_TERMINAL_WORDS     7

// 14 is strlen("send FFFF -m ")
// the max message length able to be sent from the terminal is
// total terminal line length MINUS the rest of the message
#define MAX_TERMINAL_MESSAGE_LEN  MAX_TERMINAL_LINE_LEN - 14

#include <RF24.h>
#include <SPI.h>
#include <EEPROM.h>

void networkRead(void);

void setLEDS(word);
void handlePayload(struct payload *);

void displayDemo();

// Maps commands to integers
const byte PING   = 0; // Ping
const byte LED    = 1; // LED pattern
const byte MESS   = 2; // Message
const byte DEMO   = 3; // Demo Pattern

// Global Variables
int SROEPin = 3; // using digital pin 3 for SR !OE
int SRLatchPin = 8; // using digital pin 4 for SR latch
boolean terminalConnect = false; // indicates if the terminal has connected to the board yet

// nRF24L01 radio static initializations
RF24 radio(9,10); // Setup nRF24L01 on SPI bus using pins 9 & 10 as CE & CSN, respectively

uint16_t this_node_address = (EEPROM.read(0) << 8) | EEPROM.read(1); // Radio address for this node
unsigned long startTime = 0;

struct payload{ // Payload structure
  byte command;
  byte led_pattern;
  char message[30];
};

// This runs once on boot
void setup() {
  Serial.begin(9600);

  // SPI initializations
  SPI.begin();
  SPI.setBitOrder(MSBFIRST); // nRF requires MSB first
  SPI.setClockDivider(16); // Set SPI clock to 16 MHz / 16 = 1 MHz

  // nRF radio initializations
  radio.begin();
  radio.setDataRate(RF24_1MBPS); // 1Mbps transfer rate
  radio.setCRCLength(RF24_CRC_16); // 16-bit CRC
  radio.setChannel(80); // Channel center frequency = 2.4005 GHz + (Channel# * 1 MHz)
  radio.setRetries(200, 5); // set the delay and number of retries upon failed transmit
  radio.openReadingPipe(0, this_node_address); // Open this address
  radio.startListening(); // Start listening on opened address

  // Shift register pin initializations
  pinMode(SROEPin, OUTPUT);
  pinMode(SRLatchPin, OUTPUT);
  digitalWrite(SROEPin, HIGH);
  digitalWrite(SRLatchPin, LOW);

  // make the pretty LEDs happen
  displayDemo();

  startTime = millis();
  //
  digitalWrite(SROEPin, LOW);
}

// This loops forever
void loop() {
  if (Serial && !terminalConnect) {
    terminalConnect = true;
    sync_time_serial();
  } else if (!Serial && terminalConnect) {
    terminalConnect = false;
  }

  displayTime();
}

void displayTime() {
  unsigned long time = millis() - startTime;
  int hour = (time / 3600000) % 12;
  int minute = (time / 60000) % 60;
  int second = (time / 1000) % 60;

  if (second % 2) {
    setLEDS(ledNum(toLED16(hour)) | ledNum(toLED16(minute / 5)));
  } else {
    setLEDS(ledNum(toLED16(hour)));
  }
  delay(1000);
  if (minute % 5 == 0 && second < 1) {
    for (int i = 0; i < 16; i++) {
      setLEDS(ledNum(i));
      delay((int) 1000/16);
    }
  }

  Serial.print(millis());
  Serial.print(" : ");
  Serial.print(time);
  Serial.print(" : ");
  Serial.print(hour);
  Serial.print(" : ");
  Serial.println(minute);
}

//12 hour clock, but 16 LEDs
int toLED16(int i) {
  int ret = i;

  //We have to not use 4 of the 16 for a 12 clock
  if (ret >= 3) ret += 1;
  if (ret >= 5) ret += 1;
  if (ret >= 11) ret += 1;
  if (ret >= 13) ret += 1;
  ret += 9;
  return ret % 16;
}

void sync_time_serial() {

}

/*
// Display LED pattern

// LED numbering:

           9
       8       10
     7           11
   6               12
  5                 13
   4               14
     3           15
       2       16
           1

shift register 1-8: AA
shift register 9-16: BB

setLEDS data in hex: 0xAABB
where AA in binary = 0b[8][7][6][5][4][3][2][1]
      BB in binary = 0b[16][15][14][13][12][11][10][9]

*/
word ledNum(int i) {
  word shit[17];
  shit[0] = 0x0000;

  shit[1] = 0x0100;
  shit[2] = 0x0200;
  shit[3] = 0x0400;
  shit[4] = 0x0800;
  shit[5] = 0x1000;
  shit[6] = 0x2000;
  shit[7] = 0x4000;
  shit[8] = 0x8000;

  shit[9] =  0x0001;
  shit[10] = 0x0002;
  shit[11] = 0x0004;
  shit[12] = 0x0008;
  shit[13] = 0x0010;
  shit[14] = 0x0020;
  shit[15] = 0x0040;
  shit[16] = 0x0080;

  return shit[i];
}

// LED display demo
void displayDemo() {
  digitalWrite(SROEPin, LOW);
  for (int i = 0; i < 4; i++) {
    setLEDS(0xAAAA);
    delay(125);
    setLEDS(0x5555);
    delay(125);
  }
  digitalWrite(SROEPin, HIGH);
}

// Sends word sized value to both SRs & latches output pins
void setLEDS(word value) {
  byte Hvalue = value >> 8;
  byte Lvalue = value & 0x00FF;
  SPI.transfer(Lvalue);
  SPI.transfer(Hvalue);
  digitalWrite(SRLatchPin, HIGH);
  digitalWrite(SRLatchPin, LOW);
}
<commit_msg>hmm still tired<commit_after>/*
 * This badge clock was coded by none other than Simon Smith and Cameron Kachur.
 * It does clock things such as tell time and.........................
 * You wish you could make a clock badgerooni like this.
 * Happy clocking and turn down for only dead batteries.
 * Boilermake 2014 - All clock no sleep
 */

#define MAX_TERMINAL_LINE_LEN 40
#define MAX_TERMINAL_WORDS     7

// 14 is strlen("send FFFF -m ")
// the max message length able to be sent from the terminal is
// total terminal line length MINUS the rest of the message
#define MAX_TERMINAL_MESSAGE_LEN  MAX_TERMINAL_LINE_LEN - 14

#include <RF24.h>
#include <SPI.h>
#include <EEPROM.h>

void networkRead(void);

void setLEDS(word);
void handlePayload(struct payload *);

void displayDemo();

// Maps commands to integers
const byte PING   = 0; // Ping
const byte LED    = 1; // LED pattern
const byte MESS   = 2; // Message
const byte DEMO   = 3; // Demo Pattern

// Global Variables
int SROEPin = 3; // using digital pin 3 for SR !OE
int SRLatchPin = 8; // using digital pin 4 for SR latch
boolean terminalConnect = false; // indicates if the terminal has connected to the board yet

// nRF24L01 radio static initializations
RF24 radio(9,10); // Setup nRF24L01 on SPI bus using pins 9 & 10 as CE & CSN, respectively

uint16_t this_node_address = (EEPROM.read(0) << 8) | EEPROM.read(1); // Radio address for this node
unsigned long startTime = 0;

struct payload{ // Payload structure
  byte command;
  byte led_pattern;
  char message[30];
};

// This runs once on boot
void setup() {
  Serial.begin(9600);

  // SPI initializations
  SPI.begin();
  SPI.setBitOrder(MSBFIRST); // nRF requires MSB first
  SPI.setClockDivider(16); // Set SPI clock to 16 MHz / 16 = 1 MHz

  // nRF radio initializations
  radio.begin();
  radio.setDataRate(RF24_1MBPS); // 1Mbps transfer rate
  radio.setCRCLength(RF24_CRC_16); // 16-bit CRC
  radio.setChannel(80); // Channel center frequency = 2.4005 GHz + (Channel# * 1 MHz)
  radio.setRetries(200, 5); // set the delay and number of retries upon failed transmit
  radio.openReadingPipe(0, this_node_address); // Open this address
  radio.startListening(); // Start listening on opened address

  // Shift register pin initializations
  pinMode(SROEPin, OUTPUT);
  pinMode(SRLatchPin, OUTPUT);
  digitalWrite(SROEPin, HIGH);
  digitalWrite(SRLatchPin, LOW);

  // make the pretty LEDs happen
  displayDemo();

  startTime = millis();
  //
  digitalWrite(SROEPin, LOW);
}

// This loops forever
void loop() {
  if (Serial && !terminalConnect) {
    terminalConnect = true;
    sync_time_serial();
  } else if (!Serial && terminalConnect) {
    terminalConnect = false;
  }

  displayTime();
}

void displayTime() {
  unsigned long time = millis() - startTime;
  int hour = (time / 3600000) % 12;
  int minute = (time / 60000) % 60;
  int second = (time / 1000) % 60;

  if (second % 2) {
    setLEDS(ledNum(toLED16(hour)) | ledNum(toLED16(minute / 5)));
  } else {
    setLEDS(ledNum(toLED16(hour)));
  }
  delay(1000);
  if (minute % 5 == 0 && second == 0) {
    for (int i = 0; i < 16; i++) {
      setLEDS(ledNum((i + 9 + hour) % 16 + 1));
      delay((int) 1000/16);
    }
  }

  Serial.print(millis());
  Serial.print(" : ");
  Serial.print(time);
  Serial.print(" : ");
  Serial.print(hour);
  Serial.print(" : ");
  Serial.println(minute);
}

//12 hour clock, but 16 LEDs
int toLED16(int i) {
  int ret = i;

  //We have to not use 4 of the 16 for a 12 clock
  if (ret >= 3) ret += 1;
  if (ret >= 5) ret += 1;
  if (ret >= 11) ret += 1;
  if (ret >= 13) ret += 1;
  ret += 9;
  return ret % 16;
}

//Wait a bit and see if we get serial time sync
void sync_time_serial() {

}

/*
// Display LED pattern

// LED numbering:

           9
       8       10
     7           11
   6               12
  5                 13
   4               14
     3           15
       2       16
           1

shift register 1-8: AA
shift register 9-16: BB

setLEDS data in hex: 0xAABB
where AA in binary = 0b[8][7][6][5][4][3][2][1]
      BB in binary = 0b[16][15][14][13][12][11][10][9]

*/
word ledNum(int i) {
  word shit[17];
  shit[0] = 0x0000;

  shit[1] = 0x0100;
  shit[2] = 0x0200;
  shit[3] = 0x0400;
  shit[4] = 0x0800;
  shit[5] = 0x1000;
  shit[6] = 0x2000;
  shit[7] = 0x4000;
  shit[8] = 0x8000;

  shit[9] =  0x0001;
  shit[10] = 0x0002;
  shit[11] = 0x0004;
  shit[12] = 0x0008;
  shit[13] = 0x0010;
  shit[14] = 0x0020;
  shit[15] = 0x0040;
  shit[16] = 0x0080;

  return shit[i];
}

// LED display demo
void displayDemo() {
  digitalWrite(SROEPin, LOW);
  for (int i = 0; i < 4; i++) {
    setLEDS(0xAAAA);
    delay(125);
    setLEDS(0x5555);
    delay(125);
  }
  digitalWrite(SROEPin, HIGH);
}

// Sends word sized value to both SRs & latches output pins
void setLEDS(word value) {
  byte Hvalue = value >> 8;
  byte Lvalue = value & 0x00FF;
  SPI.transfer(Lvalue);
  SPI.transfer(Hvalue);
  digitalWrite(SRLatchPin, HIGH);
  digitalWrite(SRLatchPin, LOW);
}
<|endoftext|>


<commit_before>/*
Copyright libCellML Contributors

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 "gtest/gtest.h"

#include <algorithm>
#include <fstream>
#include <iostream>
#include <libcellml>
#include <sstream>
#include <vector>

// generated with test resource locations
#include "test_resources.h"

static int countImportedComponents(libcellml::ModelPtr model)
{
    return -1;
}

TEST(ResolveImports, parseSineModelFromFile) {
    std::ifstream t(TestResources::getLocation(
                    TestResources::CELLML_SINE_MODEL_RESOURCE));
    std::stringstream buffer;
    buffer << t.rdbuf();

    libcellml::Parser p(libcellml::Format::XML);
    libcellml::ModelPtr model = p.parseModel(buffer.str());

    EXPECT_EQ(0, p.errorCount());

    EXPECT_EQ(0, countImportedComponents(model));
}

TEST(ResolveImports, parseSineImportsModelFromFile) {
    std::ifstream t(TestResources::getLocation(
                    TestResources::CELLML_SINE_IMPORTS_MODEL_RESOURCE));
    std::stringstream buffer;
    buffer << t.rdbuf();

    libcellml::Parser p(libcellml::Format::XML);
    libcellml::ModelPtr model = p.parseModel(buffer.str());
    EXPECT_EQ(0, p.errorCount());

    EXPECT_EQ(3, countImportedComponents(model));
}
<commit_msg>Hierarchically counting imported components.<commit_after>/*
Copyright libCellML Contributors

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 "gtest/gtest.h"

#include <algorithm>
#include <fstream>
#include <iostream>
#include <libcellml>
#include <sstream>
#include <vector>

// generated with test resource locations
#include "test_resources.h"

static size_t countImportedChildren(libcellml::ComponentPtr parent)
{
    size_t numberImportedChildren = 0;
    for (size_t n = 0; n < parent->componentCount();  ++n)
    {
        libcellml::ComponentPtr c = parent->getComponent(n);
        if (c->isImport()) ++numberImportedChildren;
        numberImportedChildren += countImportedChildren(c);
    }
    return numberImportedChildren;
}

TEST(ResolveImports, parseSineModelFromFile) {
    std::ifstream t(TestResources::getLocation(
                    TestResources::CELLML_SINE_MODEL_RESOURCE));
    std::stringstream buffer;
    buffer << t.rdbuf();

    libcellml::Parser p(libcellml::Format::XML);
    libcellml::ModelPtr model = p.parseModel(buffer.str());

    EXPECT_EQ(0, p.errorCount());

    size_t nImportedComponents = 0;
    for (size_t n = 0; n < model->componentCount();  ++n)
    {
        libcellml::ComponentPtr c = model->getComponent(n);
        if (c->isImport()) ++nImportedComponents;
        nImportedComponents += countImportedChildren(c);
    }
    EXPECT_EQ(0, nImportedComponents);
}

TEST(ResolveImports, parseSineImportsModelFromFile) {
    std::ifstream t(TestResources::getLocation(
                    TestResources::CELLML_SINE_IMPORTS_MODEL_RESOURCE));
    std::stringstream buffer;
    buffer << t.rdbuf();

    libcellml::Parser p(libcellml::Format::XML);
    libcellml::ModelPtr model = p.parseModel(buffer.str());
    EXPECT_EQ(0, p.errorCount());

    size_t nImportedComponents = 0;
    for (size_t n = 0; n < model->componentCount();  ++n)
    {
        libcellml::ComponentPtr c = model->getComponent(n);
        if (c->isImport()) ++nImportedComponents;
        nImportedComponents += countImportedChildren(c);
    }
    EXPECT_EQ(3, nImportedComponents);
}
<|endoftext|>