<commit_before>#include "common/config.h"
#include "common/file_stream.h"
#include "common/logging.h"
#include "common/utils.h"
#include "common/version.h"
#include "common/regex.h"

#include <algorithm>
#include <set>
#include <string>

namespace marian {

// @TODO: keep seed in a single place, now it is kept here and in Config/Options
size_t Config::seed = (size_t)time(0);

Config::Config(int argc,
               char** argv,
               cli::mode mode /*= cli::mode::training*/,
               bool validate /*= true*/) {
  initialize(argc, argv, mode, validate);
}

Config::Config(const Config& other) : config_(YAML::Clone(other.config_)) {}
Config::Config(const Options& options) : config_(YAML::Clone(options.getYaml())) {}

void Config::initialize(int argc, char** argv, cli::mode mode, bool validate) {
  auto parser = ConfigParser(argc, argv, mode, validate);
  config_ = parser.getConfig();

  createLoggers(this);

  // echo version and command line
  LOG(info, "[marian] Marian {}", buildVersion());
  std::string cmdLine;
  for (int i = 0; i < argc; i++) {
    std::string arg = argv[i];
    std::string quote; // attempt to quote special chars
    if (arg.empty() || arg.find_first_of(" #`\"'\\${}|&^?*!()%><") != std::string::npos)
      quote = "'";
    arg = regex::regex_replace(arg, std::regex("'"), "'\\''");
    if (!cmdLine.empty())
      cmdLine.push_back(' ');
    cmdLine += quote + arg + quote;
  }
  std::string hostname; int pid; std::tie
  (hostname, pid) = utils::hostnameAndProcessId();
  LOG(info, "[marian] Running on {} as process {} with command line:", hostname, pid);
  LOG(info, "[marian] {}", cmdLine);

  // set random seed
  if(get<size_t>("seed") == 0) {
    seed = (size_t)time(0);
  } else {
    seed = get<size_t>("seed");
  }

  // load model parameters
  if(mode != cli::mode::translation) {
    auto model = get<std::string>("model");
    if(filesystem::exists(model) && !get<bool>("no-reload")) {
      try {
        if(!get<bool>("ignore-model-config"))
          loadModelParameters(model);
      } catch(std::runtime_error&) {
        LOG(info, "[config] No model configuration found in model file");
      }
    }
  }
  // if cli::mode::translation
  else {
    auto model = get<std::vector<std::string>>("models")[0];
    try {
      if(!get<bool>("ignore-model-config"))
        loadModelParameters(model);
    } catch(std::runtime_error& ) {
      LOG(info, "[config] No model configuration found in model file");
    }
  }

  // echo full configuration
  log();

  // Log version of Marian that has been used to create the model.
  //
  // Key "version" is present only if loaded from model parameters and is not
  // related to --version flag
  if(has("version")) {
    auto version = get<std::string>("version");

    if(mode == cli::mode::training && version != buildVersion())
      LOG(info,
          "[config] Loaded model has been created with Marian {}, "
          "will be overwritten with current version {} at saving",
          version,
          buildVersion());
    else
      LOG(info,
          "[config] Loaded model has been created with Marian {}",
          version);
  }
  // If this is a newly started training
  else if(mode == cli::mode::training) {
    LOG(info,
        "[config] Model is being created with Marian {}",
        buildVersion());
  }
}

bool Config::has(const std::string& key) const {
  return config_[key];
}

YAML::Node Config::operator[](const std::string& key) const {
  return get(key);
}

YAML::Node Config::get(const std::string& key) const {
  return config_[key];
}

const YAML::Node& Config::get() const {
  return config_;
}

YAML::Node& Config::get() {
  return config_;
}

void Config::save(const std::string& name) {
  io::OutputFileStream out(name);
  out << *this;
}

void Config::loadModelParameters(const std::string& name) {
  YAML::Node config;
  io::getYamlFromModel(config, "special:model.yml", name);
  override(config);
}

void Config::loadModelParameters(const void* ptr) {
  YAML::Node config;
  io::getYamlFromModel(config, "special:model.yml", ptr);
  override(config);
}

void Config::override(const YAML::Node& params) {
  for(auto& it : params) {
    config_[it.first.as<std::string>()] = it.second;
  }
}

void Config::log() {
  YAML::Emitter out;
  cli::OutputYaml(config_, out);
  std::string configString = out.c_str();

  // print YAML prepending each line with [config]
  std::vector<std::string> results;
  utils::split(configString, results, "\n");
  for(auto& r : results)
    LOG(info, "[config] {}", r);
}

// Parse the device-spec parameters (--num-devices, --devices, --cpu-threads) into an array of
// size_t For multi-node, this returns the devices vector for the given rank, where "devices" really
// refers to how many graph instances are used (for CPU, that is the number of threads).
//
// For CPU, specify --cpu-threads.
//
// For GPU, specify either --num-devices or --devices.
//
// For single-MPI-process GPU, if both are given, --num-devices must be equal to size of --devices.
//
// For multi-MPI-process GPU, if --devices is equal to --num-devices, then the device set is shared
// across all nodes. Alternatively, it can contain a multiple of --num-devices entries. In that
// case, devices lists the set of MPI-process-local GPUs for all MPI processes, concatenated. This
// last form must be used when running a multi-MPI-process MPI job on a single machine with multiple
// GPUs.
//
// Examples:
//  - CPU:
//    --cpu-threads 8
//  - single MPI process, single GPU:
//    [no option given]  // will use device 0
//    --num-devices 1    // same
//    --devices 2        // will use device 2
//  - single MPI process, multiple GPU:
//    --num-devices 4    // will use devices 0, 1, 2, and 3
//    --devices 0 1 2 3  // same
//    --devices 4 5 6 7  // will use devices 4, 5, 6, and 7
//  - multiple MPI processes, multiple GPU:
//    --num-devices 4   // will use devices 0, 1, 2, and 3 in all MPI process, respectively
//    --devices 4 5 6 7 // will use devices 4, 5, 6, and 7 in all MPI process, respectively
//    --num-devices 1 --devices 0 1 2 3 4 5 6 7 // this is a 8-process job on a single machine;
//                                              // MPI processes 0..7 use devices 0..7, respectively
//    --num-devices 4 --devices 0 1 2 3 4 5 6 7 // this is a 2-process job on a single machine;
//                                              // MPI process 0 uses 0..3, and MPI process 1 uses 4..7
std::vector<DeviceId> Config::getDevices(Ptr<Options> options,
                                         size_t myMPIRank /*= 0*/,
                                         size_t numMPIProcesses /*= 1*/) {
  std::vector<DeviceId> devices;
  auto devicesArg = options->get<std::vector<std::string>>("devices");

  // CPU: devices[] just enumerate the threads (note: --devices refers to GPUs, and is thus ignored)
  if(options->get<size_t>("cpu-threads") > 0) {
    for(size_t i = 0; i < options->get<size_t>("cpu-threads"); ++i)
      devices.push_back({i, DeviceType::cpu});
  }
  // GPU: devices[] are interpreted in a more complex way
  else {
    size_t numDevices = options->get<size_t>("num-devices", 0);
    std::vector<size_t> deviceNos;
    for(auto d : devicesArg)
      deviceNos.push_back((size_t)std::stoull(d));

    // if devices[] is empty then default to 0..N-1, where N = numDevices or 1
    if (deviceNos.empty()) {
      if(numDevices == 0)  // if neither is given, then we default to 1 device, which is device[0]
        numDevices = 1;
      for(size_t i = 0; i < numDevices; ++i) // default to 0..N-1
        deviceNos.push_back(i);
    }
    // devices[] is not empty
    else if(numDevices == 0) // if device list then num devices defaults to list size
      numDevices = deviceNos.size(); // default to #devices

    // If multiple MPI processes then we can either have one set of devices shared across all
    // MPI-processes, or the full list across all MPI processes concatenated.  E.g. --num-devices 1
    // --devices 0 2 4 5 means 4 processes using devices 0, 2, 4, and 5, respectively.  In that
    // case, we cut out and return our own slice. In the above example, for MPI process 1, we would
    // return {2}.

    // special-case the error message (also caught indirectly below, but with a msg that is
    // confusing when one does not run multi-node)
    if(numMPIProcesses == 1)
      // same as requiring numPerMPIProcessDeviceNos == 1
      // @TODO: improve logging message as devices[] and numDevices are not informative for the user
      ABORT_IF(numDevices != deviceNos.size(), "devices[] size must be equal to numDevices");

    // how many lists concatenated in devices[]? Allowed is either 1 (=shared) or numWorkers
    size_t numPerMPIProcessDeviceNos = deviceNos.size() / numDevices;
    // @TODO: improve logging message as devices[] and numDevices are not informative for the user
    ABORT_IF(numDevices * numPerMPIProcessDeviceNos != deviceNos.size(),
             "devices[] size must be equal to or a multiple of numDevices");  // (check that it is a
                                                                              // multiple)

    // if multiple concatenated lists are given, slice out the one for myMPIRank
    if(numPerMPIProcessDeviceNos != 1) {
      ABORT_IF(numPerMPIProcessDeviceNos != numMPIProcesses,
               "devices[] must either list a shared set of devices, or one set per MPI process");
      deviceNos.erase(deviceNos.begin(), deviceNos.begin() + myMPIRank * numDevices);
      deviceNos.resize(numDevices);
    }
    // form the final vector
    for(auto d : deviceNos)
      devices.push_back({ d, DeviceType::gpu });
  }
#ifdef MPI_FOUND
  for(auto d : devices)
    LOG(info, "[MPI rank {} out of {}]: {}[{}]",
        myMPIRank, numMPIProcesses, d.type == DeviceType::cpu ? "CPU" : "GPU", d.no);
#endif
  return devices;
}

Ptr<Options> parseOptions(int argc,
                          char** argv,
                          cli::mode mode /*= cli::mode::training*/,
                          bool validate /*= true*/) {
  auto config = New<Config>(argc, argv, mode, validate);
  auto options = New<Options>();
  options->merge(config->get());
  return options;
}

}  // namespace marian
<commit_msg>fix missing namespace<commit_after>#include "common/config.h"
#include "common/file_stream.h"
#include "common/logging.h"
#include "common/utils.h"
#include "common/version.h"
#include "common/regex.h"

#include <algorithm>
#include <set>
#include <string>

namespace marian {

// @TODO: keep seed in a single place, now it is kept here and in Config/Options
size_t Config::seed = (size_t)time(0);

Config::Config(int argc,
               char** argv,
               cli::mode mode /*= cli::mode::training*/,
               bool validate /*= true*/) {
  initialize(argc, argv, mode, validate);
}

Config::Config(const Config& other) : config_(YAML::Clone(other.config_)) {}
Config::Config(const Options& options) : config_(YAML::Clone(options.getYaml())) {}

void Config::initialize(int argc, char** argv, cli::mode mode, bool validate) {
  auto parser = ConfigParser(argc, argv, mode, validate);
  config_ = parser.getConfig();

  createLoggers(this);

  // echo version and command line
  LOG(info, "[marian] Marian {}", buildVersion());
  std::string cmdLine;
  for (int i = 0; i < argc; i++) {
    std::string arg = argv[i];
    std::string quote; // attempt to quote special chars
    if (arg.empty() || arg.find_first_of(" #`\"'\\${}|&^?*!()%><") != std::string::npos)
      quote = "'";
    arg = regex::regex_replace(arg, regex::regex("'"), "'\\''");
    if (!cmdLine.empty())
      cmdLine.push_back(' ');
    cmdLine += quote + arg + quote;
  }
  std::string hostname; int pid; std::tie
  (hostname, pid) = utils::hostnameAndProcessId();
  LOG(info, "[marian] Running on {} as process {} with command line:", hostname, pid);
  LOG(info, "[marian] {}", cmdLine);

  // set random seed
  if(get<size_t>("seed") == 0) {
    seed = (size_t)time(0);
  } else {
    seed = get<size_t>("seed");
  }

  // load model parameters
  if(mode != cli::mode::translation) {
    auto model = get<std::string>("model");
    if(filesystem::exists(model) && !get<bool>("no-reload")) {
      try {
        if(!get<bool>("ignore-model-config"))
          loadModelParameters(model);
      } catch(std::runtime_error&) {
        LOG(info, "[config] No model configuration found in model file");
      }
    }
  }
  // if cli::mode::translation
  else {
    auto model = get<std::vector<std::string>>("models")[0];
    try {
      if(!get<bool>("ignore-model-config"))
        loadModelParameters(model);
    } catch(std::runtime_error& ) {
      LOG(info, "[config] No model configuration found in model file");
    }
  }

  // echo full configuration
  log();

  // Log version of Marian that has been used to create the model.
  //
  // Key "version" is present only if loaded from model parameters and is not
  // related to --version flag
  if(has("version")) {
    auto version = get<std::string>("version");

    if(mode == cli::mode::training && version != buildVersion())
      LOG(info,
          "[config] Loaded model has been created with Marian {}, "
          "will be overwritten with current version {} at saving",
          version,
          buildVersion());
    else
      LOG(info,
          "[config] Loaded model has been created with Marian {}",
          version);
  }
  // If this is a newly started training
  else if(mode == cli::mode::training) {
    LOG(info,
        "[config] Model is being created with Marian {}",
        buildVersion());
  }
}

bool Config::has(const std::string& key) const {
  return config_[key];
}

YAML::Node Config::operator[](const std::string& key) const {
  return get(key);
}

YAML::Node Config::get(const std::string& key) const {
  return config_[key];
}

const YAML::Node& Config::get() const {
  return config_;
}

YAML::Node& Config::get() {
  return config_;
}

void Config::save(const std::string& name) {
  io::OutputFileStream out(name);
  out << *this;
}

void Config::loadModelParameters(const std::string& name) {
  YAML::Node config;
  io::getYamlFromModel(config, "special:model.yml", name);
  override(config);
}

void Config::loadModelParameters(const void* ptr) {
  YAML::Node config;
  io::getYamlFromModel(config, "special:model.yml", ptr);
  override(config);
}

void Config::override(const YAML::Node& params) {
  for(auto& it : params) {
    config_[it.first.as<std::string>()] = it.second;
  }
}

void Config::log() {
  YAML::Emitter out;
  cli::OutputYaml(config_, out);
  std::string configString = out.c_str();

  // print YAML prepending each line with [config]
  std::vector<std::string> results;
  utils::split(configString, results, "\n");
  for(auto& r : results)
    LOG(info, "[config] {}", r);
}

// Parse the device-spec parameters (--num-devices, --devices, --cpu-threads) into an array of
// size_t For multi-node, this returns the devices vector for the given rank, where "devices" really
// refers to how many graph instances are used (for CPU, that is the number of threads).
//
// For CPU, specify --cpu-threads.
//
// For GPU, specify either --num-devices or --devices.
//
// For single-MPI-process GPU, if both are given, --num-devices must be equal to size of --devices.
//
// For multi-MPI-process GPU, if --devices is equal to --num-devices, then the device set is shared
// across all nodes. Alternatively, it can contain a multiple of --num-devices entries. In that
// case, devices lists the set of MPI-process-local GPUs for all MPI processes, concatenated. This
// last form must be used when running a multi-MPI-process MPI job on a single machine with multiple
// GPUs.
//
// Examples:
//  - CPU:
//    --cpu-threads 8
//  - single MPI process, single GPU:
//    [no option given]  // will use device 0
//    --num-devices 1    // same
//    --devices 2        // will use device 2
//  - single MPI process, multiple GPU:
//    --num-devices 4    // will use devices 0, 1, 2, and 3
//    --devices 0 1 2 3  // same
//    --devices 4 5 6 7  // will use devices 4, 5, 6, and 7
//  - multiple MPI processes, multiple GPU:
//    --num-devices 4   // will use devices 0, 1, 2, and 3 in all MPI process, respectively
//    --devices 4 5 6 7 // will use devices 4, 5, 6, and 7 in all MPI process, respectively
//    --num-devices 1 --devices 0 1 2 3 4 5 6 7 // this is a 8-process job on a single machine;
//                                              // MPI processes 0..7 use devices 0..7, respectively
//    --num-devices 4 --devices 0 1 2 3 4 5 6 7 // this is a 2-process job on a single machine;
//                                              // MPI process 0 uses 0..3, and MPI process 1 uses 4..7
std::vector<DeviceId> Config::getDevices(Ptr<Options> options,
                                         size_t myMPIRank /*= 0*/,
                                         size_t numMPIProcesses /*= 1*/) {
  std::vector<DeviceId> devices;
  auto devicesArg = options->get<std::vector<std::string>>("devices");

  // CPU: devices[] just enumerate the threads (note: --devices refers to GPUs, and is thus ignored)
  if(options->get<size_t>("cpu-threads") > 0) {
    for(size_t i = 0; i < options->get<size_t>("cpu-threads"); ++i)
      devices.push_back({i, DeviceType::cpu});
  }
  // GPU: devices[] are interpreted in a more complex way
  else {
    size_t numDevices = options->get<size_t>("num-devices", 0);
    std::vector<size_t> deviceNos;
    for(auto d : devicesArg)
      deviceNos.push_back((size_t)std::stoull(d));

    // if devices[] is empty then default to 0..N-1, where N = numDevices or 1
    if (deviceNos.empty()) {
      if(numDevices == 0)  // if neither is given, then we default to 1 device, which is device[0]
        numDevices = 1;
      for(size_t i = 0; i < numDevices; ++i) // default to 0..N-1
        deviceNos.push_back(i);
    }
    // devices[] is not empty
    else if(numDevices == 0) // if device list then num devices defaults to list size
      numDevices = deviceNos.size(); // default to #devices

    // If multiple MPI processes then we can either have one set of devices shared across all
    // MPI-processes, or the full list across all MPI processes concatenated.  E.g. --num-devices 1
    // --devices 0 2 4 5 means 4 processes using devices 0, 2, 4, and 5, respectively.  In that
    // case, we cut out and return our own slice. In the above example, for MPI process 1, we would
    // return {2}.

    // special-case the error message (also caught indirectly below, but with a msg that is
    // confusing when one does not run multi-node)
    if(numMPIProcesses == 1)
      // same as requiring numPerMPIProcessDeviceNos == 1
      // @TODO: improve logging message as devices[] and numDevices are not informative for the user
      ABORT_IF(numDevices != deviceNos.size(), "devices[] size must be equal to numDevices");

    // how many lists concatenated in devices[]? Allowed is either 1 (=shared) or numWorkers
    size_t numPerMPIProcessDeviceNos = deviceNos.size() / numDevices;
    // @TODO: improve logging message as devices[] and numDevices are not informative for the user
    ABORT_IF(numDevices * numPerMPIProcessDeviceNos != deviceNos.size(),
             "devices[] size must be equal to or a multiple of numDevices");  // (check that it is a
                                                                              // multiple)

    // if multiple concatenated lists are given, slice out the one for myMPIRank
    if(numPerMPIProcessDeviceNos != 1) {
      ABORT_IF(numPerMPIProcessDeviceNos != numMPIProcesses,
               "devices[] must either list a shared set of devices, or one set per MPI process");
      deviceNos.erase(deviceNos.begin(), deviceNos.begin() + myMPIRank * numDevices);
      deviceNos.resize(numDevices);
    }
    // form the final vector
    for(auto d : deviceNos)
      devices.push_back({ d, DeviceType::gpu });
  }
#ifdef MPI_FOUND
  for(auto d : devices)
    LOG(info, "[MPI rank {} out of {}]: {}[{}]",
        myMPIRank, numMPIProcesses, d.type == DeviceType::cpu ? "CPU" : "GPU", d.no);
#endif
  return devices;
}

Ptr<Options> parseOptions(int argc,
                          char** argv,
                          cli::mode mode /*= cli::mode::training*/,
                          bool validate /*= true*/) {
  auto config = New<Config>(argc, argv, mode, validate);
  auto options = New<Options>();
  options->merge(config->get());
  return options;
}

}  // namespace marian
<|endoftext|>


<commit_before>#ifndef MJOLNIR_STEEPEST_DESCENT_SIMULATOR
#define MJOLNIR_STEEPEST_DESCENT_SIMULATOR
#include <mjolnir/core/SimulatorBase.hpp>
#include <mjolnir/core/System.hpp>
#include <mjolnir/core/ForceField.hpp>
#include <mjolnir/core/Observer.hpp>
#include <limits>

namespace mjolnir
{

template<typename traitsT>
class SteepestDescentSimulator final : public SimulatorBase
{
  public:
    typedef traitsT traits_type;
    typedef System<traits_type>     system_type;
    typedef ForceField<traits_type> forcefield_type;
    typedef Observer<traits_type>   observer_type;
    typedef typename traits_type::real_type       real_type;
    typedef typename traits_type::coordinate_type coordinate_type;

    SteepestDescentSimulator(const real_type h, const real_type threshold,
            const std::size_t step_limit, const std::size_t save_step,
            system_type&& sys, forcefield_type&& ff, observer_type&& obs)
    : h_(h), threshold_(threshold),
      step_limit_(step_limit), step_count_(0), save_step_(save_step),
      system_(std::move(sys)), ff_(std::move(ff)), observer_(std::move(obs))
    {}
    ~SteepestDescentSimulator() override = default;

    void initialize() override;
    bool step()       override;
    void finalize()   override;

    real_type calc_energy() const {return this->ff_.calc_energy(this->system_);}

    system_type&       system()       noexcept {return system_;}
    system_type const& system() const noexcept {return system_;}

    ForceField<traitsT>&       forcefields()       noexcept {return ff_;}
    ForceField<traitsT> const& forcefields() const noexcept {return ff_;}

  protected:
    real_type       h_;
    real_type       threshold_;
    std::size_t     step_limit_;
    std::size_t     step_count_;
    std::size_t     save_step_;
    system_type     system_;
    forcefield_type ff_;
    observer_type   observer_;
};

template<typename traitsT>
inline void SteepestDescentSimulator<traitsT>::initialize()
{
    this->ff_.initialize(this->system_);

    this->observer_.initialize(this->system_, this->ff_, total_step_);
    this->observer_.output(0, this->system_, this->ff_);
    return;
}

template<typename traitsT>
inline bool SteepestDescentSimulator<traitsT>::step()
{
    // calculate negative derivatives (-dV/dr)
    this->ff_.calc_force(this->system_);

    real_type max_disp2 = 0.0; // to update cell list and check the convergence
    real_type max_diff  = 0.0; // to check the convergence
    for(std::size_t i=0; i<this->system_.size(); ++i)
    {
        const coordinate_type disp = this->h_ * this->system_[i].force;

        max_diff = std::max(max_diff, std::abs(this->system_[i].force[0]));
        max_diff = std::max(max_diff, std::abs(this->system_[i].force[1]));
        max_diff = std::max(max_diff, std::abs(this->system_[i].force[2]));

        max_disp2 = std::max(max_disp2, length_sq(disp));
        system_[i].position = system_.adjust_position(system_[i].position + disp);
        system_[i].force    = coordinate_type(0, 0, 0);
    }

    if(max_diff < this->threshold_)
    {
        this->observer_.output(this->step_count_, this->system_, this->ff_);
        return false; // converged. stop the simulation!
    }
    this->system_.largest_displacement() = std::sqrt(max_disp2);

    if(step_count_ % save_step_ == 0)
    {
        this->observer_.output(this->step_count_, this->system_, this->ff_);
    }
    ++step_count_;
    return this->step_count_ < this->step_limit_;
}

template<typename traitsT>
inline void SteepestDescentSimulator<traitsT>::finalize()
{
    this->observer_.output(this->step_count_, this->system_, this->ff_);
    return;
}

} // mjolnir
#endif /* MJOLNIR_STEEPEST_DESCENT_SIMULATOR */
<commit_msg>fix typo<commit_after>#ifndef MJOLNIR_STEEPEST_DESCENT_SIMULATOR
#define MJOLNIR_STEEPEST_DESCENT_SIMULATOR
#include <mjolnir/core/SimulatorBase.hpp>
#include <mjolnir/core/System.hpp>
#include <mjolnir/core/ForceField.hpp>
#include <mjolnir/core/Observer.hpp>
#include <limits>

namespace mjolnir
{

template<typename traitsT>
class SteepestDescentSimulator final : public SimulatorBase
{
  public:
    typedef traitsT traits_type;
    typedef System<traits_type>     system_type;
    typedef ForceField<traits_type> forcefield_type;
    typedef Observer<traits_type>   observer_type;
    typedef typename traits_type::real_type       real_type;
    typedef typename traits_type::coordinate_type coordinate_type;

    SteepestDescentSimulator(const real_type h, const real_type threshold,
            const std::size_t step_limit, const std::size_t save_step,
            system_type&& sys, forcefield_type&& ff, observer_type&& obs)
    : h_(h), threshold_(threshold),
      step_limit_(step_limit), step_count_(0), save_step_(save_step),
      system_(std::move(sys)), ff_(std::move(ff)), observer_(std::move(obs))
    {}
    ~SteepestDescentSimulator() override = default;

    void initialize() override;
    bool step()       override;
    void finalize()   override;

    real_type calc_energy() const {return this->ff_.calc_energy(this->system_);}

    system_type&       system()       noexcept {return system_;}
    system_type const& system() const noexcept {return system_;}

    ForceField<traitsT>&       forcefields()       noexcept {return ff_;}
    ForceField<traitsT> const& forcefields() const noexcept {return ff_;}

  protected:
    real_type       h_;
    real_type       threshold_;
    std::size_t     step_limit_;
    std::size_t     step_count_;
    std::size_t     save_step_;
    system_type     system_;
    forcefield_type ff_;
    observer_type   observer_;
};

template<typename traitsT>
inline void SteepestDescentSimulator<traitsT>::initialize()
{
    this->ff_.initialize(this->system_);

    this->observer_.initialize(this->system_, this->ff_, step_limit_);
    this->observer_.output(0, this->system_, this->ff_);
    return;
}

template<typename traitsT>
inline bool SteepestDescentSimulator<traitsT>::step()
{
    // calculate negative derivatives (-dV/dr)
    this->ff_.calc_force(this->system_);

    real_type max_disp2 = 0.0; // to update cell list and check the convergence
    real_type max_diff  = 0.0; // to check the convergence
    for(std::size_t i=0; i<this->system_.size(); ++i)
    {
        const coordinate_type disp = this->h_ * this->system_[i].force;

        max_diff = std::max(max_diff, std::abs(this->system_[i].force[0]));
        max_diff = std::max(max_diff, std::abs(this->system_[i].force[1]));
        max_diff = std::max(max_diff, std::abs(this->system_[i].force[2]));

        max_disp2 = std::max(max_disp2, length_sq(disp));
        system_[i].position = system_.adjust_position(system_[i].position + disp);
        system_[i].force    = coordinate_type(0, 0, 0);
    }

    if(max_diff < this->threshold_)
    {
        this->observer_.output(this->step_count_, this->system_, this->ff_);
        return false; // converged. stop the simulation!
    }
    this->system_.largest_displacement() = std::sqrt(max_disp2);

    if(step_count_ % save_step_ == 0)
    {
        this->observer_.output(this->step_count_, this->system_, this->ff_);
    }
    ++step_count_;
    return this->step_count_ < this->step_limit_;
}

template<typename traitsT>
inline void SteepestDescentSimulator<traitsT>::finalize()
{
    this->observer_.output(this->step_count_, this->system_, this->ff_);
    return;
}

} // mjolnir
#endif /* MJOLNIR_STEEPEST_DESCENT_SIMULATOR */
<|endoftext|>


<commit_before>//
// Created by dar on 4/29/16.
//

#include <core/map/entity/Entity.h>
#include "LevelContext.h"
#include <core/map/Map.h>
#include <core/map/entity/EntityPlayer.h>
#include <core/map/TiledTxtMapLoader.h>

LevelContext::LevelContext(const std::string &name) : name(name) {
#ifdef __ANDROID__
    defaultBlockSize = blockSize = 96.0f;
#else
    defaultBlockSize = blockSize = 64.0f;
#endif //__ANDROID__

    scriptState["LevelContext"].setClass(kaguya::ClassMetatable<LevelContext>()
                                             .addMember("setMap", &LevelContext::setMap)
    );

    scriptState["TiledTxtMapLoader"].setClass(kaguya::ClassMetatable<TiledTxtMapLoader>()
                                                  .addConstructor<std::string>()
                                                  .addMember("loadMap", &TiledTxtMapLoader::loadMap)
    );

    scriptState["Entity"].setClass(kaguya::ClassMetatable<Entity>()
                                       .addConstructor<Map *, double, double>()
                                       .addMember("getId", &Entity::getId)
                                       .addMember("getX", &Entity::getX)
                                       .addMember("getY", &Entity::getY)
                                       .addMember("getAngle", &Entity::getAngle)
                                       .addMember("getWidth", &Entity::getWidth)
                                       .addMember("getHeight", &Entity::getHeight)
                                       .addMember("setX", &Entity::setX)
                                       .addMember("setY", &Entity::setY)
                                       .addMember("setAngle", &Entity::setAngle)
                                       .addMember("getBody", &Entity::getBody)
                                       .addMember("doesCollide", &Entity::doesCollide)
                                       .addMember("remove", &Entity::remove)
    );

    scriptState["EntityMoving"].setClass(kaguya::ClassMetatable<EntityMoving, Entity>()
                                             .addConstructor<Map *, double, double>()
                                             .addMember("setBodyType", &EntityMoving::setBodyType)
                                             .addMember("applyForce", &EntityMoving::applyForce)
                                             .addMember("applyImpulse", &EntityMoving::applyImpulse)
    );

    scriptState["EntityPlayer"].setClass(kaguya::ClassMetatable<EntityPlayer, EntityMoving>()
                                             .addMember("getColorfulness", &EntityPlayer::getColorfulness)
                                             .addMember("getDamagedToy", &EntityPlayer::getDamagedToy)
                                             .addMember("getEjectTime", &EntityPlayer::getEjectTime)
                                             .addMember("getToyToMerge", &EntityPlayer::getToyToMerge)
                                             .addMember("getTailAnimation", &EntityPlayer::getTailAnimation)
    );

    scriptState["Map"].setClass(kaguya::ClassMetatable<Map>()
                                    .addStaticMember("getWidth", &Map::getWidth)
                                    .addStaticMember("getHeight", &Map::getHeight)
                                    .addStaticMember("getBlock", &Map::getBlock)
                                    .addStaticMember("getEntities", &Map::getEntities)
                                    .addStaticMember("getEntity", &Map::getEntity<>)
                                    .addStaticMember("getEntityPlayer", &Map::getEntity<EntityPlayer>)
                                    .addStaticMember("getEntityAt", &Map::getEntityAt<Entity>)
                                    .addStaticMember("getWorldTime", &Map::getWorldTime)
    );

    scriptState["this"] = this;
    scriptState.dofile("scripts/levels/" + name + ".lua");

    for (Entity *e : map->getEntities()) {
        if (EntityPlayer *p = dynamic_cast<EntityPlayer *>(e)) {
            this->player = p;
            break;
        }
    }
}<commit_msg>Removed static modifier from Map's members script declarations<commit_after>//
// Created by dar on 4/29/16.
//

#include <core/map/entity/Entity.h>
#include "LevelContext.h"
#include <core/map/Map.h>
#include <core/map/entity/EntityPlayer.h>
#include <core/map/TiledTxtMapLoader.h>

LevelContext::LevelContext(const std::string &name) : name(name) {
#ifdef __ANDROID__
    defaultBlockSize = blockSize = 96.0f;
#else
    defaultBlockSize = blockSize = 64.0f;
#endif //__ANDROID__

    scriptState["LevelContext"].setClass(kaguya::ClassMetatable<LevelContext>()
                                             .addMember("setMap", &LevelContext::setMap)
    );

    scriptState["TiledTxtMapLoader"].setClass(kaguya::ClassMetatable<TiledTxtMapLoader>()
                                                  .addConstructor<std::string>()
                                                  .addMember("loadMap", &TiledTxtMapLoader::loadMap)
    );

    scriptState["Entity"].setClass(kaguya::ClassMetatable<Entity>()
                                       .addConstructor<Map *, double, double>()
                                       .addMember("getId", &Entity::getId)
                                       .addMember("getX", &Entity::getX)
                                       .addMember("getY", &Entity::getY)
                                       .addMember("getAngle", &Entity::getAngle)
                                       .addMember("getWidth", &Entity::getWidth)
                                       .addMember("getHeight", &Entity::getHeight)
                                       .addMember("setX", &Entity::setX)
                                       .addMember("setY", &Entity::setY)
                                       .addMember("setAngle", &Entity::setAngle)
                                       .addMember("getBody", &Entity::getBody)
                                       .addMember("doesCollide", &Entity::doesCollide)
                                       .addMember("remove", &Entity::remove)
    );

    scriptState["EntityMoving"].setClass(kaguya::ClassMetatable<EntityMoving, Entity>()
                                             .addConstructor<Map *, double, double>()
                                             .addMember("setBodyType", &EntityMoving::setBodyType)
                                             .addMember("applyForce", &EntityMoving::applyForce)
                                             .addMember("applyImpulse", &EntityMoving::applyImpulse)
    );

    scriptState["EntityPlayer"].setClass(kaguya::ClassMetatable<EntityPlayer, EntityMoving>()
                                             .addMember("getColorfulness", &EntityPlayer::getColorfulness)
                                             .addMember("getDamagedToy", &EntityPlayer::getDamagedToy)
                                             .addMember("getEjectTime", &EntityPlayer::getEjectTime)
                                             .addMember("getToyToMerge", &EntityPlayer::getToyToMerge)
                                             .addMember("getTailAnimation", &EntityPlayer::getTailAnimation)
    );

    scriptState["Map"].setClass(kaguya::ClassMetatable<Map>()
                                    .addMember("getWidth", &Map::getWidth)
                                    .addMember("getHeight", &Map::getHeight)
                                    .addMember("getBlock", &Map::getBlock)
                                    .addMember("getEntities", &Map::getEntities)
                                    .addMember("getEntity", &Map::getEntity<>)
                                    .addMember("getEntityPlayer", &Map::getEntity<EntityPlayer>)
                                    .addMember("getEntityAt", &Map::getEntityAt<Entity>)
                                    .addMember("getWorldTime", &Map::getWorldTime)
    );

    scriptState["this"] = this;
    scriptState.dofile("scripts/levels/" + name + ".lua");

    for (Entity *e : map->getEntities()) {
        if (EntityPlayer *p = dynamic_cast<EntityPlayer *>(e)) {
            this->player = p;
            break;
        }
    }
}<|endoftext|>


<commit_before>
/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBBoxRecord.h"

void SkBBoxRecord::drawOval(const SkRect& rect, const SkPaint& paint) {
    if (this->transformBounds(rect, &paint)) {
        INHERITED::drawOval(rect, paint);
    }
}

void SkBBoxRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
    if (this->transformBounds(rrect.rect(), &paint)) {
        INHERITED::drawRRect(rrect, paint);
    }
}

void SkBBoxRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
    if (this->transformBounds(rect, &paint)) {
        INHERITED::drawRect(rect, paint);
    }
}

void SkBBoxRecord::drawPath(const SkPath& path, const SkPaint& paint) {
    if (path.isInverseFillType()) {
        // If path is inverse filled, use the current clip bounds as the
        // path's device-space bounding box.
        SkIRect clipBounds;
        if (this->getClipDeviceBounds(&clipBounds)) {
            this->handleBBox(SkRect::MakeFromIRect(clipBounds));
            INHERITED::drawPath(path, paint);
        }
    } else if (this->transformBounds(path.getBounds(), &paint)) {
        INHERITED::drawPath(path, paint);
    }
}

void SkBBoxRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
                              const SkPaint& paint) {
    SkRect bbox;
    bbox.set(pts, count);
    // Small min width value, just to ensure hairline point bounding boxes aren't empty.
    // Even though we know hairline primitives are drawn one pixel wide, we do not use a
    // minimum of 1 because the playback scale factor is unknown at record time. Later
    // outsets will take care of adding additional padding for antialiasing and rounding out
    // to integer device coordinates, guaranteeing that the rasterized pixels will be included
    // in the computed bounds.
    // Note: The device coordinate outset in SkBBoxHierarchyRecord::handleBBox is currently
    // done in the recording coordinate space, which is wrong.
    // http://code.google.com/p/skia/issues/detail?id=1021
    static const SkScalar kMinWidth = SkFloatToScalar(0.01f);
    SkScalar halfStrokeWidth = SkMaxScalar(paint.getStrokeWidth(), kMinWidth) / 2;
    bbox.outset(halfStrokeWidth, halfStrokeWidth);
    if (this->transformBounds(bbox, &paint)) {
        INHERITED::drawPoints(mode, count, pts, paint);
    }
}

void SkBBoxRecord::drawPaint(const SkPaint& paint) {
    SkRect bbox;
    if (this->getClipBounds(&bbox)) {
        if (this->transformBounds(bbox, &paint)) {
            INHERITED::drawPaint(paint);
        }
    }
}

void SkBBoxRecord::clear(SkColor color) {
    SkISize size = this->getDeviceSize();
    SkRect bbox = {0, 0, SkIntToScalar(size.width()), SkIntToScalar(size.height())};
    this->handleBBox(bbox);
    INHERITED::clear(color);
}

void SkBBoxRecord::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
                            const SkPaint& paint) {
    SkRect bbox;
    paint.measureText(text, byteLength, &bbox);
    SkPaint::FontMetrics metrics;
    paint.getFontMetrics(&metrics);

    // Vertical and aligned text need to be offset
    if (paint.isVerticalText()) {
        SkScalar h = bbox.fBottom - bbox.fTop;
        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
            bbox.fTop    -= h / 2;
            bbox.fBottom -= h / 2;
        }
        // Pad top and bottom with max extents from FontMetrics
        bbox.fBottom += metrics.fBottom;
        bbox.fTop += metrics.fTop;
    } else {
        SkScalar w = bbox.fRight - bbox.fLeft;
        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
            bbox.fLeft  -= w / 2;
            bbox.fRight -= w / 2;
        } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
            bbox.fLeft  -= w;
            bbox.fRight -= w;
        }
        // Set vertical bounds to max extents from font metrics
        bbox.fTop = metrics.fTop;
        bbox.fBottom = metrics.fBottom;
    }

    // Pad horizontal bounds on each side by half of max vertical extents (this is sort of
    // arbitrary, but seems to produce reasonable results, if there were a way of getting max
    // glyph X-extents to pad by, that may be better here, but FontMetrics fXMin and fXMax seem
    // incorrect on most platforms (too small in Linux, never even set in Windows).
    SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
    bbox.fLeft  -= pad;
    bbox.fRight += pad;

    bbox.fLeft += x;
    bbox.fRight += x;
    bbox.fTop += y;
    bbox.fBottom += y;
    if (this->transformBounds(bbox, &paint)) {
        INHERITED::drawText(text, byteLength, x, y, paint);
    }
}

void SkBBoxRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
                              const SkPaint* paint) {
    SkRect bbox = {left, top, left + bitmap.width(), top + bitmap.height()};
    if (this->transformBounds(bbox, paint)) {
        INHERITED::drawBitmap(bitmap, left, top, paint);
    }
}

void SkBBoxRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
                                  const SkRect& dst, const SkPaint* paint) {
    if (this->transformBounds(dst, paint)) {
        INHERITED::drawBitmapRectToRect(bitmap, src, dst, paint);
    }
}

void SkBBoxRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& mat,
                                    const SkPaint* paint) {
    SkMatrix m = mat;
    SkRect bbox = {0, 0, SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())};
    m.mapRect(&bbox);
    if (this->transformBounds(bbox, paint)) {
        INHERITED::drawBitmapMatrix(bitmap, mat, paint);
    }
}

void SkBBoxRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
                                  const SkRect& dst, const SkPaint* paint) {
    if (this->transformBounds(dst, paint)) {
        INHERITED::drawBitmapNine(bitmap, center, dst, paint);
    }
}

void SkBBoxRecord::drawPosText(const void* text, size_t byteLength,
                               const SkPoint pos[], const SkPaint& paint) {
    SkRect bbox;
    bbox.set(pos, paint.countText(text, byteLength));
    SkPaint::FontMetrics metrics;
    paint.getFontMetrics(&metrics);
    bbox.fTop += metrics.fTop;
    bbox.fBottom += metrics.fBottom;

    // pad on left and right by half of max vertical glyph extents
    SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
    bbox.fLeft += pad;
    bbox.fRight -= pad;

    if (this->transformBounds(bbox, &paint)) {
        INHERITED::drawPosText(text, byteLength, pos, paint);
    }
}

void SkBBoxRecord::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
                                SkScalar constY, const SkPaint& paint) {
    SkRect bbox;
    size_t numChars = paint.countText(text, byteLength);
    if (numChars > 0) {
        bbox.fLeft  = xpos[0];
        bbox.fRight = xpos[numChars - 1];
        // if we had a guarantee that these will be monotonically increasing, this could be sped up
        for (size_t i = 1; i < numChars; ++i) {
            if (xpos[i] < bbox.fLeft) {
                bbox.fLeft = xpos[i];
            }
            if (xpos[i] > bbox.fRight) {
                bbox.fRight = xpos[i];
            }
        }
        SkPaint::FontMetrics metrics;
        paint.getFontMetrics(&metrics);

        // pad horizontally by max glyph height
        SkScalar pad = (metrics.fTop - metrics.fBottom);
        bbox.fLeft  += pad;
        bbox.fRight -= pad;

        bbox.fTop    = metrics.fTop + constY;
        bbox.fBottom = metrics.fBottom + constY;
        if (!this->transformBounds(bbox, &paint)) {
            return;
        }
    }
    INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
}

void SkBBoxRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
                              const SkPaint* paint) {
    SkRect bbox;
    bbox.set(SkIRect::MakeXYWH(left, top, bitmap.width(), bitmap.height()));
    this->handleBBox(bbox); // directly call handleBBox, matrix is ignored
    INHERITED::drawSprite(bitmap, left, top, paint);
}

void SkBBoxRecord::drawTextOnPath(const void* text, size_t byteLength,
                                  const SkPath& path, const SkMatrix* matrix,
                                  const SkPaint& paint) {
    SkRect bbox = path.getBounds();
    SkPaint::FontMetrics metrics;
    paint.getFontMetrics(&metrics);

    // pad out all sides by the max glyph height above baseline
    SkScalar pad = metrics.fTop;
    bbox.fLeft += pad;
    bbox.fRight -= pad;
    bbox.fTop += pad;
    bbox.fBottom -= pad;

    if (this->transformBounds(bbox, &paint)) {
        INHERITED::drawTextOnPath(text, byteLength, path, matrix, paint);
    }
}

void SkBBoxRecord::drawVertices(VertexMode mode, int vertexCount,
                                const SkPoint vertices[], const SkPoint texs[],
                                const SkColor colors[], SkXfermode* xfer,
                                const uint16_t indices[], int indexCount,
                                const SkPaint& paint) {
    SkRect bbox;
    bbox.set(vertices, vertexCount);
    if (this->transformBounds(bbox, &paint)) {
        INHERITED::drawVertices(mode, vertexCount, vertices, texs,
                                colors, xfer, indices, indexCount, paint);
    }
}

void SkBBoxRecord::drawPicture(SkPicture& picture) {
    if (picture.width() > 0 && picture.height() > 0 &&
        this->transformBounds(SkRect::MakeWH(picture.width(), picture.height()), NULL)) {
        INHERITED::drawPicture(picture);
    }
}

bool SkBBoxRecord::transformBounds(const SkRect& bounds, const SkPaint* paint) {
    SkRect outBounds = bounds;
    outBounds.sort();

    if (paint) {
        // account for stroking, path effects, shadows, etc
        if (paint->canComputeFastBounds()) {
            SkRect temp;
            outBounds = paint->computeFastBounds(outBounds, &temp);
        } else {
            // set bounds to current clip
            if (!this->getClipBounds(&outBounds)) {
                // current clip is empty
                return false;
            }
        }
    }

    SkRect clip;

    if (this->getClipBounds(&clip) && outBounds.intersect(clip)) {
        this->getTotalMatrix().mapRect(&outBounds);
        this->handleBBox(outBounds);
        return true;
    }

    return false;
}

<commit_msg>Properly reject clipped out draws in BBox pictures. https://codereview.appspot.com/7057065/<commit_after>
/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBBoxRecord.h"

void SkBBoxRecord::drawOval(const SkRect& rect, const SkPaint& paint) {
    if (this->transformBounds(rect, &paint)) {
        INHERITED::drawOval(rect, paint);
    }
}

void SkBBoxRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
    if (this->transformBounds(rrect.rect(), &paint)) {
        INHERITED::drawRRect(rrect, paint);
    }
}

void SkBBoxRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
    if (this->transformBounds(rect, &paint)) {
        INHERITED::drawRect(rect, paint);
    }
}

void SkBBoxRecord::drawPath(const SkPath& path, const SkPaint& paint) {
    if (path.isInverseFillType()) {
        // If path is inverse filled, use the current clip bounds as the
        // path's device-space bounding box.
        SkIRect clipBounds;
        if (this->getClipDeviceBounds(&clipBounds)) {
            this->handleBBox(SkRect::MakeFromIRect(clipBounds));
            INHERITED::drawPath(path, paint);
        }
    } else if (this->transformBounds(path.getBounds(), &paint)) {
        INHERITED::drawPath(path, paint);
    }
}

void SkBBoxRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
                              const SkPaint& paint) {
    SkRect bbox;
    bbox.set(pts, count);
    // Small min width value, just to ensure hairline point bounding boxes aren't empty.
    // Even though we know hairline primitives are drawn one pixel wide, we do not use a
    // minimum of 1 because the playback scale factor is unknown at record time. Later
    // outsets will take care of adding additional padding for antialiasing and rounding out
    // to integer device coordinates, guaranteeing that the rasterized pixels will be included
    // in the computed bounds.
    // Note: The device coordinate outset in SkBBoxHierarchyRecord::handleBBox is currently
    // done in the recording coordinate space, which is wrong.
    // http://code.google.com/p/skia/issues/detail?id=1021
    static const SkScalar kMinWidth = SkFloatToScalar(0.01f);
    SkScalar halfStrokeWidth = SkMaxScalar(paint.getStrokeWidth(), kMinWidth) / 2;
    bbox.outset(halfStrokeWidth, halfStrokeWidth);
    if (this->transformBounds(bbox, &paint)) {
        INHERITED::drawPoints(mode, count, pts, paint);
    }
}

void SkBBoxRecord::drawPaint(const SkPaint& paint) {
    SkRect bbox;
    if (this->getClipBounds(&bbox)) {
        if (this->transformBounds(bbox, &paint)) {
            INHERITED::drawPaint(paint);
        }
    }
}

void SkBBoxRecord::clear(SkColor color) {
    SkISize size = this->getDeviceSize();
    SkRect bbox = {0, 0, SkIntToScalar(size.width()), SkIntToScalar(size.height())};
    this->handleBBox(bbox);
    INHERITED::clear(color);
}

void SkBBoxRecord::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
                            const SkPaint& paint) {
    SkRect bbox;
    paint.measureText(text, byteLength, &bbox);
    SkPaint::FontMetrics metrics;
    paint.getFontMetrics(&metrics);

    // Vertical and aligned text need to be offset
    if (paint.isVerticalText()) {
        SkScalar h = bbox.fBottom - bbox.fTop;
        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
            bbox.fTop    -= h / 2;
            bbox.fBottom -= h / 2;
        }
        // Pad top and bottom with max extents from FontMetrics
        bbox.fBottom += metrics.fBottom;
        bbox.fTop += metrics.fTop;
    } else {
        SkScalar w = bbox.fRight - bbox.fLeft;
        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
            bbox.fLeft  -= w / 2;
            bbox.fRight -= w / 2;
        } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
            bbox.fLeft  -= w;
            bbox.fRight -= w;
        }
        // Set vertical bounds to max extents from font metrics
        bbox.fTop = metrics.fTop;
        bbox.fBottom = metrics.fBottom;
    }

    // Pad horizontal bounds on each side by half of max vertical extents (this is sort of
    // arbitrary, but seems to produce reasonable results, if there were a way of getting max
    // glyph X-extents to pad by, that may be better here, but FontMetrics fXMin and fXMax seem
    // incorrect on most platforms (too small in Linux, never even set in Windows).
    SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
    bbox.fLeft  -= pad;
    bbox.fRight += pad;

    bbox.fLeft += x;
    bbox.fRight += x;
    bbox.fTop += y;
    bbox.fBottom += y;
    if (this->transformBounds(bbox, &paint)) {
        INHERITED::drawText(text, byteLength, x, y, paint);
    }
}

void SkBBoxRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
                              const SkPaint* paint) {
    SkRect bbox = {left, top, left + bitmap.width(), top + bitmap.height()};
    if (this->transformBounds(bbox, paint)) {
        INHERITED::drawBitmap(bitmap, left, top, paint);
    }
}

void SkBBoxRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
                                  const SkRect& dst, const SkPaint* paint) {
    if (this->transformBounds(dst, paint)) {
        INHERITED::drawBitmapRectToRect(bitmap, src, dst, paint);
    }
}

void SkBBoxRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& mat,
                                    const SkPaint* paint) {
    SkMatrix m = mat;
    SkRect bbox = {0, 0, SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())};
    m.mapRect(&bbox);
    if (this->transformBounds(bbox, paint)) {
        INHERITED::drawBitmapMatrix(bitmap, mat, paint);
    }
}

void SkBBoxRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
                                  const SkRect& dst, const SkPaint* paint) {
    if (this->transformBounds(dst, paint)) {
        INHERITED::drawBitmapNine(bitmap, center, dst, paint);
    }
}

void SkBBoxRecord::drawPosText(const void* text, size_t byteLength,
                               const SkPoint pos[], const SkPaint& paint) {
    SkRect bbox;
    bbox.set(pos, paint.countText(text, byteLength));
    SkPaint::FontMetrics metrics;
    paint.getFontMetrics(&metrics);
    bbox.fTop += metrics.fTop;
    bbox.fBottom += metrics.fBottom;

    // pad on left and right by half of max vertical glyph extents
    SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
    bbox.fLeft += pad;
    bbox.fRight -= pad;

    if (this->transformBounds(bbox, &paint)) {
        INHERITED::drawPosText(text, byteLength, pos, paint);
    }
}

void SkBBoxRecord::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
                                SkScalar constY, const SkPaint& paint) {
    SkRect bbox;
    size_t numChars = paint.countText(text, byteLength);
    if (numChars > 0) {
        bbox.fLeft  = xpos[0];
        bbox.fRight = xpos[numChars - 1];
        // if we had a guarantee that these will be monotonically increasing, this could be sped up
        for (size_t i = 1; i < numChars; ++i) {
            if (xpos[i] < bbox.fLeft) {
                bbox.fLeft = xpos[i];
            }
            if (xpos[i] > bbox.fRight) {
                bbox.fRight = xpos[i];
            }
        }
        SkPaint::FontMetrics metrics;
        paint.getFontMetrics(&metrics);

        // pad horizontally by max glyph height
        SkScalar pad = (metrics.fTop - metrics.fBottom);
        bbox.fLeft  += pad;
        bbox.fRight -= pad;

        bbox.fTop    = metrics.fTop + constY;
        bbox.fBottom = metrics.fBottom + constY;
        if (!this->transformBounds(bbox, &paint)) {
            return;
        }
    }
    INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
}

void SkBBoxRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
                              const SkPaint* paint) {
    SkRect bbox;
    bbox.set(SkIRect::MakeXYWH(left, top, bitmap.width(), bitmap.height()));
    this->handleBBox(bbox); // directly call handleBBox, matrix is ignored
    INHERITED::drawSprite(bitmap, left, top, paint);
}

void SkBBoxRecord::drawTextOnPath(const void* text, size_t byteLength,
                                  const SkPath& path, const SkMatrix* matrix,
                                  const SkPaint& paint) {
    SkRect bbox = path.getBounds();
    SkPaint::FontMetrics metrics;
    paint.getFontMetrics(&metrics);

    // pad out all sides by the max glyph height above baseline
    SkScalar pad = metrics.fTop;
    bbox.fLeft += pad;
    bbox.fRight -= pad;
    bbox.fTop += pad;
    bbox.fBottom -= pad;

    if (this->transformBounds(bbox, &paint)) {
        INHERITED::drawTextOnPath(text, byteLength, path, matrix, paint);
    }
}

void SkBBoxRecord::drawVertices(VertexMode mode, int vertexCount,
                                const SkPoint vertices[], const SkPoint texs[],
                                const SkColor colors[], SkXfermode* xfer,
                                const uint16_t indices[], int indexCount,
                                const SkPaint& paint) {
    SkRect bbox;
    bbox.set(vertices, vertexCount);
    if (this->transformBounds(bbox, &paint)) {
        INHERITED::drawVertices(mode, vertexCount, vertices, texs,
                                colors, xfer, indices, indexCount, paint);
    }
}

void SkBBoxRecord::drawPicture(SkPicture& picture) {
    if (picture.width() > 0 && picture.height() > 0 &&
        this->transformBounds(SkRect::MakeWH(picture.width(), picture.height()), NULL)) {
        INHERITED::drawPicture(picture);
    }
}

bool SkBBoxRecord::transformBounds(const SkRect& bounds, const SkPaint* paint) {
    SkRect outBounds = bounds;
    outBounds.sort();

    if (paint) {
        // account for stroking, path effects, shadows, etc
        if (paint->canComputeFastBounds()) {
            SkRect temp;
            outBounds = paint->computeFastBounds(outBounds, &temp);
        } else {
            // set bounds to current clip
            if (!this->getClipBounds(&outBounds)) {
                // current clip is empty
                return false;
            }
        }
    }

    if (!this->quickReject(outBounds)) {
        this->getTotalMatrix().mapRect(&outBounds);
        this->handleBBox(outBounds);
        return true;
    }

    return false;
}

<|endoftext|>


<commit_before>#ifndef __GLOBALS_HPP_INCLUDED
#define __GLOBALS_HPP_INCLUDED

#include "code/ylikuutio/callback_system/key_and_callback_struct.hpp"
#include "any_value.hpp"

// GCC (at least g++ 4.7.2) and Visual Studio 2015 do support
// setting default values of a struct using C++11 syntax.
// Clang 3.7.0 and Visual Studio 2013 do not support
// setting default values of a struct using C++11 syntax.
// Visual Studio 2013 fails to compile, whereas Clang-compiled
// executable with code with setting default values of a struct
// causes Segmentation fault upon execution of the program.
// Compilers that don't support setting default values of a struct
// are handled by setting the default values in a macro.
// http://stackoverflow.com/questions/16782103/initializing-default-values-in-a-struct/16783513#16783513
#ifdef __clang__
#elif defined(__GNUC__)
#define __STRUCT_DEFAULT_VALUES_ARE_ACCEPTED
#elif defined(_WIN32)
#if (_MSC_VER >= 1900)
#define __STRUCT_DEFAULT_VALUES_ARE_ACCEPTED
#endif
#endif

// GLEW must be included here, because `globals.hpp` may be compiled
// first, and if `GL/glew.h` is not included before `glfw3.h` (?),
// then g++ prints the following error:
// `error: #error gl.h included before glew.h`
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h> // GLfloat, GLuint etc.
#endif

// Include GLFW
#ifndef __GLFW3_H_INCLUDED
#define __GLFW3_H_INCLUDED
#include <glfw3.h>
#endif

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <stdint.h> // uint32_t etc.
#include <string>   // std::string
#include <unordered_map> // std::unordered_map
#include <vector>   // std::vector

#ifndef PI
#define PI 3.14159265359f
#endif

namespace config
{
    class SettingMaster;
    class Setting;
}

namespace callback_system
{
    class CallbackEngine;
    class CallbackObject;
    class CallbackParameter;
}

namespace graph
{
    class Graph;
}

typedef datatypes::AnyValue* (*ConsoleCommandCallback) (
        console::Console*,
        ontology::Universe*,
        std::vector<std::string>& command_parameters);

typedef struct ConsoleStruct
{
    std::vector<KeyAndCallbackStruct>** current_keypress_callback_engine_vector_pointer_pointer;
    std::vector<KeyAndCallbackStruct>** current_keyrelease_callback_engine_vector_pointer_pointer;
    std::unordered_map<std::string, ConsoleCommandCallback>* command_callback_map_pointer;
    ontology::Universe* universe_pointer;
    ontology::Font2D* font2D_pointer;
} ConsoleStruct;

typedef datatypes::AnyValue* (*ActivateCallback) (ontology::Universe* universe, config::SettingMaster* setting_master);

typedef struct SettingStruct
{
    SettingStruct(datatypes::AnyValue& initial_value)
        : initial_value(initial_value), should_ylikuutio_call_activate_callback_now(true), setting_master_pointer(nullptr), activate_callback(nullptr)
    {
        // constructor.
    }
    std::string name;
    datatypes::AnyValue& initial_value;
    config::SettingMaster* setting_master_pointer;
    ActivateCallback activate_callback;
    bool should_ylikuutio_call_activate_callback_now;
} SettingStruct;

typedef struct
{
    uint32_t screen_width;
    uint32_t screen_height;
    uint32_t x;
    uint32_t y;
    uint32_t text_size;
    uint32_t font_size;
    std::string text;
    const char* text_char;
    const char* char_font_texture_file_format;
    const char* horizontal_alignment;
    const char* vertical_alignment;
} PrintingStruct;

typedef struct
{
    double rho;
    double theta;
    double phi;
} SphericalCoordinatesStruct;

typedef struct SphericalWorldStruct
{
    SphericalWorldStruct()
        :SRTM_latitude_step_in_degrees(1.0f/1200.0f), SRTM_longitude_step_in_degrees(1.0f/1200.0f)
    {
        // constructor.
    }
    double southern_latitude;
    double northern_latitude;
    double western_longitude;
    double eastern_longitude;
    double SRTM_latitude_step_in_degrees;
    double SRTM_longitude_step_in_degrees;
} SphericalWorldStruct;

typedef struct TriangulateQuadsStruct
{
    TriangulateQuadsStruct()
        : should_ylikuutio_use_real_texture_coordinates(true)
    {
        // constructor.
    }
    uint32_t image_width;
    uint32_t image_height;
    std::string triangulation_type;
    bool should_ylikuutio_use_real_texture_coordinates;
    double sphere_radius;
    SphericalWorldStruct spherical_world_struct;
} TriangulateQuadsStruct;

typedef struct TriangulatePolygonsStruct
{
    TriangulatePolygonsStruct()
        : should_ylikuutio_use_real_texture_coordinates(true)
    {
        // constructor.
    }
    std::vector<std::vector<glm::vec2>>* input_vertices;
    bool should_ylikuutio_use_real_texture_coordinates;
} TriangulatePolygonsStruct;

typedef struct
{
    uint32_t image_width;
    uint32_t image_height;
    bool should_ylikuutio_use_real_texture_coordinates;
} BilinearInterpolationStruct;

typedef struct
{
    uint32_t image_width;
    uint32_t image_height;
    double sphere_radius;
    bool is_bilinear_interpolation_in_use;
    SphericalWorldStruct spherical_world_struct;
} TransformationStruct;

typedef datatypes::AnyValue* (*InputParametersToAnyValueCallback) (
        callback_system::CallbackEngine*,
        callback_system::CallbackObject*,
        std::vector<callback_system::CallbackParameter*>&);

namespace console
{
    class Console;
}
typedef datatypes::AnyValue* (*InputParametersToAnyValueCallbackWithConsole) (
        callback_system::CallbackEngine*,
        callback_system::CallbackObject*,
        std::vector<callback_system::CallbackParameter*>&,
        console::Console*);

typedef datatypes::AnyValue* (*GetContentCallback) (
        callback_system::CallbackEngine*,
        callback_system::CallbackObject*,
        std::vector<callback_system::CallbackParameter*>&,
        uint32_t x_start,
        uint32_t y_start,
        uint32_t z_start,
        uint32_t x_size,
        uint32_t y_size,
        uint32_t z_size);

#endif
<commit_msg>`typedef struct TriangulateQuadsStruct`: `x_step` & `z_step`.<commit_after>#ifndef __GLOBALS_HPP_INCLUDED
#define __GLOBALS_HPP_INCLUDED

#include "code/ylikuutio/callback_system/key_and_callback_struct.hpp"
#include "any_value.hpp"

// GCC (at least g++ 4.7.2) and Visual Studio 2015 do support
// setting default values of a struct using C++11 syntax.
// Clang 3.7.0 and Visual Studio 2013 do not support
// setting default values of a struct using C++11 syntax.
// Visual Studio 2013 fails to compile, whereas Clang-compiled
// executable with code with setting default values of a struct
// causes Segmentation fault upon execution of the program.
// Compilers that don't support setting default values of a struct
// are handled by setting the default values in a macro.
// http://stackoverflow.com/questions/16782103/initializing-default-values-in-a-struct/16783513#16783513
#ifdef __clang__
#elif defined(__GNUC__)
#define __STRUCT_DEFAULT_VALUES_ARE_ACCEPTED
#elif defined(_WIN32)
#if (_MSC_VER >= 1900)
#define __STRUCT_DEFAULT_VALUES_ARE_ACCEPTED
#endif
#endif

// GLEW must be included here, because `globals.hpp` may be compiled
// first, and if `GL/glew.h` is not included before `glfw3.h` (?),
// then g++ prints the following error:
// `error: #error gl.h included before glew.h`
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h> // GLfloat, GLuint etc.
#endif

// Include GLFW
#ifndef __GLFW3_H_INCLUDED
#define __GLFW3_H_INCLUDED
#include <glfw3.h>
#endif

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <stdint.h> // uint32_t etc.
#include <string>   // std::string
#include <unordered_map> // std::unordered_map
#include <vector>   // std::vector

#ifndef PI
#define PI 3.14159265359f
#endif

namespace config
{
    class SettingMaster;
    class Setting;
}

namespace callback_system
{
    class CallbackEngine;
    class CallbackObject;
    class CallbackParameter;
}

namespace graph
{
    class Graph;
}

typedef datatypes::AnyValue* (*ConsoleCommandCallback) (
        console::Console*,
        ontology::Universe*,
        std::vector<std::string>& command_parameters);

typedef struct ConsoleStruct
{
    std::vector<KeyAndCallbackStruct>** current_keypress_callback_engine_vector_pointer_pointer;
    std::vector<KeyAndCallbackStruct>** current_keyrelease_callback_engine_vector_pointer_pointer;
    std::unordered_map<std::string, ConsoleCommandCallback>* command_callback_map_pointer;
    ontology::Universe* universe_pointer;
    ontology::Font2D* font2D_pointer;
} ConsoleStruct;

typedef datatypes::AnyValue* (*ActivateCallback) (ontology::Universe* universe, config::SettingMaster* setting_master);

typedef struct SettingStruct
{
    SettingStruct(datatypes::AnyValue& initial_value)
        : initial_value(initial_value), should_ylikuutio_call_activate_callback_now(true), setting_master_pointer(nullptr), activate_callback(nullptr)
    {
        // constructor.
    }
    std::string name;
    datatypes::AnyValue& initial_value;
    config::SettingMaster* setting_master_pointer;
    ActivateCallback activate_callback;
    bool should_ylikuutio_call_activate_callback_now;
} SettingStruct;

typedef struct
{
    uint32_t screen_width;
    uint32_t screen_height;
    uint32_t x;
    uint32_t y;
    uint32_t text_size;
    uint32_t font_size;
    std::string text;
    const char* text_char;
    const char* char_font_texture_file_format;
    const char* horizontal_alignment;
    const char* vertical_alignment;
} PrintingStruct;

typedef struct
{
    double rho;
    double theta;
    double phi;
} SphericalCoordinatesStruct;

typedef struct SphericalWorldStruct
{
    SphericalWorldStruct()
        :SRTM_latitude_step_in_degrees(1.0f/1200.0f), SRTM_longitude_step_in_degrees(1.0f/1200.0f)
    {
        // constructor.
    }
    double southern_latitude;
    double northern_latitude;
    double western_longitude;
    double eastern_longitude;
    double SRTM_latitude_step_in_degrees;
    double SRTM_longitude_step_in_degrees;
} SphericalWorldStruct;

typedef struct TriangulateQuadsStruct
{
    TriangulateQuadsStruct()
        : should_ylikuutio_use_real_texture_coordinates(true), x_step(1), z_step(1)
    {
        // constructor.
    }
    uint32_t image_width;
    uint32_t image_height;
    uint32_t x_step;
    uint32_t z_step;
    std::string triangulation_type;
    bool should_ylikuutio_use_real_texture_coordinates;
    double sphere_radius;
    SphericalWorldStruct spherical_world_struct;
} TriangulateQuadsStruct;

typedef struct TriangulatePolygonsStruct
{
    TriangulatePolygonsStruct()
        : should_ylikuutio_use_real_texture_coordinates(true)
    {
        // constructor.
    }
    std::vector<std::vector<glm::vec2>>* input_vertices;
    bool should_ylikuutio_use_real_texture_coordinates;
} TriangulatePolygonsStruct;

typedef struct
{
    uint32_t image_width;
    uint32_t image_height;
    bool should_ylikuutio_use_real_texture_coordinates;
} BilinearInterpolationStruct;

typedef struct
{
    uint32_t image_width;
    uint32_t image_height;
    double sphere_radius;
    bool is_bilinear_interpolation_in_use;
    SphericalWorldStruct spherical_world_struct;
} TransformationStruct;

typedef datatypes::AnyValue* (*InputParametersToAnyValueCallback) (
        callback_system::CallbackEngine*,
        callback_system::CallbackObject*,
        std::vector<callback_system::CallbackParameter*>&);

namespace console
{
    class Console;
}
typedef datatypes::AnyValue* (*InputParametersToAnyValueCallbackWithConsole) (
        callback_system::CallbackEngine*,
        callback_system::CallbackObject*,
        std::vector<callback_system::CallbackParameter*>&,
        console::Console*);

typedef datatypes::AnyValue* (*GetContentCallback) (
        callback_system::CallbackEngine*,
        callback_system::CallbackObject*,
        std::vector<callback_system::CallbackParameter*>&,
        uint32_t x_start,
        uint32_t y_start,
        uint32_t z_start,
        uint32_t x_size,
        uint32_t y_size,
        uint32_t z_size);

#endif
<|endoftext|>


<commit_before>/**
 * @file SquareMatrix.hpp
 *
 * A square matrix
 *
 * @author James Goppert <james.goppert@gmail.com>
 */

#pragma once

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "math.hpp"
#include "helper_functions.hpp"

namespace matrix
{

template <typename Type, size_t M, size_t N>
class Matrix;

template <typename Type, size_t M>
class Vector;

template<typename Type, size_t  M>
class SquareMatrix : public Matrix<Type, M, M>
{
public:
    SquareMatrix() :
        Matrix<Type, M, M>()
    {
    }

    SquareMatrix(const Type *data_) :
        Matrix<Type, M, M>(data_)
    {
    }

    SquareMatrix(const Matrix<Type, M, M> &other) :
        Matrix<Type, M, M>(other)
    {
    }

    // inverse alias
    inline SquareMatrix<Type, M> I() const
    {
        SquareMatrix<Type, M> i;
        if(inv(*this, i)) {
            return i;
        } else {
            i.setZero();
            return i;
        }
    }

    // inverse alias
    inline bool I(SquareMatrix<Type, M> &i) const
    {
        return inv(*this, i);
    }

    Vector<Type, M> diag() const
    {
        Vector<Type, M> res;
        const SquareMatrix<Type, M> &self = *this;

        for (size_t i = 0; i < M; i++) {
            res(i) = self(i, i);
        }
        return res;
    }

    Type trace() const
    {
        Type res = 0;
        const SquareMatrix<Type, M> &self = *this;

        for (size_t i = 0; i < M; i++) {
            res += self(i, i);
        }
        return res;
    }

};

typedef SquareMatrix<float, 3> SquareMatrix3f;

template<typename Type, size_t M>
SquareMatrix<Type, M> eye() {
    SquareMatrix<Type, M> m;
    m.setIdentity();
    return m;
}

template<typename Type, size_t M>
SquareMatrix<Type, M> diag(Vector<Type, M> d) {
    SquareMatrix<Type, M> m;
    for (size_t i=0; i<M; i++) {
        m(i,i) = d(i);
    }
    return m;
}

template<typename Type, size_t M>
SquareMatrix<Type, M> expm(const Matrix<Type, M, M> & A, size_t order=5)
{
    SquareMatrix<Type, M> res;
    SquareMatrix<Type, M> A_pow = A;
    res.setIdentity();
    size_t i_factorial = 1;
    for (size_t i=1; i<=order; i++) {
        i_factorial *= i;
        res += A_pow / Type(i_factorial);
        A_pow *= A_pow;
    }

    return res;
}

/**
 * inverse based on LU factorization with partial pivotting
 */
template<typename Type, size_t M>
bool inv(const SquareMatrix<Type, M> & A, SquareMatrix<Type, M> & inv)
{
    SquareMatrix<Type, M> L;
    L.setIdentity();
    SquareMatrix<Type, M> U = A;
    SquareMatrix<Type, M> P;
    P.setIdentity();

    //printf("A:\n"); A.print();

    // for all diagonal elements
    for (size_t n = 0; n < M; n++) {

        // if diagonal is zero, swap with row below
        if (fabsf(U(n, n)) < 1e-8f) {
            //printf("trying pivot for row %d\n",n);
            for (size_t i = n + 1; i < M; i++) {

                //printf("\ttrying row %d\n",i);
                if (fabsf(U(i, n)) > 1e-8f) {
                    //printf("swapped %d\n",i);
                    U.swapRows(i, n);
                    P.swapRows(i, n);
                    L.swapRows(i, n);
                    L.swapCols(i, n);
                    break;
                }
            }
        }

#ifdef MATRIX_ASSERT
        //printf("A:\n"); A.print();
        //printf("U:\n"); U.print();
        //printf("P:\n"); P.print();
        //fflush(stdout);
        //ASSERT(fabsf(U(n, n)) > 1e-8f);
#endif

        // failsafe, return zero matrix
        if (fabsf(U(n, n)) < 1e-8f) {
            return false;
        }

        // for all rows below diagonal
        for (size_t i = (n + 1); i < M; i++) {
            L(i, n) = U(i, n) / U(n, n);

            // add i-th row and n-th row
            // multiplied by: -a(i,n)/a(n,n)
            for (size_t k = n; k < M; k++) {
                U(i, k) -= L(i, n) * U(n, k);
            }
        }
    }

    //printf("L:\n"); L.print();
    //printf("U:\n"); U.print();

    // solve LY=P*I for Y by forward subst
    //SquareMatrix<Type, M> Y = P;

    // for all columns of Y
    for (size_t c = 0; c < M; c++) {
        // for all rows of L
        for (size_t i = 0; i < M; i++) {
            // for all columns of L
            for (size_t j = 0; j < i; j++) {
                // for all existing y
                // subtract the component they
                // contribute to the solution
                P(i, c) -= L(i, j) * P(j, c);
            }

            // divide by the factor
            // on current
            // term to be solved
            // Y(i,c) /= L(i,i);
            // but L(i,i) = 1.0
        }
    }

    //printf("Y:\n"); Y.print();

    // solve Ux=y for x by back subst
    //SquareMatrix<Type, M> X = Y;

    // for all columns of X
    for (size_t c = 0; c < M; c++) {
        // for all rows of U
        for (size_t k = 0; k < M; k++) {
            // have to go in reverse order
            size_t i = M - 1 - k;

            // for all columns of U
            for (size_t j = i + 1; j < M; j++) {
                // for all existing x
                // subtract the component they
                // contribute to the solution
                P(i, c) -= U(i, j) * P(j, c);
            }

            // divide by the factor
            // on current
            // term to be solved
            //
            // we know that U(i, i) != 0 from above
            P(i, c) /= U(i, i);
        }
    }

    //check sanity of results
    for (size_t i = 0; i < M; i++) {
        for (size_t j = 0; j < M; j++) {
            if (!is_finite(P(i,j))) {
                return false;
            }
        }
    }
    //printf("X:\n"); X.print();
    inv = P;
    return true;
}

/**
 * inverse based on LU factorization with partial pivotting
 */
template<typename Type, size_t M>
SquareMatrix<Type, M> inv(const SquareMatrix<Type, M> & A)
{
    SquareMatrix<Type, M> i;
    if(inv(A, i)) {
        return i;
    } else {
        i.setZero();
        return i;
    }
}

/**
 * cholesky decomposition
 *
 * Note: A must be positive definite
 */
template<typename Type, size_t M>
SquareMatrix <Type, M> cholesky(const SquareMatrix<Type, M> & A)
{
    SquareMatrix<Type, M> L;
    for (size_t j = 0; j < M; j++) {
        for (size_t i = j; i < M; i++) {
            if (i==j) {
                float sum = 0;
                for (size_t k = 0; k < j; k++) {
                    sum += L(j, k)*L(j, k);
                }
                Type res = A(j, j) - sum;
                if (res <= 0) {
                    L(j, j) = 0;
                } else {
                    L(j, j) = sqrtf(res);
                }
            } else {
                float sum = 0;
                for (size_t k = 0; k < j; k++) {
                    sum += L(i, k)*L(j, k);
                }
                if (L(j, j) <= 0) {
                    L(i, j) = 0;
                } else {
                    L(i, j) = (A(i, j) - sum)/L(j, j);
                }
            }
        }
    }
    return L;
}

/**
 * cholesky inverse
 *
 * TODO: Check if gaussian elimination jumps straight to back-substitution
 * for L or we need to do it manually. Will impact speed otherwise.
 */
template<typename Type, size_t M>
SquareMatrix <Type, M> choleskyInv(const SquareMatrix<Type, M> & A)
{
    SquareMatrix<Type, M> L_inv = inv(cholesky(A));
    return L_inv.T()*L_inv;
}

typedef SquareMatrix<float, 3> Matrix3f;

} // namespace matrix

/* vim: set et fenc=utf-8 ff=unix sts=0 sw=4 ts=4 : */
<commit_msg>Matrix inversion: Ensure that null check is done against the same type<commit_after>/**
 * @file SquareMatrix.hpp
 *
 * A square matrix
 *
 * @author James Goppert <james.goppert@gmail.com>
 */

#pragma once

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "math.hpp"
#include "helper_functions.hpp"

namespace matrix
{

template <typename Type, size_t M, size_t N>
class Matrix;

template <typename Type, size_t M>
class Vector;

template<typename Type, size_t  M>
class SquareMatrix : public Matrix<Type, M, M>
{
public:
    SquareMatrix() :
        Matrix<Type, M, M>()
    {
    }

    SquareMatrix(const Type *data_) :
        Matrix<Type, M, M>(data_)
    {
    }

    SquareMatrix(const Matrix<Type, M, M> &other) :
        Matrix<Type, M, M>(other)
    {
    }

    // inverse alias
    inline SquareMatrix<Type, M> I() const
    {
        SquareMatrix<Type, M> i;
        if(inv(*this, i)) {
            return i;
        } else {
            i.setZero();
            return i;
        }
    }

    // inverse alias
    inline bool I(SquareMatrix<Type, M> &i) const
    {
        return inv(*this, i);
    }

    Vector<Type, M> diag() const
    {
        Vector<Type, M> res;
        const SquareMatrix<Type, M> &self = *this;

        for (size_t i = 0; i < M; i++) {
            res(i) = self(i, i);
        }
        return res;
    }

    Type trace() const
    {
        Type res = 0;
        const SquareMatrix<Type, M> &self = *this;

        for (size_t i = 0; i < M; i++) {
            res += self(i, i);
        }
        return res;
    }

};

typedef SquareMatrix<float, 3> SquareMatrix3f;

template<typename Type, size_t M>
SquareMatrix<Type, M> eye() {
    SquareMatrix<Type, M> m;
    m.setIdentity();
    return m;
}

template<typename Type, size_t M>
SquareMatrix<Type, M> diag(Vector<Type, M> d) {
    SquareMatrix<Type, M> m;
    for (size_t i=0; i<M; i++) {
        m(i,i) = d(i);
    }
    return m;
}

template<typename Type, size_t M>
SquareMatrix<Type, M> expm(const Matrix<Type, M, M> & A, size_t order=5)
{
    SquareMatrix<Type, M> res;
    SquareMatrix<Type, M> A_pow = A;
    res.setIdentity();
    size_t i_factorial = 1;
    for (size_t i=1; i<=order; i++) {
        i_factorial *= i;
        res += A_pow / Type(i_factorial);
        A_pow *= A_pow;
    }

    return res;
}

/**
 * inverse based on LU factorization with partial pivotting
 */
template<typename Type, size_t M>
bool inv(const SquareMatrix<Type, M> & A, SquareMatrix<Type, M> & inv)
{
    SquareMatrix<Type, M> L;
    L.setIdentity();
    SquareMatrix<Type, M> U = A;
    SquareMatrix<Type, M> P;
    P.setIdentity();

    //printf("A:\n"); A.print();

    // for all diagonal elements
    for (size_t n = 0; n < M; n++) {

        // if diagonal is zero, swap with row below
        if (fabsf(static_cast<float>(U(n, n))) < 1e-8f) {
            //printf("trying pivot for row %d\n",n);
            for (size_t i = n + 1; i < M; i++) {

                //printf("\ttrying row %d\n",i);
                if (fabsf(static_cast<float>(U(i, n))) > 1e-8f) {
                    //printf("swapped %d\n",i);
                    U.swapRows(i, n);
                    P.swapRows(i, n);
                    L.swapRows(i, n);
                    L.swapCols(i, n);
                    break;
                }
            }
        }

#ifdef MATRIX_ASSERT
        //printf("A:\n"); A.print();
        //printf("U:\n"); U.print();
        //printf("P:\n"); P.print();
        //fflush(stdout);
        //ASSERT(fabsf(U(n, n)) > 1e-8f);
#endif

        // failsafe, return zero matrix
        if (fabsf(static_cast<float>(U(n, n))) < 1e-8f) {
            return false;
        }

        // for all rows below diagonal
        for (size_t i = (n + 1); i < M; i++) {
            L(i, n) = U(i, n) / U(n, n);

            // add i-th row and n-th row
            // multiplied by: -a(i,n)/a(n,n)
            for (size_t k = n; k < M; k++) {
                U(i, k) -= L(i, n) * U(n, k);
            }
        }
    }

    //printf("L:\n"); L.print();
    //printf("U:\n"); U.print();

    // solve LY=P*I for Y by forward subst
    //SquareMatrix<Type, M> Y = P;

    // for all columns of Y
    for (size_t c = 0; c < M; c++) {
        // for all rows of L
        for (size_t i = 0; i < M; i++) {
            // for all columns of L
            for (size_t j = 0; j < i; j++) {
                // for all existing y
                // subtract the component they
                // contribute to the solution
                P(i, c) -= L(i, j) * P(j, c);
            }

            // divide by the factor
            // on current
            // term to be solved
            // Y(i,c) /= L(i,i);
            // but L(i,i) = 1.0
        }
    }

    //printf("Y:\n"); Y.print();

    // solve Ux=y for x by back subst
    //SquareMatrix<Type, M> X = Y;

    // for all columns of X
    for (size_t c = 0; c < M; c++) {
        // for all rows of U
        for (size_t k = 0; k < M; k++) {
            // have to go in reverse order
            size_t i = M - 1 - k;

            // for all columns of U
            for (size_t j = i + 1; j < M; j++) {
                // for all existing x
                // subtract the component they
                // contribute to the solution
                P(i, c) -= U(i, j) * P(j, c);
            }

            // divide by the factor
            // on current
            // term to be solved
            //
            // we know that U(i, i) != 0 from above
            P(i, c) /= U(i, i);
        }
    }

    //check sanity of results
    for (size_t i = 0; i < M; i++) {
        for (size_t j = 0; j < M; j++) {
            if (!is_finite(P(i,j))) {
                return false;
            }
        }
    }
    //printf("X:\n"); X.print();
    inv = P;
    return true;
}

/**
 * inverse based on LU factorization with partial pivotting
 */
template<typename Type, size_t M>
SquareMatrix<Type, M> inv(const SquareMatrix<Type, M> & A)
{
    SquareMatrix<Type, M> i;
    if(inv(A, i)) {
        return i;
    } else {
        i.setZero();
        return i;
    }
}

/**
 * cholesky decomposition
 *
 * Note: A must be positive definite
 */
template<typename Type, size_t M>
SquareMatrix <Type, M> cholesky(const SquareMatrix<Type, M> & A)
{
    SquareMatrix<Type, M> L;
    for (size_t j = 0; j < M; j++) {
        for (size_t i = j; i < M; i++) {
            if (i==j) {
                float sum = 0;
                for (size_t k = 0; k < j; k++) {
                    sum += L(j, k)*L(j, k);
                }
                Type res = A(j, j) - sum;
                if (res <= 0) {
                    L(j, j) = 0;
                } else {
                    L(j, j) = sqrtf(res);
                }
            } else {
                float sum = 0;
                for (size_t k = 0; k < j; k++) {
                    sum += L(i, k)*L(j, k);
                }
                if (L(j, j) <= 0) {
                    L(i, j) = 0;
                } else {
                    L(i, j) = (A(i, j) - sum)/L(j, j);
                }
            }
        }
    }
    return L;
}

/**
 * cholesky inverse
 *
 * TODO: Check if gaussian elimination jumps straight to back-substitution
 * for L or we need to do it manually. Will impact speed otherwise.
 */
template<typename Type, size_t M>
SquareMatrix <Type, M> choleskyInv(const SquareMatrix<Type, M> & A)
{
    SquareMatrix<Type, M> L_inv = inv(cholesky(A));
    return L_inv.T()*L_inv;
}

typedef SquareMatrix<float, 3> Matrix3f;

} // namespace matrix

/* vim: set et fenc=utf-8 ff=unix sts=0 sw=4 ts=4 : */
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2017 gRPC authors.
 *
 * 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 <grpc/support/port_platform.h>

#include "src/core/lib/iomgr/port.h"

#ifdef GRPC_POSIX_FORK

#ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
#include <pthread.h>
#endif

#include <string.h>

#include <grpc/fork.h>
#include <grpc/grpc.h>
#include <grpc/support/log.h>

#include "src/core/lib/gprpp/fork.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/timer_manager.h"
#include "src/core/lib/iomgr/wakeup_fd_posix.h"

/*
 * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
 *       AROUND VERY SPECIFIC USE CASES.
 */

namespace {
bool skipped_handler = true;
bool registered_handlers = false;
}  // namespace

void grpc_prefork() {
  skipped_handler = true;
  // This  may be called after core shuts down, so verify initialized before
  // instantiating an ExecCtx.
  if (!grpc_is_initialized()) {
    return;
  }
  grpc_core::ExecCtx exec_ctx;
  if (!grpc_core::Fork::Enabled()) {
    gpr_log(GPR_ERROR,
            "Fork support not enabled; try running with the "
            "environment variable GRPC_ENABLE_FORK_SUPPORT=1");
    return;
  }
  const char* poll_strategy_name = grpc_get_poll_strategy_name();
  if (poll_strategy_name == nullptr ||
      (strcmp(poll_strategy_name, "epoll1") != 0 &&
       strcmp(poll_strategy_name, "poll") != 0)) {
    gpr_log(GPR_INFO,
            "Fork support is only compatible with the epoll1 and poll polling "
            "strategies");
  }
  if (!grpc_core::Fork::BlockExecCtx()) {
    gpr_log(GPR_INFO,
            "Other threads are currently calling into gRPC, skipping fork() "
            "handlers");
    return;
  }
  grpc_timer_manager_set_threading(false);
  grpc_core::Executor::SetThreadingAll(false);
  grpc_core::ExecCtx::Get()->Flush();
  grpc_core::Fork::AwaitThreads();
  skipped_handler = false;
}

void grpc_postfork_parent() {
  if (!skipped_handler) {
    grpc_core::Fork::AllowExecCtx();
    grpc_core::ExecCtx exec_ctx;
    grpc_timer_manager_set_threading(true);
    grpc_core::Executor::SetThreadingAll(true);
  }
}

void grpc_postfork_child() {
  if (!skipped_handler) {
    grpc_core::Fork::AllowExecCtx();
    grpc_core::ExecCtx exec_ctx;
    grpc_core::Fork::child_postfork_func reset_polling_engine =
        grpc_core::Fork::GetResetChildPollingEngineFunc();
    if (reset_polling_engine != nullptr) {
      reset_polling_engine();
    }
    grpc_timer_manager_set_threading(true);
    grpc_core::Executor::SetThreadingAll(true);
  }
}

void grpc_fork_handlers_auto_register() {
  if (grpc_core::Fork::Enabled() & !registered_handlers) {
#ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
    pthread_atfork(grpc_prefork, grpc_postfork_parent, grpc_postfork_child);
    registered_handlers = true;
#endif  // GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
  }
}

#endif  // GRPC_POSIX_FORK
<commit_msg>Log errors for unsupported fork scenarios in Python (#28566)<commit_after>/*
 *
 * Copyright 2017 gRPC authors.
 *
 * 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 <grpc/support/port_platform.h>

#include "src/core/lib/iomgr/port.h"

#ifdef GRPC_POSIX_FORK

#ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
#include <pthread.h>
#endif

#include <string.h>

#include <grpc/fork.h>
#include <grpc/grpc.h>
#include <grpc/support/log.h>

#include "src/core/lib/gprpp/fork.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/timer_manager.h"
#include "src/core/lib/iomgr/wakeup_fd_posix.h"

/*
 * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
 *       AROUND VERY SPECIFIC USE CASES.
 */

namespace {
bool skipped_handler = true;
bool registered_handlers = false;
}  // namespace

void grpc_prefork() {
  skipped_handler = true;
  // This  may be called after core shuts down, so verify initialized before
  // instantiating an ExecCtx.
  if (!grpc_is_initialized()) {
    return;
  }
  grpc_core::ExecCtx exec_ctx;
  if (!grpc_core::Fork::Enabled()) {
    gpr_log(GPR_ERROR,
            "Fork support not enabled; try running with the "
            "environment variable GRPC_ENABLE_FORK_SUPPORT=1");
    return;
  }
  const char* poll_strategy_name = grpc_get_poll_strategy_name();
  if (poll_strategy_name == nullptr ||
      (strcmp(poll_strategy_name, "epoll1") != 0 &&
       strcmp(poll_strategy_name, "poll") != 0)) {
    gpr_log(GPR_ERROR,
            "Fork support is only compatible with the epoll1 and poll polling "
            "strategies");
    return;
  }
  if (!grpc_core::Fork::BlockExecCtx()) {
    gpr_log(GPR_ERROR,
            "Other threads are currently calling into gRPC, skipping fork() "
            "handlers");
    return;
  }
  grpc_timer_manager_set_threading(false);
  grpc_core::Executor::SetThreadingAll(false);
  grpc_core::ExecCtx::Get()->Flush();
  grpc_core::Fork::AwaitThreads();
  skipped_handler = false;
}

void grpc_postfork_parent() {
  if (!skipped_handler) {
    grpc_core::Fork::AllowExecCtx();
    grpc_core::ExecCtx exec_ctx;
    grpc_timer_manager_set_threading(true);
    grpc_core::Executor::SetThreadingAll(true);
  }
}

void grpc_postfork_child() {
  if (!skipped_handler) {
    grpc_core::Fork::AllowExecCtx();
    grpc_core::ExecCtx exec_ctx;
    grpc_core::Fork::child_postfork_func reset_polling_engine =
        grpc_core::Fork::GetResetChildPollingEngineFunc();
    if (reset_polling_engine != nullptr) {
      reset_polling_engine();
    }
    grpc_timer_manager_set_threading(true);
    grpc_core::Executor::SetThreadingAll(true);
  }
}

void grpc_fork_handlers_auto_register() {
  if (grpc_core::Fork::Enabled() & !registered_handlers) {
#ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
    pthread_atfork(grpc_prefork, grpc_postfork_parent, grpc_postfork_child);
    registered_handlers = true;
#endif  // GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
  }
}

#endif  // GRPC_POSIX_FORK
<|endoftext|>