<commit_before>#include "solver.hpp"

#include <cstring>
#include <algorithm>

namespace CaDiCaL {

Solver::Solver ()
:
  max_var (0),
  vtab (0),
  vals (0),
  phases (0),
  wtab (0),
  unsat (false),
  level (0),
  propagated (0),
  iterating (false),
  conflict (0),
  clashing_unit (false),
  reduce_limit (0),
  restart_limit (0),
  recently_resolved (0),
  fixed_limit (0),
  reduce_inc (0),
  proof (0),
  opts (this),
  stats (this),
  solution (0),
  profiles (this),
  solver (this)
{
}

void Solver::init_variables () {
  const int max_lit = 2*max_var + 1;
  NEW (vals,   signed char, max_var + 1);
  NEW (phases, signed char, max_var + 1);
  NEW (vtab,           Var, max_var + 1);
  NEW (wtab,       Watches, max_lit + 1);
  for (int i = 1; i <= max_var; i++) vals[i] = 0;
  for (int i = 1; i <= max_var; i++) phases[i] = -1;
  queue.init (this);
  MSG ("initialized %d variables", max_var);
  control.push_back (Level (0));
}

Solver::~Solver () {
  for (size_t i = 0; i < clauses.size (); i++)
    delete_clause (clauses[i]);
  if (proof) delete proof;
  if (wtab) delete [] wtab;
  if (vtab) delete [] vtab;
  if (vals) delete [] vals;
  if (phases) delete [] phases;
  if (solution) delete [] solution;
}

/*------------------------------------------------------------------------*/

int Solver::search () {
  int res = 0;
  START (search);
  while (!res)
         if (unsat) res = 20;
    else if (!propagate ()) analyze ();
    else if (iterating) iterate ();
    else if (satisfied ()) res = 10;
    else if (restarting ()) restart ();
    else if (reducing ()) reduce ();
    else decide ();
  STOP (search);
  return res;
}

/*------------------------------------------------------------------------*/

void Solver::init_solving () {
  restart_limit = opts.restartint;
  reduce_limit = reduce_inc = opts.reduceinit;
  INIT_EMA (fast_glue_avg, opts.emagluefast);
  INIT_EMA (slow_glue_avg, opts.emaglueslow);
}

int Solver::solve () {
  init_solving ();
  SECTION ("solving");
  if (clashing_unit) { learn_empty_clause (); return 20; }
  else return search ();
}

};
<commit_msg>removed redundant include<commit_after>#include "solver.hpp"

namespace CaDiCaL {

Solver::Solver ()
:
  max_var (0),
  vtab (0),
  vals (0),
  phases (0),
  wtab (0),
  unsat (false),
  level (0),
  propagated (0),
  iterating (false),
  conflict (0),
  clashing_unit (false),
  reduce_limit (0),
  restart_limit (0),
  recently_resolved (0),
  fixed_limit (0),
  reduce_inc (0),
  proof (0),
  opts (this),
  stats (this),
  solution (0),
  profiles (this),
  solver (this)
{
}

void Solver::init_variables () {
  const int max_lit = 2*max_var + 1;
  NEW (vals,   signed char, max_var + 1);
  NEW (phases, signed char, max_var + 1);
  NEW (vtab,           Var, max_var + 1);
  NEW (wtab,       Watches, max_lit + 1);
  for (int i = 1; i <= max_var; i++) vals[i] = 0;
  for (int i = 1; i <= max_var; i++) phases[i] = -1;
  queue.init (this);
  MSG ("initialized %d variables", max_var);
  control.push_back (Level (0));
}

Solver::~Solver () {
  for (size_t i = 0; i < clauses.size (); i++)
    delete_clause (clauses[i]);
  if (proof) delete proof;
  if (wtab) delete [] wtab;
  if (vtab) delete [] vtab;
  if (vals) delete [] vals;
  if (phases) delete [] phases;
  if (solution) delete [] solution;
}

/*------------------------------------------------------------------------*/

int Solver::search () {
  int res = 0;
  START (search);
  while (!res)
         if (unsat) res = 20;
    else if (!propagate ()) analyze ();
    else if (iterating) iterate ();
    else if (satisfied ()) res = 10;
    else if (restarting ()) restart ();
    else if (reducing ()) reduce ();
    else decide ();
  STOP (search);
  return res;
}

/*------------------------------------------------------------------------*/

void Solver::init_solving () {
  restart_limit = opts.restartint;
  reduce_limit = reduce_inc = opts.reduceinit;
  INIT_EMA (fast_glue_avg, opts.emagluefast);
  INIT_EMA (slow_glue_avg, opts.emaglueslow);
}

int Solver::solve () {
  init_solving ();
  SECTION ("solving");
  if (clashing_unit) { learn_empty_clause (); return 20; }
  else return search ();
}

};
<|endoftext|>


<commit_before>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.

#include "source.h"
#include "option.h"
#include "environment.h"

namespace librealsense
{
    class frame_queue_size : public option_base
    {
    public:
        frame_queue_size(std::atomic<uint32_t>* ptr, const option_range& opt_range)
            : option_base(opt_range),
              _ptr(ptr)
        {}

        void set(float value) override
        {
            if (!is_valid(value))
                throw invalid_value_exception(to_string() << "set(frame_queue_size) failed! Given value " << value << " is out of range.");

            *_ptr = static_cast<uint32_t>(value);
            _recording_function(*this);
        }

        float query() const override { return static_cast<float>(_ptr->load()); }

        bool is_enabled() const override { return true; }

        const char* get_description() const override
        {
            return "Max number of frames you can hold at a given time. Increasing this number will reduce frame drops but increase latency, and vice versa";
        }
    private:
        std::atomic<uint32_t>* _ptr;
    };

    std::shared_ptr<option> frame_source::get_published_size_option()
    {
        return std::make_shared<frame_queue_size>(&_max_publish_list_size, option_range{ 0, 32, 1, 16 });
    }

    frame_source::frame_source(uint32_t max_publish_list_size)
            : _callback(nullptr, [](rs2_frame_callback*) {}),
              _max_publish_list_size(max_publish_list_size),
              _ts(environment::get_instance().get_time_service())
    {}

    void frame_source::init(std::shared_ptr<metadata_parser_map> metadata_parsers)
    {
        std::lock_guard<std::mutex> lock(_callback_mutex);

        std::vector<rs2_extension> supported { RS2_EXTENSION_VIDEO_FRAME,
                                               RS2_EXTENSION_COMPOSITE_FRAME,
                                               RS2_EXTENSION_POINTS,
                                               RS2_EXTENSION_DEPTH_FRAME,
                                               RS2_EXTENSION_DISPARITY_FRAME,
                                               RS2_EXTENSION_MOTION_FRAME,
                                               RS2_EXTENSION_POSE_FRAME };

        for (auto type : supported)
        {
            _archive[type] = make_archive(type, &_max_publish_list_size, _ts, metadata_parsers);
        }

        _metadata_parsers = metadata_parsers;
    }

    callback_invocation_holder frame_source::begin_callback()
    {
        return _archive[RS2_EXTENSION_VIDEO_FRAME]->begin_callback();
//        return _archive[RS2_EXTENSION_DEPTH_FRAME]->begin_callback();
    }

    void frame_source::reset()
    {
        std::lock_guard<std::mutex> lock(_callback_mutex);
        _callback.reset();
        for (auto&& kvp : _archive)
        {
            kvp.second.reset();
        }
        _metadata_parsers.reset();
    }

    frame_interface* frame_source::alloc_frame(rs2_extension type, size_t size, frame_additional_data additional_data, bool requires_memory) const
    {
        auto it = _archive.find(type);
        if (it == _archive.end()) throw wrong_api_call_sequence_exception("Requested frame type is not supported!");
        return it->second->alloc_and_track(size, additional_data, requires_memory);
    }

    void frame_source::set_sensor(const std::shared_ptr<sensor_interface>& s)
    {
        for (auto&& a : _archive)
        {
            a.second->set_sensor(s);
        }
    }

    void frame_source::set_callback(frame_callback_ptr callback)
    {
        std::lock_guard<std::mutex> lock(_callback_mutex);
        _callback = callback;
    }

    frame_callback_ptr frame_source::get_callback() const
    {
        std::lock_guard<std::mutex> lock(_callback_mutex);
        return _callback;
    }
    void frame_source::invoke_callback(frame_holder frame) const
    {
        if (frame)
        {
            auto callback = frame.frame->get_owner()->begin_callback();
            try
            {
                frame->log_callback_start(_ts ? _ts->get_time() : 0);
                if (_callback)
                {
                    frame_interface* ref = nullptr;
                    std::swap(frame.frame, ref);
                    _callback->on_frame((rs2_frame*)ref);
                }
            }
            catch(...)
            {
                LOG_ERROR("Exception was thrown during user callback!");
            }
        }
    }

    void frame_source::flush() const
    {
        for (auto&& kvp : _archive)
        {
            if (kvp.second)
                kvp.second->flush();
        }
    }
}

<commit_msg>Add additional exception handler information<commit_after>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.

#include "source.h"
#include "option.h"
#include "environment.h"

namespace librealsense
{
    class frame_queue_size : public option_base
    {
    public:
        frame_queue_size(std::atomic<uint32_t>* ptr, const option_range& opt_range)
            : option_base(opt_range),
              _ptr(ptr)
        {}

        void set(float value) override
        {
            if (!is_valid(value))
                throw invalid_value_exception(to_string() << "set(frame_queue_size) failed! Given value " << value << " is out of range.");

            *_ptr = static_cast<uint32_t>(value);
            _recording_function(*this);
        }

        float query() const override { return static_cast<float>(_ptr->load()); }

        bool is_enabled() const override { return true; }

        const char* get_description() const override
        {
            return "Max number of frames you can hold at a given time. Increasing this number will reduce frame drops but increase latency, and vice versa";
        }
    private:
        std::atomic<uint32_t>* _ptr;
    };

    std::shared_ptr<option> frame_source::get_published_size_option()
    {
        return std::make_shared<frame_queue_size>(&_max_publish_list_size, option_range{ 0, 32, 1, 16 });
    }

    frame_source::frame_source(uint32_t max_publish_list_size)
            : _callback(nullptr, [](rs2_frame_callback*) {}),
              _max_publish_list_size(max_publish_list_size),
              _ts(environment::get_instance().get_time_service())
    {}

    void frame_source::init(std::shared_ptr<metadata_parser_map> metadata_parsers)
    {
        std::lock_guard<std::mutex> lock(_callback_mutex);

        std::vector<rs2_extension> supported { RS2_EXTENSION_VIDEO_FRAME,
                                               RS2_EXTENSION_COMPOSITE_FRAME,
                                               RS2_EXTENSION_POINTS,
                                               RS2_EXTENSION_DEPTH_FRAME,
                                               RS2_EXTENSION_DISPARITY_FRAME,
                                               RS2_EXTENSION_MOTION_FRAME,
                                               RS2_EXTENSION_POSE_FRAME };

        for (auto type : supported)
        {
            _archive[type] = make_archive(type, &_max_publish_list_size, _ts, metadata_parsers);
        }

        _metadata_parsers = metadata_parsers;
    }

    callback_invocation_holder frame_source::begin_callback()
    {
        return _archive[RS2_EXTENSION_VIDEO_FRAME]->begin_callback();
//        return _archive[RS2_EXTENSION_DEPTH_FRAME]->begin_callback();
    }

    void frame_source::reset()
    {
        std::lock_guard<std::mutex> lock(_callback_mutex);
        _callback.reset();
        for (auto&& kvp : _archive)
        {
            kvp.second.reset();
        }
        _metadata_parsers.reset();
    }

    frame_interface* frame_source::alloc_frame(rs2_extension type, size_t size, frame_additional_data additional_data, bool requires_memory) const
    {
        auto it = _archive.find(type);
        if (it == _archive.end()) throw wrong_api_call_sequence_exception("Requested frame type is not supported!");
        return it->second->alloc_and_track(size, additional_data, requires_memory);
    }

    void frame_source::set_sensor(const std::shared_ptr<sensor_interface>& s)
    {
        for (auto&& a : _archive)
        {
            a.second->set_sensor(s);
        }
    }

    void frame_source::set_callback(frame_callback_ptr callback)
    {
        std::lock_guard<std::mutex> lock(_callback_mutex);
        _callback = callback;
    }

    frame_callback_ptr frame_source::get_callback() const
    {
        std::lock_guard<std::mutex> lock(_callback_mutex);
        return _callback;
    }
    void frame_source::invoke_callback(frame_holder frame) const
    {
        if (frame)
        {
            auto callback = frame.frame->get_owner()->begin_callback();
            try
            {
                frame->log_callback_start(_ts ? _ts->get_time() : 0);
                if (_callback)
                {
                    frame_interface* ref = nullptr;
                    std::swap(frame.frame, ref);
                    _callback->on_frame((rs2_frame*)ref);
                }
            }
            catch( const std::exception & e )
            {
                LOG_ERROR( "Exception was thrown during user callback: " + std::string( e.what() ));
            }
            catch(...)
            {
                LOG_ERROR("Exception was thrown during user callback!");
            }
        }
    }

    void frame_source::flush() const
    {
        for (auto&& kvp : _archive)
        {
            if (kvp.second)
                kvp.second->flush();
        }
    }
}

<|endoftext|>


<commit_before>#include "openmc/source.h"

#include <algorithm> // for move
#include <sstream> // for stringstream

#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
#include <dlfcn.h> // for dlopen
#endif

#include <fmt/core.h>
#include "xtensor/xadapt.hpp"

#include "openmc/bank.h"
#include "openmc/cell.h"
#include "openmc/error.h"
#include "openmc/file_utils.h"
#include "openmc/hdf5_interface.h"
#include "openmc/material.h"
#include "openmc/message_passing.h"
#include "openmc/mgxs_interface.h"
#include "openmc/nuclide.h"
#include "openmc/capi.h"
#include "openmc/random_lcg.h"
#include "openmc/search.h"
#include "openmc/settings.h"
#include "openmc/simulation.h"
#include "openmc/state_point.h"
#include "openmc/xml_interface.h"

namespace openmc {

//==============================================================================
// Global variables
//==============================================================================

namespace model {

std::vector<SourceDistribution> external_sources;

}

//==============================================================================
// SourceDistribution implementation
//==============================================================================

SourceDistribution::SourceDistribution(UPtrSpace space, UPtrAngle angle, UPtrDist energy)
  : space_{std::move(space)}, angle_{std::move(angle)}, energy_{std::move(energy)} { }

SourceDistribution::SourceDistribution(pugi::xml_node node)
{
  // Check for particle type
  if (check_for_node(node, "particle")) {
    auto temp_str = get_node_value(node, "particle", true, true);
    if (temp_str == "neutron") {
      particle_ = Particle::Type::neutron;
    } else if (temp_str == "photon") {
      particle_ = Particle::Type::photon;
      settings::photon_transport = true;
    } else {
      fatal_error(std::string("Unknown source particle type: ") + temp_str);
    }
  }

  // Check for source strength
  if (check_for_node(node, "strength")) {
    strength_ = std::stod(get_node_value(node, "strength"));
  }

  // Check for external source file
  if (check_for_node(node, "file")) {
    // Copy path of source file
    settings::path_source = get_node_value(node, "file", false, true);

    // Check if source file exists
    if (!file_exists(settings::path_source)) {
      fatal_error(fmt::format("Source file '{}' does not exist.",
        settings::path_source));
    }
  } else if (check_for_node(node, "library")) {
     settings::path_source_library = get_node_value(node, "library", false, true);
     // check if it exists
     if (!file_exists(settings::path_source_library)) {
      	std::stringstream msg;
      	msg << "Library file " << settings::path_source_library << "' does not exist.";
	      fatal_error(msg);
     }
  } else {

    // Spatial distribution for external source
    if (check_for_node(node, "space")) {
      // Get pointer to spatial distribution
      pugi::xml_node node_space = node.child("space");

      // Check for type of spatial distribution and read
      std::string type;
      if (check_for_node(node_space, "type"))
        type = get_node_value(node_space, "type", true, true);
      if (type == "cartesian") {
        space_ = UPtrSpace{new CartesianIndependent(node_space)};
      } else if (type == "cylindrical") {
        space_ = UPtrSpace{new CylindricalIndependent(node_space)};
      } else if (type == "spherical") {
        space_ = UPtrSpace{new SphericalIndependent(node_space)};
      } else if (type == "box") {
        space_ = UPtrSpace{new SpatialBox(node_space)};
      } else if (type == "fission") {
        space_ = UPtrSpace{new SpatialBox(node_space, true)};
      } else if (type == "point") {
        space_ = UPtrSpace{new SpatialPoint(node_space)};
      } else {
        fatal_error(fmt::format(
          "Invalid spatial distribution for external source: {}", type));
      }

    } else {
      // If no spatial distribution specified, make it a point source
      space_ = UPtrSpace{new SpatialPoint()};
    }

    // Determine external source angular distribution
    if (check_for_node(node, "angle")) {
      // Get pointer to angular distribution
      pugi::xml_node node_angle = node.child("angle");

      // Check for type of angular distribution
      std::string type;
      if (check_for_node(node_angle, "type"))
        type = get_node_value(node_angle, "type", true, true);
      if (type == "isotropic") {
        angle_ = UPtrAngle{new Isotropic()};
      } else if (type == "monodirectional") {
        angle_ = UPtrAngle{new Monodirectional(node_angle)};
      } else if (type == "mu-phi") {
        angle_ = UPtrAngle{new PolarAzimuthal(node_angle)};
      } else {
        fatal_error(fmt::format(
          "Invalid angular distribution for external source: {}", type));
      }

    } else {
      angle_ = UPtrAngle{new Isotropic()};
    }

    // Determine external source energy distribution
    if (check_for_node(node, "energy")) {
      pugi::xml_node node_dist = node.child("energy");
      energy_ = distribution_from_xml(node_dist);
    } else {
      // Default to a Watt spectrum with parameters 0.988 MeV and 2.249 MeV^-1
      energy_ = UPtrDist{new Watt(0.988e6, 2.249e-6)};
    }
  }
}

Particle::Bank SourceDistribution::sample(uint64_t* seed) const
{
  Particle::Bank site;

  // Set weight to one by default
  site.wgt = 1.0;

  // Repeat sampling source location until a good site has been found
  bool found = false;
  int n_reject = 0;
  static int n_accept = 0;
  while (!found) {
    // Set particle type
    site.particle = particle_;

    // Sample spatial distribution
    site.r = space_->sample(seed);
    double xyz[] {site.r.x, site.r.y, site.r.z};

    // Now search to see if location exists in geometry
    int32_t cell_index, instance;
    int err = openmc_find_cell(xyz, &cell_index, &instance);
    found = (err != OPENMC_E_GEOMETRY);

    // Check if spatial site is in fissionable material
    if (found) {
      auto space_box = dynamic_cast<SpatialBox*>(space_.get());
      if (space_box) {
        if (space_box->only_fissionable()) {
          // Determine material
          const auto& c = model::cells[cell_index];
          auto mat_index = c->material_.size() == 1
            ? c->material_[0] : c->material_[instance];

          if (mat_index == MATERIAL_VOID) {
            found = false;
          } else {
            if (!model::materials[mat_index]->fissionable_) found = false;
          }
        }
      }
    }

    // Check for rejection
    if (!found) {
      ++n_reject;
      if (n_reject >= EXTSRC_REJECT_THRESHOLD &&
          static_cast<double>(n_accept)/n_reject <= EXTSRC_REJECT_FRACTION) {
        fatal_error("More than 95% of external source sites sampled were "
                    "rejected. Please check your external source definition.");
      }
    }
  }

  // Increment number of accepted samples
  ++n_accept;

  // Sample angle
  site.u = angle_->sample(seed);

  // Check for monoenergetic source above maximum particle energy
  auto p = static_cast<int>(particle_);
  auto energy_ptr = dynamic_cast<Discrete*>(energy_.get());
  if (energy_ptr) {
    auto energies = xt::adapt(energy_ptr->x());
    if (xt::any(energies > data::energy_max[p])) {
      fatal_error("Source energy above range of energies of at least "
                  "one cross section table");
    } else if (xt::any(energies < data::energy_min[p])) {
      fatal_error("Source energy below range of energies of at least "
                  "one cross section table");
    }
  }

  while (true) {
    // Sample energy spectrum
    site.E = energy_->sample(seed);

    // Resample if energy falls outside minimum or maximum particle energy
    if (site.E < data::energy_max[p] && site.E > data::energy_min[p]) break;
  }

  // Set delayed group
  site.delayed_group = 0;

  return site;
}

//==============================================================================
// Non-member functions
//==============================================================================

void initialize_source()
{
  write_message("Initializing source particles...", 5);

  if (settings::path_source != "") {
    // Read the source from a binary file instead of sampling from some
    // assumed source distribution

    write_message(fmt::format("Reading source file from {}...",
      settings::path_source), 6);

    // Open the binary file
    hid_t file_id = file_open(settings::path_source, 'r', true);

    // Read the file type
    std::string filetype;
    read_attribute(file_id, "filetype", filetype);

    // Check to make sure this is a source file
    if (filetype != "source" && filetype != "statepoint") {
      fatal_error("Specified starting source file not a source file type.");
    }

    // Read in the source bank
    read_source_bank(file_id);

    // Close file
    file_close(file_id);
  } else if ( settings::path_source_library != "" ) {
    // Get the source from a library object

    std::stringstream msg;
    msg << "Sampling from library source " << settings::path_source << "...";
    write_message(msg, 6);

    #if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
    // Open the library
    void* source_library = dlopen(settings::path_source_library.c_str(),RTLD_LAZY);
    if(!source_library) {
      std::stringstream msg("Couldnt open source library " + settings::path_source_library);
      fatal_error(msg);
    }
    #else
    std::stringstream msg("This feature has not yet been implemented for non POSIX systems");
    fatal_error(msg);
    #endif

    // load the symbol
    typedef Particle::Bank (*sample_t)();

    // reset errors
    dlerror();

    // get the function from the library
    sample_t sample_source = (sample_t) dlsym(source_library, "sample_source");
    const char *dlsym_error = dlerror();

    // check for any dlsym errors
    if (dlsym_error) {
      std::cout << dlsym_error << std::endl;
      dlclose(source_library);
      fatal_error("Couldnt open the sample_source symbol");
    }

    // Generation source sites from specified distribution in the
    // library source
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = simulation::total_gen*settings::n_particles +
        simulation::work_index[mpi::rank] + i + 1;
      set_particle_seed(id);

      // sample external source distribution
      simulation::source_bank[i] = sample_source();
    }
    // release the library
    dlclose(source_library);

  } else {
    // Generation source sites from specified distribution in user input
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = simulation::total_gen*settings::n_particles +
        simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_external_source(&seed);
    }
  }

  // Write out initial source
  if (settings::write_initial_source) {
    write_message("Writing out initial source...", 5);
    std::string filename = settings::path_output + "initial_source.h5";
    hid_t file_id = file_open(filename, 'w', true);
    write_source_bank(file_id);
    file_close(file_id);
  }
}

Particle::Bank sample_external_source(uint64_t* seed)
{
  // Determine total source strength
  double total_strength = 0.0;
  for (auto& s : model::external_sources)
    total_strength += s.strength();

  // Sample from among multiple source distributions
  int i = 0;
  if (model::external_sources.size() > 1) {
    double xi = prn(seed)*total_strength;
    double c = 0.0;
    for (; i < model::external_sources.size(); ++i) {
      c += model::external_sources[i].strength();
      if (xi < c) break;
    }
  }

  // Sample source site from i-th source distribution
  Particle::Bank site {model::external_sources[i].sample(seed)};

  // If running in MG, convert site.E to group
  if (!settings::run_CE) {
    site.E = lower_bound_index(data::mg.rev_energy_bins_.begin(),
      data::mg.rev_energy_bins_.end(), site.E);
    site.E = data::mg.num_energy_groups_ - site.E - 1.;
  }

  return site;
}

void free_memory_source()
{
  model::external_sources.clear();
}

void fill_source_bank_fixedsource()
{
  if (settings::path_source.empty() && settings::path_source_library.empty()) {
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = (simulation::total_gen + overall_generation()) *
        settings::n_particles + simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_external_source(&seed);
    }
  } else if (settings::path_source.empty() && !settings::path_source.empty()) {
     std::stringstream msg;

    // Open the library
    void* source_library = dlopen(settings::path_source_library.c_str(),RTLD_LAZY);
    if(!source_library) {
      std::stringstream msg("Couldnt open source library " + settings::path_source_library);
      fatal_error(msg);
    }

    // load the symbol
    typedef Particle::Bank (*sample_t)();

    // reset errors
    dlerror();

    // get the function from the library
    sample_t sample_source = (sample_t) dlsym(source_library, "sample_source");
    const char *dlsym_error = dlerror();

    // check for any dlsym errors
    if (dlsym_error) {
      std::cout << dlsym_error << std::endl;
      dlclose(source_library);
      fatal_error("Couldnt open the sample_source symbol");
    }

    // Generation source sites from specified distribution in the
    // library source
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = simulation::total_gen*settings::n_particles +
        simulation::work_index[mpi::rank] + i + 1;
      set_particle_seed(id);

      // sample external source distribution
      simulation::source_bank[i] = sample_source();
    }

    // release the library
    dlclose(source_library);
  }
}

} // namespace openmc
<commit_msg>updated signatures according to new changes in how seed is set<commit_after>#include "openmc/source.h"

#include <algorithm> // for move
#include <sstream> // for stringstream

#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
#include <dlfcn.h> // for dlopen
#endif

#include <fmt/core.h>
#include "xtensor/xadapt.hpp"

#include "openmc/bank.h"
#include "openmc/cell.h"
#include "openmc/error.h"
#include "openmc/file_utils.h"
#include "openmc/hdf5_interface.h"
#include "openmc/material.h"
#include "openmc/message_passing.h"
#include "openmc/mgxs_interface.h"
#include "openmc/nuclide.h"
#include "openmc/capi.h"
#include "openmc/random_lcg.h"
#include "openmc/search.h"
#include "openmc/settings.h"
#include "openmc/simulation.h"
#include "openmc/state_point.h"
#include "openmc/xml_interface.h"

namespace openmc {

//==============================================================================
// Global variables
//==============================================================================

namespace model {

std::vector<SourceDistribution> external_sources;

}

//==============================================================================
// SourceDistribution implementation
//==============================================================================

SourceDistribution::SourceDistribution(UPtrSpace space, UPtrAngle angle, UPtrDist energy)
  : space_{std::move(space)}, angle_{std::move(angle)}, energy_{std::move(energy)} { }

SourceDistribution::SourceDistribution(pugi::xml_node node)
{
  // Check for particle type
  if (check_for_node(node, "particle")) {
    auto temp_str = get_node_value(node, "particle", true, true);
    if (temp_str == "neutron") {
      particle_ = Particle::Type::neutron;
    } else if (temp_str == "photon") {
      particle_ = Particle::Type::photon;
      settings::photon_transport = true;
    } else {
      fatal_error(std::string("Unknown source particle type: ") + temp_str);
    }
  }

  // Check for source strength
  if (check_for_node(node, "strength")) {
    strength_ = std::stod(get_node_value(node, "strength"));
  }

  // Check for external source file
  if (check_for_node(node, "file")) {
    // Copy path of source file
    settings::path_source = get_node_value(node, "file", false, true);

    // Check if source file exists
    if (!file_exists(settings::path_source)) {
      fatal_error(fmt::format("Source file '{}' does not exist.",
        settings::path_source));
    }
  } else if (check_for_node(node, "library")) {
     settings::path_source_library = get_node_value(node, "library", false, true);
     // check if it exists
     if (!file_exists(settings::path_source_library)) {
      	std::stringstream msg;
      	msg << "Library file " << settings::path_source_library << "' does not exist.";
	      fatal_error(msg);
     }
  } else {

    // Spatial distribution for external source
    if (check_for_node(node, "space")) {
      // Get pointer to spatial distribution
      pugi::xml_node node_space = node.child("space");

      // Check for type of spatial distribution and read
      std::string type;
      if (check_for_node(node_space, "type"))
        type = get_node_value(node_space, "type", true, true);
      if (type == "cartesian") {
        space_ = UPtrSpace{new CartesianIndependent(node_space)};
      } else if (type == "cylindrical") {
        space_ = UPtrSpace{new CylindricalIndependent(node_space)};
      } else if (type == "spherical") {
        space_ = UPtrSpace{new SphericalIndependent(node_space)};
      } else if (type == "box") {
        space_ = UPtrSpace{new SpatialBox(node_space)};
      } else if (type == "fission") {
        space_ = UPtrSpace{new SpatialBox(node_space, true)};
      } else if (type == "point") {
        space_ = UPtrSpace{new SpatialPoint(node_space)};
      } else {
        fatal_error(fmt::format(
          "Invalid spatial distribution for external source: {}", type));
      }

    } else {
      // If no spatial distribution specified, make it a point source
      space_ = UPtrSpace{new SpatialPoint()};
    }

    // Determine external source angular distribution
    if (check_for_node(node, "angle")) {
      // Get pointer to angular distribution
      pugi::xml_node node_angle = node.child("angle");

      // Check for type of angular distribution
      std::string type;
      if (check_for_node(node_angle, "type"))
        type = get_node_value(node_angle, "type", true, true);
      if (type == "isotropic") {
        angle_ = UPtrAngle{new Isotropic()};
      } else if (type == "monodirectional") {
        angle_ = UPtrAngle{new Monodirectional(node_angle)};
      } else if (type == "mu-phi") {
        angle_ = UPtrAngle{new PolarAzimuthal(node_angle)};
      } else {
        fatal_error(fmt::format(
          "Invalid angular distribution for external source: {}", type));
      }

    } else {
      angle_ = UPtrAngle{new Isotropic()};
    }

    // Determine external source energy distribution
    if (check_for_node(node, "energy")) {
      pugi::xml_node node_dist = node.child("energy");
      energy_ = distribution_from_xml(node_dist);
    } else {
      // Default to a Watt spectrum with parameters 0.988 MeV and 2.249 MeV^-1
      energy_ = UPtrDist{new Watt(0.988e6, 2.249e-6)};
    }
  }
}

Particle::Bank SourceDistribution::sample(uint64_t* seed) const
{
  Particle::Bank site;

  // Set weight to one by default
  site.wgt = 1.0;

  // Repeat sampling source location until a good site has been found
  bool found = false;
  int n_reject = 0;
  static int n_accept = 0;
  while (!found) {
    // Set particle type
    site.particle = particle_;

    // Sample spatial distribution
    site.r = space_->sample(seed);
    double xyz[] {site.r.x, site.r.y, site.r.z};

    // Now search to see if location exists in geometry
    int32_t cell_index, instance;
    int err = openmc_find_cell(xyz, &cell_index, &instance);
    found = (err != OPENMC_E_GEOMETRY);

    // Check if spatial site is in fissionable material
    if (found) {
      auto space_box = dynamic_cast<SpatialBox*>(space_.get());
      if (space_box) {
        if (space_box->only_fissionable()) {
          // Determine material
          const auto& c = model::cells[cell_index];
          auto mat_index = c->material_.size() == 1
            ? c->material_[0] : c->material_[instance];

          if (mat_index == MATERIAL_VOID) {
            found = false;
          } else {
            if (!model::materials[mat_index]->fissionable_) found = false;
          }
        }
      }
    }

    // Check for rejection
    if (!found) {
      ++n_reject;
      if (n_reject >= EXTSRC_REJECT_THRESHOLD &&
          static_cast<double>(n_accept)/n_reject <= EXTSRC_REJECT_FRACTION) {
        fatal_error("More than 95% of external source sites sampled were "
                    "rejected. Please check your external source definition.");
      }
    }
  }

  // Increment number of accepted samples
  ++n_accept;

  // Sample angle
  site.u = angle_->sample(seed);

  // Check for monoenergetic source above maximum particle energy
  auto p = static_cast<int>(particle_);
  auto energy_ptr = dynamic_cast<Discrete*>(energy_.get());
  if (energy_ptr) {
    auto energies = xt::adapt(energy_ptr->x());
    if (xt::any(energies > data::energy_max[p])) {
      fatal_error("Source energy above range of energies of at least "
                  "one cross section table");
    } else if (xt::any(energies < data::energy_min[p])) {
      fatal_error("Source energy below range of energies of at least "
                  "one cross section table");
    }
  }

  while (true) {
    // Sample energy spectrum
    site.E = energy_->sample(seed);

    // Resample if energy falls outside minimum or maximum particle energy
    if (site.E < data::energy_max[p] && site.E > data::energy_min[p]) break;
  }

  // Set delayed group
  site.delayed_group = 0;

  return site;
}

//==============================================================================
// Non-member functions
//==============================================================================

void initialize_source()
{
  write_message("Initializing source particles...", 5);

  if (settings::path_source != "") {
    // Read the source from a binary file instead of sampling from some
    // assumed source distribution

    write_message(fmt::format("Reading source file from {}...",
      settings::path_source), 6);

    // Open the binary file
    hid_t file_id = file_open(settings::path_source, 'r', true);

    // Read the file type
    std::string filetype;
    read_attribute(file_id, "filetype", filetype);

    // Check to make sure this is a source file
    if (filetype != "source" && filetype != "statepoint") {
      fatal_error("Specified starting source file not a source file type.");
    }

    // Read in the source bank
    read_source_bank(file_id);

    // Close file
    file_close(file_id);
  } else if ( settings::path_source_library != "" ) {
    // Get the source from a library object

    std::stringstream msg;
    msg << "Sampling from library source " << settings::path_source << "...";
    write_message(msg, 6);

    #if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
    // Open the library
    void* source_library = dlopen(settings::path_source_library.c_str(),RTLD_LAZY);
    if(!source_library) {
      std::stringstream msg("Couldnt open source library " + settings::path_source_library);
      fatal_error(msg);
    }
    #else
    std::stringstream msg("This feature has not yet been implemented for non POSIX systems");
    fatal_error(msg);
    #endif

    // load the symbol
    typedef Particle::Bank (*sample_t)(uint64_t *seed);

    // reset errors
    dlerror();

    // get the function from the library
    sample_t sample_source = (sample_t) dlsym(source_library, "sample_source");
    const char *dlsym_error = dlerror();

    // check for any dlsym errors
    if (dlsym_error) {
      std::cout << dlsym_error << std::endl;
      dlclose(source_library);
      fatal_error("Couldnt open the sample_source symbol");
    }

    // Generation source sites from specified distribution in the
    // library source
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = simulation::total_gen*settings::n_particles +
        simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_source(&seed);
    }
    // release the library
    dlclose(source_library);

  } else {
    // Generation source sites from specified distribution in user input
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = simulation::total_gen*settings::n_particles +
        simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_external_source(&seed);
    }
  }

  // Write out initial source
  if (settings::write_initial_source) {
    write_message("Writing out initial source...", 5);
    std::string filename = settings::path_output + "initial_source.h5";
    hid_t file_id = file_open(filename, 'w', true);
    write_source_bank(file_id);
    file_close(file_id);
  }
}

Particle::Bank sample_external_source(uint64_t* seed)
{
  // Determine total source strength
  double total_strength = 0.0;
  for (auto& s : model::external_sources)
    total_strength += s.strength();

  // Sample from among multiple source distributions
  int i = 0;
  if (model::external_sources.size() > 1) {
    double xi = prn(seed)*total_strength;
    double c = 0.0;
    for (; i < model::external_sources.size(); ++i) {
      c += model::external_sources[i].strength();
      if (xi < c) break;
    }
  }

  // Sample source site from i-th source distribution
  Particle::Bank site {model::external_sources[i].sample(seed)};

  // If running in MG, convert site.E to group
  if (!settings::run_CE) {
    site.E = lower_bound_index(data::mg.rev_energy_bins_.begin(),
      data::mg.rev_energy_bins_.end(), site.E);
    site.E = data::mg.num_energy_groups_ - site.E - 1.;
  }

  return site;
}

void free_memory_source()
{
  model::external_sources.clear();
}

void fill_source_bank_fixedsource()
{
  if (settings::path_source.empty() && settings::path_source_library.empty()) {
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = (simulation::total_gen + overall_generation()) *
        settings::n_particles + simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_external_source(&seed);
    }
  } else if (settings::path_source.empty() && !settings::path_source.empty()) {
     std::stringstream msg;

    // Open the library
    void* source_library = dlopen(settings::path_source_library.c_str(),RTLD_LAZY);
    if(!source_library) {
      std::stringstream msg("Couldnt open source library " + settings::path_source_library);
      fatal_error(msg);
    }

    // load the symbol
    typedef Particle::Bank (*sample_t)(uint64_t *seed);

    // reset errors
    dlerror();

    // get the function from the library
    sample_t sample_source = (sample_t) dlsym(source_library, "sample_source");
    const char *dlsym_error = dlerror();

    // check for any dlsym errors
    if (dlsym_error) {
      std::cout << dlsym_error << std::endl;
      dlclose(source_library);
      fatal_error("Couldnt open the sample_source symbol");
    }

    // Generation source sites from specified distribution in the
    // library source
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = simulation::total_gen*settings::n_particles +
        simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_source(&seed);
    }

    // release the library
    dlclose(source_library);
  }
}

} // namespace openmc
<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.

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 "paddle/fluid/operators/controlflow/logical_op.h"
#include <string>
#include "paddle/fluid/framework/op_registry.h"

namespace paddle {
namespace operators {
template <typename OpComment>
class BinaryLogicalOpProtoMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    OpComment comment;
    AddInput("X",
             string::Sprintf("(LoDTensor) Left hand operand of %s operator",
                             comment.type));
    AddInput("Y",
             string::Sprintf("(LoDTensor) Right hand operand of %s operator",
                             comment.type));
    AddOutput("Out", string::Sprintf(
                         "(LoDTensor) n-dim bool tensor. Each element is %s",
                         comment.equation));
    AddComment(string::Sprintf(R"DOC(%s Operator

It operates element-wise on X and Y, and returns the Out. X, Y and Out are N-dim boolean tensors.
Each element of Out is calculated by %s
)DOC",
                               comment.type, comment.equation));
  }
};

template <typename OpComment>
class UnaryLogicalOpProtoMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    OpComment comment;
    AddInput("X", string::Sprintf("(LoDTensor) Operand of %s operator",
                                  comment.type));
    AddOutput("Out", string::Sprintf(
                         "(LoDTensor) n-dim bool tensor. Each element is %s",
                         comment.equation));
    AddComment(string::Sprintf(R"DOC(%s Operator

It operates element-wise on X, and returns the Out. X and Out are N-dim boolean tensors.
Each element of Out is calculated by %s
)DOC",
                               comment.type, comment.equation));
  }
};

template <typename OpComment>
class BinaryLogicalOpInferShape : public framework::InferShapeBase {
 public:
  void operator()(framework::InferShapeContext *context) const override {
    OpComment comment;
    PADDLE_ENFORCE(context->HasInput("X"),
                   "Input(X) of %s operator must not be null", comment.type);
    PADDLE_ENFORCE(context->HasInput("Y"),
                   "Input(Y) of %s operator must not be null", comment.type);
    auto dim_x = context->GetInputDim("X");
    auto dim_y = context->GetInputDim("Y");

    int product_x = framework::product(dim_x);
    int product_y = framework::product(dim_y);
    bool check = ctx->IsRuntime() && product_x >= 0 && product_y >= 0;
    if (check) {
      PADDLE_ENFORCE_EQ(
          product_x, product_y,
          "The number of elements in X and Y should be same, %d != %d",
          product_x, product_y);
    }

    context->SetOutputDim("Out", context->GetInputDim("X"));
    context->ShareLoD("X", "Out");
  }
};

template <typename OpComment>
class UnaryLogicalOpInferShape : public framework::InferShapeBase {
 public:
  void operator()(framework::InferShapeContext *context) const override {
    OpComment comment;
    PADDLE_ENFORCE(context->HasInput("X"),
                   "Input(X) of %s operator must not be null", comment.type);
    context->SetOutputDim("Out", context->GetInputDim("X"));
    context->ShareLoD("X", "Out");
  }
};

class LogicalOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext &ctx) const override {
    framework::OpKernelType kt = OperatorWithKernel::GetExpectedKernelType(ctx);
    // LogicalOp kernel's device type is decided by input tensor place
    kt.place_ = ctx.Input<framework::LoDTensor>("X")->place();
    return kt;
  }
};

}  // namespace operators
}  // namespace paddle

#define REGISTER_BINARY_LOGICAL_OP(op_type, _equation)                     \
  struct _##op_type##Comment {                                             \
    static char type[];                                                    \
    static char equation[];                                                \
  };                                                                       \
  char _##op_type##Comment::type[]{#op_type};                              \
  char _##op_type##Comment::equation[]{_equation};                         \
  REGISTER_OPERATOR(                                                       \
      op_type, ::paddle::operators::LogicalOp,                             \
      ::paddle::operators::BinaryLogicalOpProtoMaker<_##op_type##Comment>, \
      ::paddle::operators::BinaryLogicalOpInferShape<_##op_type##Comment>, \
      ::paddle::framework::EmptyGradOpMaker);

#define REGISTER_UNARY_LOGICAL_OP(op_type, _equation)                     \
  struct _##op_type##Comment {                                            \
    static char type[];                                                   \
    static char equation[];                                               \
  };                                                                      \
  char _##op_type##Comment::type[]{#op_type};                             \
  char _##op_type##Comment::equation[]{_equation};                        \
  REGISTER_OPERATOR(                                                      \
      op_type, ::paddle::operators::LogicalOp,                            \
      ::paddle::operators::UnaryLogicalOpProtoMaker<_##op_type##Comment>, \
      ::paddle::operators::UnaryLogicalOpInferShape<_##op_type##Comment>, \
      ::paddle::framework::EmptyGradOpMaker);

REGISTER_BINARY_LOGICAL_OP(logical_and, "$$Out = X \\&\\& Y$$");
REGISTER_BINARY_LOGICAL_KERNEL(logical_and, CPU,
                               paddle::operators::LogicalAndFunctor);
REGISTER_BINARY_LOGICAL_OP(logical_or, "$$Out = X || Y$$");
REGISTER_BINARY_LOGICAL_KERNEL(logical_or, CPU,
                               paddle::operators::LogicalOrFunctor);
REGISTER_UNARY_LOGICAL_OP(logical_not, "$$Out = !X$$");
REGISTER_UNARY_LOGICAL_KERNEL(logical_not, CPU,
                              paddle::operators::LogicalNotFunctor);
REGISTER_BINARY_LOGICAL_OP(logical_xor,
                           "$$Out = (X || Y) \\&\\& !(X \\&\\& Y)$$");
REGISTER_BINARY_LOGICAL_KERNEL(logical_xor, CPU,
                               paddle::operators::LogicalXorFunctor);
<commit_msg>Update logical_op.cc<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.

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 "paddle/fluid/operators/controlflow/logical_op.h"
#include <string>
#include "paddle/fluid/framework/op_registry.h"

namespace paddle {
namespace operators {
template <typename OpComment>
class BinaryLogicalOpProtoMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    OpComment comment;
    AddInput("X",
             string::Sprintf("(LoDTensor) Left hand operand of %s operator",
                             comment.type));
    AddInput("Y",
             string::Sprintf("(LoDTensor) Right hand operand of %s operator",
                             comment.type));
    AddOutput("Out", string::Sprintf(
                         "(LoDTensor) n-dim bool tensor. Each element is %s",
                         comment.equation));
    AddComment(string::Sprintf(R"DOC(%s Operator

It operates element-wise on X and Y, and returns the Out. X, Y and Out are N-dim boolean tensors.
Each element of Out is calculated by %s
)DOC",
                               comment.type, comment.equation));
  }
};

template <typename OpComment>
class UnaryLogicalOpProtoMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    OpComment comment;
    AddInput("X", string::Sprintf("(LoDTensor) Operand of %s operator",
                                  comment.type));
    AddOutput("Out", string::Sprintf(
                         "(LoDTensor) n-dim bool tensor. Each element is %s",
                         comment.equation));
    AddComment(string::Sprintf(R"DOC(%s Operator

It operates element-wise on X, and returns the Out. X and Out are N-dim boolean tensors.
Each element of Out is calculated by %s
)DOC",
                               comment.type, comment.equation));
  }
};

template <typename OpComment>
class BinaryLogicalOpInferShape : public framework::InferShapeBase {
 public:
  void operator()(framework::InferShapeContext *context) const override {
    OpComment comment;
    PADDLE_ENFORCE(context->HasInput("X"),
                   "Input(X) of %s operator must not be null", comment.type);
    PADDLE_ENFORCE(context->HasInput("Y"),
                   "Input(Y) of %s operator must not be null", comment.type);
    auto dim_x = context->GetInputDim("X");
    auto dim_y = context->GetInputDim("Y");

    int product_x = framework::product(dim_x);
    int product_y = framework::product(dim_y);
    bool check = ctx->IsRuntime() || (product_x >= 0 && product_y >= 0);
    if (check) {
      PADDLE_ENFORCE_EQ(
          product_x, product_y,
          "The number of elements in X and Y should be same, %d != %d",
          product_x, product_y);
    }

    context->SetOutputDim("Out", context->GetInputDim("X"));
    context->ShareLoD("X", "Out");
  }
};

template <typename OpComment>
class UnaryLogicalOpInferShape : public framework::InferShapeBase {
 public:
  void operator()(framework::InferShapeContext *context) const override {
    OpComment comment;
    PADDLE_ENFORCE(context->HasInput("X"),
                   "Input(X) of %s operator must not be null", comment.type);
    context->SetOutputDim("Out", context->GetInputDim("X"));
    context->ShareLoD("X", "Out");
  }
};

class LogicalOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext &ctx) const override {
    framework::OpKernelType kt = OperatorWithKernel::GetExpectedKernelType(ctx);
    // LogicalOp kernel's device type is decided by input tensor place
    kt.place_ = ctx.Input<framework::LoDTensor>("X")->place();
    return kt;
  }
};

}  // namespace operators
}  // namespace paddle

#define REGISTER_BINARY_LOGICAL_OP(op_type, _equation)                     \
  struct _##op_type##Comment {                                             \
    static char type[];                                                    \
    static char equation[];                                                \
  };                                                                       \
  char _##op_type##Comment::type[]{#op_type};                              \
  char _##op_type##Comment::equation[]{_equation};                         \
  REGISTER_OPERATOR(                                                       \
      op_type, ::paddle::operators::LogicalOp,                             \
      ::paddle::operators::BinaryLogicalOpProtoMaker<_##op_type##Comment>, \
      ::paddle::operators::BinaryLogicalOpInferShape<_##op_type##Comment>, \
      ::paddle::framework::EmptyGradOpMaker);

#define REGISTER_UNARY_LOGICAL_OP(op_type, _equation)                     \
  struct _##op_type##Comment {                                            \
    static char type[];                                                   \
    static char equation[];                                               \
  };                                                                      \
  char _##op_type##Comment::type[]{#op_type};                             \
  char _##op_type##Comment::equation[]{_equation};                        \
  REGISTER_OPERATOR(                                                      \
      op_type, ::paddle::operators::LogicalOp,                            \
      ::paddle::operators::UnaryLogicalOpProtoMaker<_##op_type##Comment>, \
      ::paddle::operators::UnaryLogicalOpInferShape<_##op_type##Comment>, \
      ::paddle::framework::EmptyGradOpMaker);

REGISTER_BINARY_LOGICAL_OP(logical_and, "$$Out = X \\&\\& Y$$");
REGISTER_BINARY_LOGICAL_KERNEL(logical_and, CPU,
                               paddle::operators::LogicalAndFunctor);
REGISTER_BINARY_LOGICAL_OP(logical_or, "$$Out = X || Y$$");
REGISTER_BINARY_LOGICAL_KERNEL(logical_or, CPU,
                               paddle::operators::LogicalOrFunctor);
REGISTER_UNARY_LOGICAL_OP(logical_not, "$$Out = !X$$");
REGISTER_UNARY_LOGICAL_KERNEL(logical_not, CPU,
                              paddle::operators::LogicalNotFunctor);
REGISTER_BINARY_LOGICAL_OP(logical_xor,
                           "$$Out = (X || Y) \\&\\& !(X \\&\\& Y)$$");
REGISTER_BINARY_LOGICAL_KERNEL(logical_xor, CPU,
                               paddle::operators::LogicalXorFunctor);
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Christoph Uhde
////////////////////////////////////////////////////////////////////////////////

#include <memory>
#include <boost/asio/io_service.hpp>
#include <fuerte/loop.h>
#include "HttpCommunicator.h"

namespace arangodb { namespace fuerte { inline namespace v1 {

static VpackInit init;

class LoopProvider;
class VstConnection;

// io_service::work is a inner class and we need to declare it forward
struct Work {
  Work(boost::asio::io_service& serv):_work(serv){}
  ::boost::asio::io_service::work _work;
};

// Loop ///////////////////////////////////////////////////////////////

Loop::Loop()
  :_serviceSharedPtr(new ::boost::asio::io_service)
  ,_service(_serviceSharedPtr.get())
  ,_sealed(false)
  ,_owning(true)
  ,_running(false)
  ,_singleRunMode(false)
  {}

void Loop::run_ready(){
  _sealed = true;
  if(!_owning){
    return;
  }
  _singleRunMode=true;
  _service->run();
  _service->reset();
  _singleRunMode=false;
}

void Loop::poll(){
  _sealed = true;
  if(!_owning){
    return;
  }
  _service->poll();
}

void Loop::reset(){
  _service->reset();
}

void Loop::setIoService(::boost::asio::io_service * service){
  if(_sealed){ return; }
  _owning = false;
  _serviceSharedPtr = nullptr;
  _service = service;
}

void Loop::setIoServiceTakeOwnership(::boost::asio::io_service* service){
  if(_sealed){ return; }
  _owning = true;
  _serviceSharedPtr.reset(service);
  _service = service;
}

boost::asio::io_service* Loop::getIoService(){
  _sealed = true;
  return _service;
}

// LoopProvider ///////////////////////////////////////////////////////////////

LoopProvider::LoopProvider()
  :_asioLoop(new Loop{})
  ,_httpLoop(new http::HttpCommunicator())
  {}

void LoopProvider::setAsioService(::boost::asio::io_service* service, bool running){
  if (_asioLoop->_sealed) {
    throw std::logic_error("you try to modify a loop that is already in use");
  } else {
    _asioLoop->setIoService(service);
  }
}

std::shared_ptr<Loop> LoopProvider::getAsioLoop(){
  _asioLoop->_sealed = true;
  return _asioLoop;
}

void LoopProvider::run(){
  if(_asioLoop){
    _asioLoop->run_ready();  //runs unitl all work is done
  }

  //poll http -- spins busy for http
  if(_httpLoop){
    while (true) {
      int left = _httpLoop->workOnce(); // check if there is still somehting to do
      if (left == 0) { break; }
      _httpLoop->wait(); // work happens here
    }
  }
}

void LoopProvider::poll(){
  //poll asio
  if(_asioLoop){
    _asioLoop->poll();  //polls until io_service has no further tasks
  }

  //poll http
  if(_httpLoop){
    int left = _httpLoop->workOnce();
  }
}

void LoopProvider::resetIoService(){
  if(_asioLoop){
    _asioLoop->reset();
  }
}
}}}

//void Loop::run(){
//  if(!_running && _service && _owning){
//    _running = true;
//    _sealed = true;
//    _work = std::make_shared<Work>(*_service);
//    while(_work){
//      try
//      {
//        _service->run();
//        break; // run() exited normally
//      }
//      catch (std::exception const& e)
//      {
//        FUERTE_LOG_ERROR << e.what() << std::endl; //return to loop
//        _service->reset();
//      }
//      catch(...){
//        FUERTE_LOG_ERROR << "unknown exception";
//        _service->reset();
//      }
//    }
//    return true;
//  }
//  return false;
//};
// void Loop::ask_to_stop(){
//   if(!_running || !_owning) { return; }
//   _work.reset();
//   _running = false;
// }
//
<commit_msg>partially fix race - one test still fails<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Christoph Uhde
////////////////////////////////////////////////////////////////////////////////

#include <memory>
#include <boost/asio/io_service.hpp>
#include <fuerte/loop.h>
#include "HttpCommunicator.h"

namespace arangodb { namespace fuerte { inline namespace v1 {

static VpackInit init;

class LoopProvider;
class VstConnection;

// io_service::work is a inner class and we need to declare it forward
struct Work {
  Work(boost::asio::io_service& serv):_work(serv){}
  ::boost::asio::io_service::work _work;
};

// Loop ///////////////////////////////////////////////////////////////

Loop::Loop()
  :_serviceSharedPtr(new ::boost::asio::io_service)
  ,_service(_serviceSharedPtr.get())
  ,_sealed(false)
  ,_owning(true)
  ,_running(false)
  ,_singleRunMode(false)
  {}

void Loop::run_ready(){
  _sealed = true;
  if(!_owning){
    return;
  }
  _singleRunMode=true;
  _service->run();
  _service->reset();
  _singleRunMode=false;
}

void Loop::poll(){
  _sealed = true;
  if(!_owning){
    return;
  }
  _service->poll();
}

void Loop::reset(){
  _service->reset();
}

void Loop::setIoService(::boost::asio::io_service * service){
  if(_sealed){ return; }
  _owning = false;
  _serviceSharedPtr = nullptr;
  _service = service;
}

void Loop::setIoServiceTakeOwnership(::boost::asio::io_service* service){
  if(_sealed){ return; }
  _owning = true;
  _serviceSharedPtr.reset(service);
  _service = service;
}

boost::asio::io_service* Loop::getIoService(){
  _sealed = true;
  return _service;
}

// LoopProvider ///////////////////////////////////////////////////////////////

LoopProvider::LoopProvider()
  :_asioLoop(new Loop{})
  ,_httpLoop(new http::HttpCommunicator())
  {}

void LoopProvider::setAsioService(::boost::asio::io_service* service, bool running){
  if (_asioLoop->_sealed) {
    throw std::logic_error("you try to modify a loop that is already in use");
  } else {
    _asioLoop->setIoService(service);
  }
}

std::shared_ptr<Loop> LoopProvider::getAsioLoop(){
  _asioLoop->_sealed = true;
  return _asioLoop;
}

void LoopProvider::run(){
  static std::mutex mutex;

  if(_asioLoop){
    _asioLoop->run_ready();  //runs unitl all work is done
  }

  //poll http -- spins busy for http
  if(_httpLoop && mutex.try_lock()){
    while (true) {
      int left = _httpLoop->workOnce(); // check if there is still somehting to do
      if (left == 0) { break; }
      _httpLoop->wait(); // work happens here
    }
    mutex.unlock();
  }
}

void LoopProvider::poll(){
  static std::mutex mutex;
  //poll asio
  if(_asioLoop){
    _asioLoop->poll();  //polls until io_service has no further tasks
  }

  //poll http
  if(_httpLoop && mutex.try_lock()){
    int left = _httpLoop->workOnce();
    mutex.unlock();
  }
}

void LoopProvider::resetIoService(){
  if(_asioLoop){
    _asioLoop->reset();
  }
}
}}}

//void Loop::run(){
//  if(!_running && _service && _owning){
//    _running = true;
//    _sealed = true;
//    _work = std::make_shared<Work>(*_service);
//    while(_work){
//      try
//      {
//        _service->run();
//        break; // run() exited normally
//      }
//      catch (std::exception const& e)
//      {
//        FUERTE_LOG_ERROR << e.what() << std::endl; //return to loop
//        _service->reset();
//      }
//      catch(...){
//        FUERTE_LOG_ERROR << "unknown exception";
//        _service->reset();
//      }
//    }
//    return true;
//  }
//  return false;
//};
// void Loop::ask_to_stop(){
//   if(!_running || !_owning) { return; }
//   _work.reset();
//   _running = false;
// }
//
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Michael Hackstein
////////////////////////////////////////////////////////////////////////////////

#include "ExecutionBlock.h"
#include "Aql/ExecutionEngine.h"

using namespace arangodb::aql;

ExecutionBlock::ExecutionBlock(ExecutionEngine* engine, ExecutionNode const* ep)
    : _engine(engine),
      _trx(engine->getQuery()->trx()),
      _exeNode(ep),
      _pos(0),
      _done(false) {}

ExecutionBlock::~ExecutionBlock() {
  for (auto& it : _buffer) {
    delete it;
  }

  _buffer.clear();
}

/// @brief determine the number of rows in a vector of blocks
size_t ExecutionBlock::countBlocksRows(
    std::vector<AqlItemBlock*> const& blocks) const {
  size_t count = 0;
  for (auto const& it : blocks) {
    count += it->size();
  }
  return count;
}

bool ExecutionBlock::removeDependency(ExecutionBlock* ep) {
  auto it = _dependencies.begin();
  while (it != _dependencies.end()) {
    if (*it == ep) {
      _dependencies.erase(it);
      return true;
    }
    ++it;
  }
  return false;
}

int ExecutionBlock::initializeCursor(AqlItemBlock* items, size_t pos) {
  DEBUG_BEGIN_BLOCK();
  for (auto& d : _dependencies) {
    int res = d->initializeCursor(items, pos);

    if (res != TRI_ERROR_NO_ERROR) {
      return res;
    }
  }

  for (auto& it : _buffer) {
    delete it;
  }
  _buffer.clear();

  _done = false;
  return TRI_ERROR_NO_ERROR;
  DEBUG_END_BLOCK();
}

/// @brief whether or not the query was killed
bool ExecutionBlock::isKilled() const { return _engine->getQuery()->killed(); }

/// @brief whether or not the query was killed
void ExecutionBlock::throwIfKilled() {
  if (isKilled()) {
    THROW_ARANGO_EXCEPTION(TRI_ERROR_QUERY_KILLED);
  }
}

/// @brief initialize
int ExecutionBlock::initialize() {
  for (auto it = _dependencies.begin(); it != _dependencies.end(); ++it) {
    int res = (*it)->initialize();

    if (res != TRI_ERROR_NO_ERROR) {
      return res;
    }
  }
  return TRI_ERROR_NO_ERROR;
}

/// @brief shutdown, will be called exactly once for the whole query
int ExecutionBlock::shutdown(int errorCode) {
  int ret = TRI_ERROR_NO_ERROR;

  for (auto& it : _buffer) {
    delete it;
  }
  _buffer.clear();

  for (auto it = _dependencies.begin(); it != _dependencies.end(); ++it) {
    int res;
    try {
      res = (*it)->shutdown(errorCode);
    } catch (...) {
      res = TRI_ERROR_INTERNAL;
    }

    if (res != TRI_ERROR_NO_ERROR) {
      ret = res;
    }
  }

  return ret;
}

/// @brief getSome, gets some more items, semantic is as follows: not
/// more than atMost items may be delivered. The method tries to
/// return a block of at least atLeast items, however, it may return
/// less (for example if there are not enough items to come). However,
/// if it returns an actual block, it must contain at least one item.
AqlItemBlock* ExecutionBlock::getSome(size_t atLeast, size_t atMost) {
  DEBUG_BEGIN_BLOCK();
  std::unique_ptr<AqlItemBlock> result(
      getSomeWithoutRegisterClearout(atLeast, atMost));
  clearRegisters(result.get());
  return result.release();
  DEBUG_END_BLOCK();
}

/// @brief request an AqlItemBlock from the memory manager
AqlItemBlock* ExecutionBlock::requestBlock(size_t nrItems, RegisterId nrRegs) {
  return _engine->_itemBlockManager.requestBlock(nrItems, nrRegs);
}

/// @brief return an AqlItemBlock to the memory manager
void ExecutionBlock::returnBlock(AqlItemBlock*& block) {
  _engine->_itemBlockManager.returnBlock(block);
}

/// @brief copy register data from one block (src) into another (dst)
/// register values are cloned
void ExecutionBlock::inheritRegisters(AqlItemBlock const* src,
                                      AqlItemBlock* dst, size_t srcRow,
                                      size_t dstRow) {
  DEBUG_BEGIN_BLOCK();
  RegisterId const n = src->getNrRegs();
  auto planNode = getPlanNode();

  for (RegisterId i = 0; i < n; i++) {
    if (planNode->_regsToClear.find(i) == planNode->_regsToClear.end()) {
      auto const& value = src->getValueReference(srcRow, i);

      if (!value.isEmpty()) {
        AqlValue a = value.clone();
        AqlValueGuard guard(a, true);

        dst->setValue(dstRow, i, a);
        guard.steal();
      }
    }
  }
  DEBUG_END_BLOCK();
}

/// @brief copy register data from one block (src) into another (dst)
/// register values are cloned
void ExecutionBlock::inheritRegisters(AqlItemBlock const* src,
                                      AqlItemBlock* dst, size_t row) {
  DEBUG_BEGIN_BLOCK();
  RegisterId const n = src->getNrRegs();
  auto planNode = getPlanNode();

  for (RegisterId i = 0; i < n; i++) {
    if (planNode->_regsToClear.find(i) == planNode->_regsToClear.end()) {
      auto const& value = src->getValueReference(row, i);

      if (!value.isEmpty()) {
        AqlValue a = value.clone();
        AqlValueGuard guard(a, true);

        TRI_IF_FAILURE("ExecutionBlock::inheritRegisters") {
          THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
        }

        dst->setValue(0, i, a);
        guard.steal();
      }
    }
  }
  DEBUG_END_BLOCK();
}

/// @brief the following is internal to pull one more block and append it to
/// our _buffer deque. Returns true if a new block was appended and false if
/// the dependent node is exhausted.
bool ExecutionBlock::getBlock(size_t atLeast, size_t atMost) {
  DEBUG_BEGIN_BLOCK();
  throwIfKilled();  // check if we were aborted

  std::unique_ptr<AqlItemBlock> docs(
      _dependencies[0]->getSome(atLeast, atMost));

  if (docs == nullptr) {
    return false;
  }

  TRI_IF_FAILURE("ExecutionBlock::getBlock") {
    THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
  }

  _buffer.emplace_back(docs.get());
  docs.release();

  return true;
  DEBUG_END_BLOCK();
}

/// @brief getSomeWithoutRegisterClearout, same as above, however, this
/// is the actual worker which does not clear out registers at the end
/// the idea is that somebody who wants to call the generic functionality
/// in a derived class but wants to modify the results before the register
/// cleanup can use this method, internal use only
AqlItemBlock* ExecutionBlock::getSomeWithoutRegisterClearout(size_t atLeast,
                                                             size_t atMost) {
  DEBUG_BEGIN_BLOCK();
  TRI_ASSERT(0 < atLeast && atLeast <= atMost);
  size_t skipped = 0;

  AqlItemBlock* result = nullptr;
  int out = getOrSkipSome(atLeast, atMost, false, result, skipped);

  if (out != TRI_ERROR_NO_ERROR) {
    THROW_ARANGO_EXCEPTION(out);
  }

  return result;
  DEBUG_END_BLOCK();
}

void ExecutionBlock::clearRegisters(AqlItemBlock* result) {
  DEBUG_BEGIN_BLOCK();
  // Clear out registers not needed later on:
  if (result != nullptr) {
    result->clearRegisters(getPlanNode()->_regsToClear);
  }
  DEBUG_END_BLOCK();
}

size_t ExecutionBlock::skipSome(size_t atLeast, size_t atMost) {
  DEBUG_BEGIN_BLOCK();
  TRI_ASSERT(0 < atLeast && atLeast <= atMost);
  size_t skipped = 0;

  AqlItemBlock* result = nullptr;
  int out = getOrSkipSome(atLeast, atMost, true, result, skipped);

  TRI_ASSERT(result == nullptr);

  if (out != TRI_ERROR_NO_ERROR) {
    THROW_ARANGO_EXCEPTION(out);
  }

  return skipped;
  DEBUG_END_BLOCK();
}

// skip exactly <number> outputs, returns <true> if _done after
// skipping, and <false> otherwise . . .
bool ExecutionBlock::skip(size_t number, size_t& numActuallySkipped) {
  DEBUG_BEGIN_BLOCK();
  size_t skipped = skipSome(number, number);
  size_t nr = skipped;
  while (nr != 0 && skipped < number) {
    nr = skipSome(number - skipped, number - skipped);
    skipped += nr;
  }
  numActuallySkipped = skipped;
  if (nr == 0) {
    return true;
  }
  return !hasMore();
  DEBUG_END_BLOCK();
}

bool ExecutionBlock::hasMore() {
  if (_done) {
    return false;
  }
  if (!_buffer.empty()) {
    return true;
  }
  if (getBlock(DefaultBatchSize(), DefaultBatchSize())) {
    _pos = 0;
    return true;
  }
  _done = true;
  return false;
}

int64_t ExecutionBlock::remaining() {
  int64_t sum = 0;
  for (auto const& it : _buffer) {
    sum += it->size();
  }
  return sum + _dependencies[0]->remaining();
}

int ExecutionBlock::getOrSkipSome(size_t atLeast, size_t atMost, bool skipping,
                                  AqlItemBlock*& result, size_t& skipped) {
  DEBUG_BEGIN_BLOCK();
  TRI_ASSERT(result == nullptr && skipped == 0);

  if (_done) {
    return TRI_ERROR_NO_ERROR;
  }

  // if _buffer.size() is > 0 then _pos points to a valid place . . .
  std::vector<AqlItemBlock*> collector;

  auto freeCollector = [&collector]() {
    for (auto& x : collector) {
      delete x;
    }
    collector.clear();
  };

  try {
    while (skipped < atLeast) {
      if (_buffer.empty()) {
        if (skipping) {
          size_t numActuallySkipped = 0;
          _dependencies[0]->skip(atLeast - skipped, numActuallySkipped);
          skipped = atLeast;
          freeCollector();
          return TRI_ERROR_NO_ERROR;
        } else {
          if (!getBlock(atLeast - skipped, atMost - skipped)) {
            _done = true;
            break;  // must still put things in the result from the collector .
                    // . .
          }
          _pos = 0;
        }
      }

      AqlItemBlock* cur = _buffer.front();

      if (cur->size() - _pos > atMost - skipped) {
        // The current block is too large for atMost:
        if (!skipping) {
          std::unique_ptr<AqlItemBlock> more(
              cur->slice(_pos, _pos + (atMost - skipped)));

          TRI_IF_FAILURE("ExecutionBlock::getOrSkipSome1") {
            THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
          }

          collector.emplace_back(more.get());
          more.release();  // do not delete it!
        }
        _pos += atMost - skipped;
        skipped = atMost;
      } else if (_pos > 0) {
        // The current block fits into our result, but it is already
        // half-eaten:
        if (!skipping) {
          std::unique_ptr<AqlItemBlock> more(cur->slice(_pos, cur->size()));

          TRI_IF_FAILURE("ExecutionBlock::getOrSkipSome2") {
            THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
          }

          collector.emplace_back(more.get());
          more.release();
        }
        skipped += cur->size() - _pos;
        delete cur;
        _buffer.pop_front();
        _pos = 0;
      } else {
        // The current block fits into our result and is fresh:
        skipped += cur->size();
        if (!skipping) {
          // if any of the following statements throw, then cur is not lost,
          // as it is still contained in _buffer
          TRI_IF_FAILURE("ExecutionBlock::getOrSkipSome3") {
            THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
          }
          collector.emplace_back(cur);
        } else {
          delete cur;
        }
        _buffer.pop_front();
        _pos = 0;
      }
    }
  } catch (...) {
    freeCollector();
    throw;
  }

  TRI_ASSERT(result == nullptr);

  if (!skipping) {
    if (collector.size() == 1) {
      result = collector[0];
      collector.clear();
    } else if (!collector.empty()) {
      try {
        TRI_IF_FAILURE("ExecutionBlock::getOrSkipSomeConcatenate") {
          THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
        }
        result = AqlItemBlock::concatenate(collector);
      } catch (...) {
        freeCollector();
        throw;
      }
    }
  }

  freeCollector();
  return TRI_ERROR_NO_ERROR;
  DEBUG_END_BLOCK();
}
<commit_msg>copy row 0<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Michael Hackstein
////////////////////////////////////////////////////////////////////////////////

#include "ExecutionBlock.h"
#include "Aql/ExecutionEngine.h"

using namespace arangodb::aql;

ExecutionBlock::ExecutionBlock(ExecutionEngine* engine, ExecutionNode const* ep)
    : _engine(engine),
      _trx(engine->getQuery()->trx()),
      _exeNode(ep),
      _pos(0),
      _done(false) {}

ExecutionBlock::~ExecutionBlock() {
  for (auto& it : _buffer) {
    delete it;
  }

  _buffer.clear();
}

/// @brief determine the number of rows in a vector of blocks
size_t ExecutionBlock::countBlocksRows(
    std::vector<AqlItemBlock*> const& blocks) const {
  size_t count = 0;
  for (auto const& it : blocks) {
    count += it->size();
  }
  return count;
}

bool ExecutionBlock::removeDependency(ExecutionBlock* ep) {
  auto it = _dependencies.begin();
  while (it != _dependencies.end()) {
    if (*it == ep) {
      _dependencies.erase(it);
      return true;
    }
    ++it;
  }
  return false;
}

int ExecutionBlock::initializeCursor(AqlItemBlock* items, size_t pos) {
  DEBUG_BEGIN_BLOCK();
  for (auto& d : _dependencies) {
    int res = d->initializeCursor(items, pos);

    if (res != TRI_ERROR_NO_ERROR) {
      return res;
    }
  }

  for (auto& it : _buffer) {
    delete it;
  }
  _buffer.clear();

  _done = false;
  return TRI_ERROR_NO_ERROR;
  DEBUG_END_BLOCK();
}

/// @brief whether or not the query was killed
bool ExecutionBlock::isKilled() const { return _engine->getQuery()->killed(); }

/// @brief whether or not the query was killed
void ExecutionBlock::throwIfKilled() {
  if (isKilled()) {
    THROW_ARANGO_EXCEPTION(TRI_ERROR_QUERY_KILLED);
  }
}

/// @brief initialize
int ExecutionBlock::initialize() {
  for (auto it = _dependencies.begin(); it != _dependencies.end(); ++it) {
    int res = (*it)->initialize();

    if (res != TRI_ERROR_NO_ERROR) {
      return res;
    }
  }
  return TRI_ERROR_NO_ERROR;
}

/// @brief shutdown, will be called exactly once for the whole query
int ExecutionBlock::shutdown(int errorCode) {
  int ret = TRI_ERROR_NO_ERROR;

  for (auto& it : _buffer) {
    delete it;
  }
  _buffer.clear();

  for (auto it = _dependencies.begin(); it != _dependencies.end(); ++it) {
    int res;
    try {
      res = (*it)->shutdown(errorCode);
    } catch (...) {
      res = TRI_ERROR_INTERNAL;
    }

    if (res != TRI_ERROR_NO_ERROR) {
      ret = res;
    }
  }

  return ret;
}

/// @brief getSome, gets some more items, semantic is as follows: not
/// more than atMost items may be delivered. The method tries to
/// return a block of at least atLeast items, however, it may return
/// less (for example if there are not enough items to come). However,
/// if it returns an actual block, it must contain at least one item.
AqlItemBlock* ExecutionBlock::getSome(size_t atLeast, size_t atMost) {
  DEBUG_BEGIN_BLOCK();
  std::unique_ptr<AqlItemBlock> result(
      getSomeWithoutRegisterClearout(atLeast, atMost));
  clearRegisters(result.get());
  return result.release();
  DEBUG_END_BLOCK();
}

/// @brief request an AqlItemBlock from the memory manager
AqlItemBlock* ExecutionBlock::requestBlock(size_t nrItems, RegisterId nrRegs) {
  return _engine->_itemBlockManager.requestBlock(nrItems, nrRegs);
}

/// @brief return an AqlItemBlock to the memory manager
void ExecutionBlock::returnBlock(AqlItemBlock*& block) {
  _engine->_itemBlockManager.returnBlock(block);
}

/// @brief copy register data from one block (src) into another (dst)
/// register values are cloned
void ExecutionBlock::inheritRegisters(AqlItemBlock const* src,
                                      AqlItemBlock* dst, size_t srcRow,
                                      size_t dstRow) {
  DEBUG_BEGIN_BLOCK();
  RegisterId const n = src->getNrRegs();
  auto planNode = getPlanNode();

  for (RegisterId i = 0; i < n; i++) {
    if (planNode->_regsToClear.find(i) == planNode->_regsToClear.end()) {
      auto const& value = src->getValueReference(srcRow, i);

      if (!value.isEmpty()) {
        AqlValue a = value.clone();
        AqlValueGuard guard(a, true);

        dst->setValue(dstRow, i, a);
        guard.steal();
      }
    }
  }
  DEBUG_END_BLOCK();
}

/// @brief copy register data from one block (src) into another (dst)
/// register values are cloned
void ExecutionBlock::inheritRegisters(AqlItemBlock const* src,
                                      AqlItemBlock* dst, size_t row) {
  DEBUG_BEGIN_BLOCK();
  RegisterId const n = src->getNrRegs();
  auto planNode = getPlanNode();

  for (RegisterId i = 0; i < n; i++) {
    if (planNode->_regsToClear.find(i) == planNode->_regsToClear.end()) {
      auto const& value = src->getValueReference(row, i);

      if (!value.isEmpty()) {
        AqlValue a = value.clone();
        AqlValueGuard guard(a, true);

        TRI_IF_FAILURE("ExecutionBlock::inheritRegisters") {
          THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
        }

        dst->setValue(0, i, a);
        guard.steal();
      } else if (row > 0) {
        auto const& value = src->getValueReference(0, i);
        if (!value.isEmpty()) {
          AqlValue a = value.clone();
          AqlValueGuard guard(a, true);

          TRI_IF_FAILURE("ExecutionBlock::inheritRegisters") {
            THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
          }

          dst->setValue(0, i, a);
          guard.steal();
        }
      }
    }
  }

  DEBUG_END_BLOCK();
}

/// @brief the following is internal to pull one more block and append it to
/// our _buffer deque. Returns true if a new block was appended and false if
/// the dependent node is exhausted.
bool ExecutionBlock::getBlock(size_t atLeast, size_t atMost) {
  DEBUG_BEGIN_BLOCK();
  throwIfKilled();  // check if we were aborted

  std::unique_ptr<AqlItemBlock> docs(
      _dependencies[0]->getSome(atLeast, atMost));

  if (docs == nullptr) {
    return false;
  }

  TRI_IF_FAILURE("ExecutionBlock::getBlock") {
    THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
  }

  _buffer.emplace_back(docs.get());
  docs.release();

  return true;
  DEBUG_END_BLOCK();
}

/// @brief getSomeWithoutRegisterClearout, same as above, however, this
/// is the actual worker which does not clear out registers at the end
/// the idea is that somebody who wants to call the generic functionality
/// in a derived class but wants to modify the results before the register
/// cleanup can use this method, internal use only
AqlItemBlock* ExecutionBlock::getSomeWithoutRegisterClearout(size_t atLeast,
                                                             size_t atMost) {
  DEBUG_BEGIN_BLOCK();
  TRI_ASSERT(0 < atLeast && atLeast <= atMost);
  size_t skipped = 0;

  AqlItemBlock* result = nullptr;
  int out = getOrSkipSome(atLeast, atMost, false, result, skipped);

  if (out != TRI_ERROR_NO_ERROR) {
    THROW_ARANGO_EXCEPTION(out);
  }

  return result;
  DEBUG_END_BLOCK();
}

void ExecutionBlock::clearRegisters(AqlItemBlock* result) {
  DEBUG_BEGIN_BLOCK();
  // Clear out registers not needed later on:
  if (result != nullptr) {
    result->clearRegisters(getPlanNode()->_regsToClear);
  }
  DEBUG_END_BLOCK();
}

size_t ExecutionBlock::skipSome(size_t atLeast, size_t atMost) {
  DEBUG_BEGIN_BLOCK();
  TRI_ASSERT(0 < atLeast && atLeast <= atMost);
  size_t skipped = 0;

  AqlItemBlock* result = nullptr;
  int out = getOrSkipSome(atLeast, atMost, true, result, skipped);

  TRI_ASSERT(result == nullptr);

  if (out != TRI_ERROR_NO_ERROR) {
    THROW_ARANGO_EXCEPTION(out);
  }

  return skipped;
  DEBUG_END_BLOCK();
}

// skip exactly <number> outputs, returns <true> if _done after
// skipping, and <false> otherwise . . .
bool ExecutionBlock::skip(size_t number, size_t& numActuallySkipped) {
  DEBUG_BEGIN_BLOCK();
  size_t skipped = skipSome(number, number);
  size_t nr = skipped;
  while (nr != 0 && skipped < number) {
    nr = skipSome(number - skipped, number - skipped);
    skipped += nr;
  }
  numActuallySkipped = skipped;
  if (nr == 0) {
    return true;
  }
  return !hasMore();
  DEBUG_END_BLOCK();
}

bool ExecutionBlock::hasMore() {
  if (_done) {
    return false;
  }
  if (!_buffer.empty()) {
    return true;
  }
  if (getBlock(DefaultBatchSize(), DefaultBatchSize())) {
    _pos = 0;
    return true;
  }
  _done = true;
  return false;
}

int64_t ExecutionBlock::remaining() {
  int64_t sum = 0;
  for (auto const& it : _buffer) {
    sum += it->size();
  }
  return sum + _dependencies[0]->remaining();
}

int ExecutionBlock::getOrSkipSome(size_t atLeast, size_t atMost, bool skipping,
                                  AqlItemBlock*& result, size_t& skipped) {
  DEBUG_BEGIN_BLOCK();
  TRI_ASSERT(result == nullptr && skipped == 0);

  if (_done) {
    return TRI_ERROR_NO_ERROR;
  }

  // if _buffer.size() is > 0 then _pos points to a valid place . . .
  std::vector<AqlItemBlock*> collector;

  auto freeCollector = [&collector]() {
    for (auto& x : collector) {
      delete x;
    }
    collector.clear();
  };

  try {
    while (skipped < atLeast) {
      if (_buffer.empty()) {
        if (skipping) {
          size_t numActuallySkipped = 0;
          _dependencies[0]->skip(atLeast - skipped, numActuallySkipped);
          skipped = atLeast;
          freeCollector();
          return TRI_ERROR_NO_ERROR;
        } else {
          if (!getBlock(atLeast - skipped, atMost - skipped)) {
            _done = true;
            break;  // must still put things in the result from the collector .
                    // . .
          }
          _pos = 0;
        }
      }

      AqlItemBlock* cur = _buffer.front();

      if (cur->size() - _pos > atMost - skipped) {
        // The current block is too large for atMost:
        if (!skipping) {
          std::unique_ptr<AqlItemBlock> more(
              cur->slice(_pos, _pos + (atMost - skipped)));

          TRI_IF_FAILURE("ExecutionBlock::getOrSkipSome1") {
            THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
          }

          collector.emplace_back(more.get());
          more.release();  // do not delete it!
        }
        _pos += atMost - skipped;
        skipped = atMost;
      } else if (_pos > 0) {
        // The current block fits into our result, but it is already
        // half-eaten:
        if (!skipping) {
          std::unique_ptr<AqlItemBlock> more(cur->slice(_pos, cur->size()));

          TRI_IF_FAILURE("ExecutionBlock::getOrSkipSome2") {
            THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
          }

          collector.emplace_back(more.get());
          more.release();
        }
        skipped += cur->size() - _pos;
        delete cur;
        _buffer.pop_front();
        _pos = 0;
      } else {
        // The current block fits into our result and is fresh:
        skipped += cur->size();
        if (!skipping) {
          // if any of the following statements throw, then cur is not lost,
          // as it is still contained in _buffer
          TRI_IF_FAILURE("ExecutionBlock::getOrSkipSome3") {
            THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
          }
          collector.emplace_back(cur);
        } else {
          delete cur;
        }
        _buffer.pop_front();
        _pos = 0;
      }
    }
  } catch (...) {
    freeCollector();
    throw;
  }

  TRI_ASSERT(result == nullptr);

  if (!skipping) {
    if (collector.size() == 1) {
      result = collector[0];
      collector.clear();
    } else if (!collector.empty()) {
      try {
        TRI_IF_FAILURE("ExecutionBlock::getOrSkipSomeConcatenate") {
          THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
        }
        result = AqlItemBlock::concatenate(collector);
      } catch (...) {
        freeCollector();
        throw;
      }
    }
  }

  freeCollector();
  return TRI_ERROR_NO_ERROR;
  DEBUG_END_BLOCK();
}
<|endoftext|>