diff --git a/.gitignore b/.gitignore index 7a55f6b09..d6aa35edb 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ build*/ .vscode/ cmake-build-* phylanx.egg-info/ +/tests/unit/execution_tree/images +/tests/unit/plugins/controls/images diff --git a/examples/algorithms/lra/lra_csv_distributed.cpp b/examples/algorithms/lra/lra_csv_distributed.cpp index edac84f3f..1a5d6bb74 100644 --- a/examples/algorithms/lra/lra_csv_distributed.cpp +++ b/examples/algorithms/lra/lra_csv_distributed.cpp @@ -36,6 +36,7 @@ char const* const read_x_code = R"(block( annotate_d( slice(file_read_csv(filepath), list(row_start, row_stop), list(col_start, col_stop)), + "read_x", list("tile", list("rows", row_start, row_stop), list("columns", col_start, col_stop) @@ -53,6 +54,7 @@ char const* const read_y_code = R"(block( annotate_d( slice(file_read_csv(filepath), list(row_start , row_stop), col_stop), + "read_y", list("tile", list("rows", row_start, row_stop), list("columns", col_stop, col_stop+1) diff --git a/phylanx/execution_tree/annotation.hpp b/phylanx/execution_tree/annotation.hpp index 2ab526b50..4270a6380 100644 --- a/phylanx/execution_tree/annotation.hpp +++ b/phylanx/execution_tree/annotation.hpp @@ -12,6 +12,7 @@ #include +#include #include #include @@ -99,6 +100,10 @@ namespace phylanx { namespace execution_tree annotation&& data, std::string const& name, std::string const& codename); + PHYLANX_EXPORT bool get_if(std::string const& key, + execution_tree::annotation& ann, std::string const& name = "", + std::string const& codename = "") const; + friend bool operator==(annotation const& lhs, annotation const& rhs) { return lhs.data_ == rhs.data_; @@ -123,6 +128,33 @@ namespace phylanx { namespace execution_tree //////////////////////////////////////////////////////////////////////////// PHYLANX_EXPORT std::ostream& operator<<( std::ostream& os, annotation const& ann); + + //////////////////////////////////////////////////////////////////////////// + struct annotation_information + { + annotation_information() = default; + + PHYLANX_EXPORT annotation_information( + std::string name, std::int64_t generation); + + PHYLANX_EXPORT annotation_information( + annotation const& ann, std::string const& name, + std::string const& codename); + + PHYLANX_EXPORT std::string generate_name() const; + PHYLANX_EXPORT annotation as_annotation() const; + + private: + void extract_from_name(); + + public: + std::string name_; + std::int64_t generation_ = 0; + }; + + PHYLANX_EXPORT annotation_information extract_annotation_information( + annotation const& ann, std::string const& name, + std::string const& codename); }} #endif diff --git a/phylanx/execution_tree/locality_annotation.hpp b/phylanx/execution_tree/locality_annotation.hpp index 2d5ffe896..13bc9ab96 100644 --- a/phylanx/execution_tree/locality_annotation.hpp +++ b/phylanx/execution_tree/locality_annotation.hpp @@ -21,9 +21,18 @@ namespace phylanx { namespace execution_tree struct locality_information { PHYLANX_EXPORT locality_information(); + + locality_information( + std::uint32_t locality_id, std::uint32_t num_localities) + : locality_id_(locality_id) + , num_localities_(num_localities) + {} + PHYLANX_EXPORT locality_information(ir::range const& data, std::string const& name, std::string const& codename); + PHYLANX_EXPORT execution_tree::annotation as_annotation() const; + std::uint32_t locality_id_; std::uint32_t num_localities_; }; diff --git a/phylanx/execution_tree/meta_annotation.hpp b/phylanx/execution_tree/meta_annotation.hpp index 0bbdc19e8..ed4cd35f8 100644 --- a/phylanx/execution_tree/meta_annotation.hpp +++ b/phylanx/execution_tree/meta_annotation.hpp @@ -17,14 +17,17 @@ namespace phylanx { namespace execution_tree { PHYLANX_EXPORT hpx::future meta_annotation( annotation const& locality_ann, annotation&& ann, - std::string const& name, std::string const& codename); + std::string const& ann_name, std::string const& name, + std::string const& codename); PHYLANX_EXPORT annotation meta_annotation(hpx::launch::sync_policy, annotation const& locality_ann, annotation&& ann, - std::string const& name, std::string const& codename); + std::string const& ann_name, std::string const& name, + std::string const& codename); PHYLANX_EXPORT annotation localities_annotation(annotation& locality_ann, - annotation&& ann, std::string const& name, std::string const& codename); + annotation&& ann, annotation_information const& ann_info, + std::string const& name, std::string const& codename); }} #endif diff --git a/phylanx/execution_tree/primitives/annotate_primitive.hpp b/phylanx/execution_tree/primitives/annotate_primitive.hpp index 1a05147e7..a8bf2f565 100644 --- a/phylanx/execution_tree/primitives/annotate_primitive.hpp +++ b/phylanx/execution_tree/primitives/annotate_primitive.hpp @@ -37,11 +37,21 @@ namespace phylanx { namespace execution_tree { namespace primitives primitive_arguments_type const& args, eval_context ctx) const override; + protected: + hpx::future eval_annotate( + primitive_arguments_type const& operands, + primitive_arguments_type const& args, + eval_context ctx) const; + hpx::future eval_annotate_d( + primitive_arguments_type const& operands, + primitive_arguments_type const& args, + eval_context ctx) const; + protected: primitive_argument_type annotate(primitive_argument_type&& target, ir::range&& args) const; primitive_argument_type annotate_d(primitive_argument_type&& target, - ir::range&& args) const; + std::string&& name, ir::range&& args) const; private: std::string func_name_; diff --git a/phylanx/plugins/dist_matrixops/dist_dot_operation.hpp b/phylanx/plugins/dist_matrixops/dist_dot_operation.hpp index d15ac3c3b..6b45f6a82 100644 --- a/phylanx/plugins/dist_matrixops/dist_dot_operation.hpp +++ b/phylanx/plugins/dist_matrixops/dist_dot_operation.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -51,7 +52,9 @@ namespace phylanx { namespace dist_matrixops { namespace primitives template execution_tree::primitive_argument_type dot1d1d( - ir::node_data&& lhs, ir::node_data&& rhs) const; + ir::node_data&& lhs, ir::node_data&& rhs, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const; template execution_tree::primitive_argument_type dot1d2d( ir::node_data&& lhs, ir::node_data&& rhs) const; @@ -62,7 +65,9 @@ namespace phylanx { namespace dist_matrixops { namespace primitives #endif template execution_tree::primitive_argument_type dot1d( - ir::node_data&& lhs, ir::node_data&& rhs) const; + ir::node_data&& lhs, ir::node_data&& rhs, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const; execution_tree::primitive_argument_type dot1d( execution_tree::primitive_argument_type&&, execution_tree::primitive_argument_type&&) const; @@ -80,7 +85,9 @@ namespace phylanx { namespace dist_matrixops { namespace primitives #endif template execution_tree::primitive_argument_type dot2d( - ir::node_data&& lhs, ir::node_data&& rhs) const; + ir::node_data&& lhs, ir::node_data&& rhs, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const; execution_tree::primitive_argument_type dot2d( execution_tree::primitive_argument_type&&, execution_tree::primitive_argument_type&&) const; @@ -97,7 +104,9 @@ namespace phylanx { namespace dist_matrixops { namespace primitives ir::node_data&& lhs, ir::node_data&& rhs) const; template execution_tree::primitive_argument_type dot3d( - ir::node_data&& lhs, ir::node_data&& rhs) const; + ir::node_data&& lhs, ir::node_data&& rhs, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const; execution_tree::primitive_argument_type dot3d( execution_tree::primitive_argument_type&&, execution_tree::primitive_argument_type&&) const; diff --git a/phylanx/plugins/dist_matrixops/dist_dot_operation_impl.hpp b/phylanx/plugins/dist_matrixops/dist_dot_operation_impl.hpp index b42fa0c47..5173ca53c 100644 --- a/phylanx/plugins/dist_matrixops/dist_dot_operation_impl.hpp +++ b/phylanx/plugins/dist_matrixops/dist_dot_operation_impl.hpp @@ -11,15 +11,19 @@ #include #include #include -#include #include +#include +#include +#include +#include #include #include #include #include #include +#include #include #include #include @@ -30,6 +34,17 @@ #include #endif +using std_int64_t = std::int64_t; +using std_uint8_t = std::uint8_t; + +REGISTER_DISTRIBUTED_VECTOR_DECLARATION(double); +REGISTER_DISTRIBUTED_VECTOR_DECLARATION(std_int64_t); +REGISTER_DISTRIBUTED_VECTOR_DECLARATION(std_uint8_t); + +HPX_REGISTER_ALLREDUCE_DECLARATION(double); +HPX_REGISTER_ALLREDUCE_DECLARATION(std_int64_t); +HPX_REGISTER_ALLREDUCE_DECLARATION(std_uint8_t); + /////////////////////////////////////////////////////////////////////////////// namespace phylanx { namespace dist_matrixops { namespace primitives { @@ -67,21 +82,111 @@ namespace phylanx { namespace dist_matrixops { namespace primitives } } - /////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// template execution_tree::primitive_argument_type dist_dot_operation::dot1d1d( - ir::node_data&& lhs, ir::node_data&& rhs) const + ir::node_data&& lhs, ir::node_data&& rhs, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const { - if (lhs.size() != rhs.size()) + if (lhs_localities.dimensions() < 1 || rhs_localities.dimensions() < 1) { HPX_THROW_EXCEPTION(hpx::bad_parameter, "dist_dot_operation::dot1d1d", generate_error_message( - "the operands have incompatible number of dimensions")); + "the operands have incompatible dimensionalities")); + } + + if (lhs_localities.size() != rhs_localities.size()) + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "dist_dot_operation::dot1d1d", + generate_error_message( + "the operands have incompatible size")); + } + + // construct a distributed vector object for the rhs + util::distributed_vector rhs_data( + rhs_localities.annotation_.name_, rhs.vector(), + rhs_localities.locality_.num_localities_, + rhs_localities.locality_.locality_id_); + + // use the local tile of lhs and calculate the dot product with all + // corresponding tiles of rhs + std::size_t lhs_span_index = 0; + if (!lhs_localities.has_span(0)) + { + HPX_ASSERT(lhs_localities.has_span(1)); + lhs_span_index = 1; + } + + tiling_span const& lhs_span = lhs_localities.get_span(lhs_span_index); + + // go over all tiles of rhs vector + T dot_result = T{0}; + + std::uint32_t loc = 0; + for (auto const& rhs_tile : rhs_localities.tiles_) + { + std::size_t rhs_span_index = 0; + if (!rhs_tile.spans_[0].is_valid()) + { + HPX_ASSERT(rhs_tile.spans_[1].is_valid()); + rhs_span_index = 1; + } + + tiling_span const& rhs_span = rhs_tile.spans_[rhs_span_index]; + + tiling_span intersection; + if (!intersect(lhs_span, rhs_span, intersection)) + { + ++loc; + continue; + } + + // project global coordinates onto local ones + tiling_span lhs_intersection = lhs_localities.project_coords( + lhs_localities.locality_.locality_id_, lhs_span_index, + intersection); + tiling_span rhs_intersection = + rhs_localities.project_coords(loc, rhs_span_index, intersection); + + if (rhs_localities.locality_.locality_id_ == loc) + { + // calculate the dot product with local tile + dot_result += T{blaze::dot( + blaze::subvector(lhs.vector(), lhs_intersection.start_, + lhs_intersection.stop_ - lhs_intersection.start_), + blaze::subvector(*rhs_data, rhs_intersection.start_, + rhs_intersection.stop_ - rhs_intersection.start_))}; + } + else + { + // calculate the dot product with remote tile + dot_result += T{blaze::dot( + blaze::subvector(lhs.vector(), lhs_intersection.start_, + lhs_intersection.stop_ - lhs_intersection.start_), + rhs_data.fetch(loc, rhs_intersection.start_, + rhs_intersection.stop_).get())}; + } + ++loc; + } + + // collect overall result if left hand side vector is distributed + if (lhs_localities.locality_.num_localities_ > 1) + { + lhs = hpx::all_reduce( + ("all_reduce_" + lhs_localities.annotation_.name_).c_str(), + dot_result, std::plus{}, + lhs_localities.locality_.num_localities_, std::size_t(-1), + lhs_localities.locality_.locality_id_) + .get(); + } + else + { + lhs = dot_result; } - // lhs.dimension(0) == rhs.dimension(0) - lhs = T(blaze::dot(lhs.vector(), rhs.vector())); return execution_tree::primitive_argument_type{std::move(lhs)}; } @@ -131,7 +236,9 @@ namespace phylanx { namespace dist_matrixops { namespace primitives // Case 3: Inner product of a matrix (tensor slice) template execution_tree::primitive_argument_type dist_dot_operation::dot1d( - ir::node_data&& lhs, ir::node_data&& rhs) const + ir::node_data&& lhs, ir::node_data&& rhs, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const { switch (rhs.num_dimensions()) { @@ -141,7 +248,8 @@ namespace phylanx { namespace dist_matrixops { namespace primitives case 1: // If is_vector(lhs) && is_vector(rhs) - return dot1d1d(std::move(lhs), std::move(rhs)); + return dot1d1d( + std::move(lhs), std::move(rhs), lhs_localities, rhs_localities); case 2: // If is_vector(lhs) && is_matrix(rhs) @@ -226,7 +334,9 @@ namespace phylanx { namespace dist_matrixops { namespace primitives // Regular matrix multiplication template execution_tree::primitive_argument_type dist_dot_operation::dot2d( - ir::node_data&& lhs, ir::node_data&& rhs) const + ir::node_data&& lhs, ir::node_data&& rhs, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const { switch (rhs.num_dimensions()) { @@ -324,7 +434,9 @@ namespace phylanx { namespace dist_matrixops { namespace primitives // lhs_num_dims == 3 template execution_tree::primitive_argument_type dist_dot_operation::dot3d( - ir::node_data&& lhs, ir::node_data&& rhs) const + ir::node_data&& lhs, ir::node_data&& rhs, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const { switch (rhs.num_dimensions()) { diff --git a/phylanx/plugins/dist_matrixops/dist_transpose_operation.hpp b/phylanx/plugins/dist_matrixops/dist_transpose_operation.hpp index dcad2c8ea..3f709b077 100644 --- a/phylanx/plugins/dist_matrixops/dist_transpose_operation.hpp +++ b/phylanx/plugins/dist_matrixops/dist_transpose_operation.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -56,8 +57,7 @@ namespace phylanx { namespace dist_matrixops { namespace primitives template execution_tree::primitive_argument_type transpose2d( - ir::node_data&& arg, execution_tree::annotation&& meta, - execution_tree::annotation&& locality_ann) const; + ir::node_data&& arg, localities_information&& localities) const; #if defined(PHYLANX_HAVE_BLAZE_TENSOR) execution_tree::primitive_argument_type transpose3d( @@ -68,13 +68,11 @@ namespace phylanx { namespace dist_matrixops { namespace primitives template execution_tree::primitive_argument_type transpose3d( - ir::node_data&& arg, execution_tree::annotation&& meta, - execution_tree::annotation&& locality_ann) const; + ir::node_data&& arg, localities_information&& localities) const; template execution_tree::primitive_argument_type transpose3d( ir::node_data&& arg, ir::node_data&& axes, - execution_tree::annotation&& meta, - execution_tree::annotation&& locality_ann) const; + localities_information&& localities) const; #endif }; diff --git a/phylanx/plugins/dist_matrixops/localities_annotation.hpp b/phylanx/plugins/dist_matrixops/localities_annotation.hpp new file mode 100644 index 000000000..7fb62a974 --- /dev/null +++ b/phylanx/plugins/dist_matrixops/localities_annotation.hpp @@ -0,0 +1,69 @@ +// Copyright (c) 2019 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(PHYLANX_PRIMITIVES_LOCALITIES_ANNOTATION_JUL_01_2019_1050AM) +#define PHYLANX_PRIMITIVES_LOCALITIES_ANNOTATION_JUL_01_2019_1050AM + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace phylanx { namespace dist_matrixops +{ + //////////////////////////////////////////////////////////////////////////// + struct localities_information + { + localities_information() = default; + + localities_information( + execution_tree::annotation const& ann, std::string const& name, + std::string const& codename); + + localities_information(std::size_t dim, + std::array const& dims); + + // extract dimensionality and sizes + std::size_t dimensions() const; + + std::size_t size() const; + + std::size_t pages() const; + std::size_t rows() const; + std::size_t columns() const; + + // extract local span + bool has_span(std::size_t dim) const; + tiling_span get_span(std::size_t dim) const; + + // project given (global) span onto local span + tiling_span project_coords( + std::uint32_t loc, std::size_t dim, tiling_span const& span) const; + +// execution_tree::annotation as_annotation( +// std::string const& name, std::string const& codename) const; + + execution_tree::locality_information locality_; + execution_tree::annotation_information annotation_; + std::vector tiles_; + }; + + localities_information extract_localities_information( + execution_tree::primitive_argument_type const& arg, + std::string const& name, std::string const& codename); +}} + +#endif + diff --git a/phylanx/plugins/dist_matrixops/tiling_annotations.hpp b/phylanx/plugins/dist_matrixops/tiling_annotations.hpp index 238be5c87..febc031fd 100644 --- a/phylanx/plugins/dist_matrixops/tiling_annotations.hpp +++ b/phylanx/plugins/dist_matrixops/tiling_annotations.hpp @@ -9,11 +9,13 @@ #include #include #include +#include #include +#include +#include #include #include -#include #include namespace phylanx { namespace dist_matrixops @@ -25,13 +27,76 @@ namespace phylanx { namespace dist_matrixops tiling_span(ir::range const& rhs, std::string const& name, std::string const& codename); + tiling_span(std::int64_t start, std::int64_t stop) + : start_(start), stop_(stop) + {} + + bool is_valid() const { return start_ < stop_; } std::int64_t start_ = 0; std::int64_t stop_ = 0; }; + // find intersection of two spans + inline bool intersect( + tiling_span const& lhs, tiling_span const& rhs, tiling_span& result) + { + if (lhs.start_ < rhs.stop_ && lhs.stop_ > rhs.start_) + { + result.start_ = (std::max)(lhs.start_, rhs.start_); + result.stop_ = (std::min)(lhs.stop_, rhs.stop_); + return true; + } + return false; + } + + namespace detail + { + tiling_span extract_span(execution_tree::annotation const& ann, + char const* key, std::string const& name, + std::string const& codename); + } + + //////////////////////////////////////////////////////////////////////////// + struct tiling_information + { + static char const* get_span_name(std::size_t i) + { + static const char* const names[] = {"columns", "rows", "pages"}; + return names[i]; + } + + tiling_information(execution_tree::annotation const& ann, + std::string const& name, std::string const& codename); + + tiling_information(std::size_t dim, + std::array const& dims); + + execution_tree::annotation as_annotation( + std::string const& name, std::string const& codename) const + { + execution_tree::annotation ann("tile"); + for (std::size_t i = 0; i != spans_.size(); ++i) + { + ann.add_annotation(get_span_name(i), + ir::range(spans_[i].start_, spans_[i].stop_), name, + codename); + } + return ann; + } + + // the number of annotations corresponds to the dimensionality of the + // described data + std::size_t dimensions() const + { + return spans_.size(); + } + + std::vector spans_; + }; + //////////////////////////////////////////////////////////////////////////// - struct tiling_annotations_1d + struct tiling_information_1d { enum tile1d_type { @@ -44,10 +109,14 @@ namespace phylanx { namespace dist_matrixops return t == columns ? "columns" : "rows"; } - tiling_annotations_1d(execution_tree::annotation const& ann, + tiling_information_1d(execution_tree::annotation const& ann, std::string const& name, std::string const& codename); - execution_tree::annotation as_annotation() const; + tiling_information_1d(tiling_information const& info, + std::string const& name, std::string const& codename); + + execution_tree::annotation as_annotation( + std::string const& name, std::string const& codename) const; void transpose(); @@ -56,35 +125,37 @@ namespace phylanx { namespace dist_matrixops }; //////////////////////////////////////////////////////////////////////////// - struct tiling_annotations_2d + struct tiling_information_2d { - tiling_annotations_2d(execution_tree::annotation const& ann, + tiling_information_2d(execution_tree::annotation const& ann, + std::string const& name, std::string const& codename); + + tiling_information_2d(tiling_information const& tile, std::string const& name, std::string const& codename); - execution_tree::annotation as_annotation() const; + execution_tree::annotation as_annotation( + std::string const& name, std::string const& codename) const; void transpose(); - tiling_span row_span_; - tiling_span column_span_; + tiling_span spans_[2]; }; //////////////////////////////////////////////////////////////////////////// - struct tiling_annotations_3d + struct tiling_information_3d { - tiling_annotations_3d(execution_tree::annotation const& ann, + tiling_information_3d(execution_tree::annotation const& ann, std::string const& name, std::string const& codename); - execution_tree::annotation as_annotation() const; + tiling_information_3d(tiling_information const& tile, + std::string const& name, std::string const& codename); + + execution_tree::annotation as_annotation( + std::string const& name, std::string const& codename) const; void transpose(std::int64_t const* data, std::size_t count); - void transpose(std::initializer_list data) - { - transpose(data.begin(), data.size()); - } tiling_span spans_[3]; - tiling_span column_span_; }; }} diff --git a/phylanx/util/distributed_object.hpp b/phylanx/util/distributed_object.hpp index b1dc6b31f..872ce221a 100644 --- a/phylanx/util/distributed_object.hpp +++ b/phylanx/util/distributed_object.hpp @@ -11,7 +11,6 @@ #include #include -#include #include #include #include @@ -24,7 +23,6 @@ #include #include #include -#include #include #include @@ -271,7 +269,7 @@ namespace phylanx { namespace util /// the symbolic name ~distributed_object() { - hpx::unregister_with_basename(basename_, this_site_); + hpx::unregister_with_basename(basename_, this_site_).get(); } /// Access the calling locality's value instance for this distributed_object @@ -349,7 +347,8 @@ namespace phylanx { namespace util { HPX_THROW_EXCEPTION(hpx::no_success, "distributed_object::get_part_id", - "attempting to access invalid part of the ditributed object"); + "attempting to access invalid part of the distributed " + "object"); } std::lock_guard l(part_ids_mtx_); @@ -508,7 +507,7 @@ namespace phylanx { namespace util hpx::local_new>( hpx::launch::sync, value); - hpx::register_with_basename(basename_, part_id, this_site_); + hpx::register_with_basename(basename_, part_id, this_site_).get(); part_ids_[this_site_] = part_id; ptr_ = hpx::get_ptr>( @@ -528,7 +527,8 @@ namespace phylanx { namespace util { HPX_THROW_EXCEPTION(hpx::no_success, "distributed_object::get_part_id", - "attempting to access invalid part of the ditributed object"); + "attempting to access invalid part of the distributed " + "object"); } std::lock_guard l(part_ids_mtx_); diff --git a/phylanx/util/distributed_vector.hpp b/phylanx/util/distributed_vector.hpp new file mode 100644 index 000000000..846af1503 --- /dev/null +++ b/phylanx/util/distributed_vector.hpp @@ -0,0 +1,357 @@ +// Copyright (c) 2019 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(PHYLANX_UTIL_DISTRIBUTED_VECTOR_HPP) +#define PHYLANX_UTIL_DISTRIBUTED_VECTOR_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/// \cond NOINTERNAL +namespace phylanx { namespace util { namespace server +{ + //////////////////////////////////////////////////////////////////////////// + template + class distributed_vector_part + : public hpx::components::component_base> + { + public: + using data_type = blaze::DynamicVector; + using reference_type = blaze::CustomVector; + + distributed_vector_part() = default; + + explicit distributed_vector_part(reference_type const& data) + : data_(data) + { + } + + explicit distributed_vector_part(reference_type&& data) + : data_(std::move(data)) + { + } + + reference_type& operator*() + { + return data_; + } + + reference_type const& operator*() const + { + return data_; + } + + reference_type* operator->() + { + return &data_; + } + + reference_type const* operator->() const + { + return &data_; + } + + data_type fetch() const + { + return data_; + } + + HPX_DEFINE_COMPONENT_ACTION(distributed_vector_part, fetch); + + data_type fetch_part(std::size_t start, std::size_t stop) const + { + return data_type{blaze::subvector(data_, start, stop-start)}; + } + + HPX_DEFINE_COMPONENT_ACTION(distributed_vector_part, fetch_part); + + private: + reference_type data_; + }; +}}} +/// \endcond + +#define REGISTER_DISTRIBUTED_VECTOR_DECLARATION(type) \ + HPX_REGISTER_ACTION_DECLARATION( \ + phylanx::util::server::distributed_vector_part::fetch_action, \ + HPX_PP_CAT(__distributed_vector_part_fetch_action_, type)); \ + HPX_REGISTER_ACTION_DECLARATION( \ + phylanx::util::server::distributed_vector_part< \ + type>::fetch_part_action, \ + HPX_PP_CAT(__distributed_vector_part_fetch_part_action_, type)) \ + /**/ + +#define REGISTER_DISTRIBUTED_VECTOR(type) \ + HPX_REGISTER_ACTION( \ + phylanx::util::server::distributed_vector_part::fetch_action, \ + HPX_PP_CAT(__distributed_vector_part_fetch_action_, type)); \ + HPX_REGISTER_ACTION(phylanx::util::server::distributed_vector_part:: \ + fetch_part_action, \ + HPX_PP_CAT(__distributed_vector_part_fetch_part_action_, type)); \ + typedef ::hpx::components::component< \ + phylanx::util::server::distributed_vector_part> \ + HPX_PP_CAT(__distributed_vector_part_, type); \ + HPX_REGISTER_COMPONENT(HPX_PP_CAT(__distributed_vector_part_, type)) \ + /**/ + +namespace phylanx { namespace util +{ + template + class distributed_vector + { + private: + using data_type = + typename server::distributed_vector_part::data_type; + using reference_type = + typename server::distributed_vector_part::reference_type; + + public: + /// Creates a distributed_vector in every locality + /// + /// A distributed_vector \a base_name is created through default + /// constructor. + distributed_vector() = default; + + /// Creates a distributed_vector in every locality with a given + /// base_name string, data, and a type and construction_type in the + /// template parameters. + /// + /// \param construction_type The construction_type in the template + /// parameters accepts either meta_object or all_to_all, + /// and it is set to all_to_all by default. The meta_object + /// option provides meta object registration in the root + /// locality and meta object is essentially a table that + /// can find the instances of distributed_vector in all + /// localities. The all_to_all option only locally holds + /// the client and server of the distributed_vector. + /// \param base_name The name of the distributed_vector, which should + /// be a unique string across the localities + /// \param data The data of the type T of the distributed_vector + /// \param sub_localities The sub_localities accepts a list of locality + /// index. By default, it is initialized to a list of all + /// provided locality index. + /// + distributed_vector(std::string basename, reference_type const& data, + std::size_t num_sites = std::size_t(-1), + std::size_t this_site = std::size_t(-1)) + : num_sites_(num_sites == std::size_t(-1) ? + hpx::get_num_localities(hpx::launch::sync) : + num_sites) + , this_site_(this_site == std::size_t(-1) ? hpx::get_locality_id() : + this_site) + , basename_("dist_vector_" + std::move(basename)) + { + if (this_site_ >= num_sites_) + { + HPX_THROW_EXCEPTION(hpx::no_success, + "distributed_vector::distributed_vector", + "attempting to construct invalid part of the " + "distributed object"); + } + create_and_register_server(data); + } + + /// Creates a distributed_vector in every locality with a given + /// base_name string, data, and a type and construction_type in the + /// template parameters + /// + /// \param construction_type The construction_type in the template + /// parameters accepts either meta_object or all_to_all, + /// and it is set to all_to_all by default. The meta_object + /// option provides meta object registration in the root + /// locality and meta object is essentially a table that + /// can find the instances of distributed_vector in all + /// localities. The all_to_all option only locally holds + /// the client and server of the distributed_vector. + /// \param base_name The name of the distributed_vector, which should + /// be a unique string across the localities + /// \param data The data of the type T of the distributed_vector + /// \param sub_localities The sub_localities accepts a list of locality + /// index. By default, it is initialized to a list of all + /// provided locality index. + /// + distributed_vector(std::string basename, reference_type&& data, + std::size_t num_sites = std::size_t(-1), + std::size_t this_site = std::size_t(-1)) + : num_sites_(num_sites == std::size_t(-1) ? + hpx::get_num_localities(hpx::launch::sync) : + num_sites) + , this_site_(this_site == std::size_t(-1) ? hpx::get_locality_id() : + this_site) + , basename_("dist_vector_" + std::move(basename)) + { + if (this_site_ >= num_sites_) + { + HPX_THROW_EXCEPTION(hpx::no_success, + "distributed_vector::distributed_vector", + "attempting to construct invalid part of the " + "distributed object"); + } + create_and_register_server(std::move(data)); + } + + /// Destroy the local reference to the distributed object, unregister + /// the symbolic name + ~distributed_vector() + { + hpx::unregister_with_basename(basename_, this_site_).get(); + } + + /// Access the calling locality's value instance for this distributed_vector + reference_type& operator*() + { + HPX_ASSERT(!!ptr_); + return **ptr_; + } + + /// Access the calling locality's value instance for this distributed_vector + reference_type const& operator*() const + { + HPX_ASSERT(!!ptr_); + return **ptr_; + } + + /// Access the calling locality's value instance for this distributed_vector + reference_type* operator->() + { + HPX_ASSERT(!!ptr_); + return &**ptr_; + } + + /// Access the calling locality's value instance for this distributed_vector + reference_type const* operator->() const + { + HPX_ASSERT(!!ptr_); + return &**ptr_; + } + + /// fetch() function is an asynchronous function. This returns a future + /// of a copy of the instance of this distributed_vector associated with + /// the given locality index. The provided locality index must be valid + /// within the sub localities where this distributed object is + /// constructed. Also, if the provided locality index is same as current + /// locality, fetch function still returns a future of it local data copy. + /// It is suggested to use star operator to access local data. + hpx::future fetch(std::size_t idx) const + { + /// \cond NOINTERNAL + HPX_ASSERT(!!ptr_); + using action_type = + typename server::distributed_vector_part::fetch_action; + + return hpx::async(get_part_id(idx)); + /// \endcond + } + + /// fetch() function is an asynchronous function. This returns a future + /// of (part of) a copy of the instance of this distributed_vector + /// associated with the given locality index. The provided locality + /// index must be valid within the sub localities where this distributed + /// object is constructed. Also, if the provided locality index is same + /// as current locality, fetch function still returns a future of it + /// local data copy. + /// It is suggested to use star operator to access local data. + hpx::future fetch( + std::size_t idx, std::size_t start, std::size_t stop) const + { + /// \cond NOINTERNAL + HPX_ASSERT(!!ptr_); + using action_type = + typename server::distributed_vector_part::fetch_part_action; + + return hpx::async(get_part_id(idx), start, stop); + /// \endcond + } + + private: + /// \cond NOINTERNAL + template + hpx::id_type create_and_register_server(Arg&& value) + { + // create new distributed_vector component and register it with AGAS + hpx::id_type part_id = + hpx::local_new>( + hpx::launch::sync, std::forward(value)); + + hpx::register_with_basename(basename_, part_id, this_site_).get(); + + part_ids_[this_site_] = part_id; + ptr_ = hpx::get_ptr>( + hpx::launch::sync, part_id); + + return part_id; + } + + hpx::id_type const& get_part_id(std::size_t idx) const + { + if (idx == this_site_) + { + return part_ids_[idx]; + } + + if (idx >= num_sites_) + { + HPX_THROW_EXCEPTION(hpx::no_success, + "distributed_vector::get_part_id", + "attempting to access invalid part of the distributed " + "vector"); + } + + std::lock_guard l(part_ids_mtx_); + auto it = part_ids_.find(idx); + if (it == part_ids_.end()) + { + hpx::id_type id; + + { + hpx::util::unlock_guard ul( + part_ids_mtx_); + + id = hpx::agas::on_symbol_namespace_event( + hpx::detail::name_from_basename(basename_, idx), true).get(); + } + + it = part_ids_.find(idx); + if (it == part_ids_.end()) + { + it = part_ids_.emplace(idx, std::move(id)).first; + } + } + return it->second; + } + + private: + std::size_t const num_sites_; + std::size_t const this_site_; + std::string const basename_; + std::shared_ptr> ptr_; + + mutable hpx::lcos::local::spinlock part_ids_mtx_; + mutable std::map part_ids_; + /// \endcond + }; +}} + +#endif diff --git a/phylanx/util/repr_manip.hpp b/phylanx/util/repr_manip.hpp index fc1105bad..a4d5439c4 100644 --- a/phylanx/util/repr_manip.hpp +++ b/phylanx/util/repr_manip.hpp @@ -22,6 +22,7 @@ namespace phylanx { namespace util ~repr_wrapper(); std::ostream& strm_; + bool has_repr_; }; }} diff --git a/src/execution_tree/annotation.cpp b/src/execution_tree/annotation.cpp index 386842cd7..b54feb91d 100644 --- a/src/execution_tree/annotation.cpp +++ b/src/execution_tree/annotation.cpp @@ -10,11 +10,13 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -80,6 +82,18 @@ namespace phylanx { namespace execution_tree return false; } + bool annotation::get_if(std::string const& key, + execution_tree::annotation& ann, std::string const& name, + std::string const& codename) const + { + if (get_type() != key) + { + return false; + } + ann = get_range_ref(); + return true; + } + bool annotation::has_key(std::string const& key, std::string const& name, std::string const& codename) const { @@ -120,13 +134,28 @@ namespace phylanx { namespace execution_tree { newdata.emplace_back(std::move(val)); } - newdata.emplace_back(ir::range(key, data.copy())); + + if (data.is_ref()) + { + newdata.emplace_back(ir::range(key, data.copy())); + } + else + { + newdata.emplace_back(ir::range(key, std::move(data))); + } data_ = std::move(newdata); } else { - data_.args().emplace_back(ir::range(key, data.copy())); + if (data.is_ref()) + { + data_.args().emplace_back(ir::range(key, data.copy())); + } + else + { + data_.args().emplace_back(ir::range(key, std::move(data))); + } } } @@ -151,13 +180,13 @@ namespace phylanx { namespace execution_tree { newdata.emplace_back(std::move(val)); } - newdata.emplace_back(data.get_range()); + newdata.emplace_back(std::move(data.get_range())); data_ = std::move(newdata); } else { - data_.args().emplace_back(data.get_range()); + data_.args().emplace_back(std::move(data.get_range())); } } @@ -220,6 +249,8 @@ namespace phylanx { namespace execution_tree //////////////////////////////////////////////////////////////////////////// std::ostream& operator<<(std::ostream& os, annotation const& ann) { + util::repr_wrapper wrap(os); + os << "annotation("; bool first = true; for (auto const& elem : ann.get_range_ref()) @@ -234,5 +265,72 @@ namespace phylanx { namespace execution_tree os << ")"; return os; } + + //////////////////////////////////////////////////////////////////////////// + annotation_information::annotation_information(annotation const& ann, + std::string const& name, std::string const& codename) + { + auto&& key = ann.get_type(name, codename); + if (key != "name") + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "annotation_information::annotation_information", + util::generate_error_message( + hpx::util::format("unexpected annotation type ({})", key), + name, codename)); + } + + auto it = ann.get_data().begin(); + + name_ = execution_tree::extract_string_value_strict( + *(ann.get_data().begin()), name, codename); + + extract_from_name(); + } + + annotation_information::annotation_information( + std::string name, std::int64_t generation) + : name_(std::move(name)) + , generation_(generation) + { + extract_from_name(); + } + + void annotation_information::extract_from_name() + { + auto p = name_.find_last_of("/"); + if (p != std::string::npos && std::isdigit(name_[p + 1])) + { + generation_ = std::stoll(name_.substr(p + 1)); + name_ = name_.erase(p); + } + } + + std::string annotation_information::generate_name() const + { + return hpx::util::format("{}/{}", name_, generation_); + } + + annotation annotation_information::as_annotation() const + { + return annotation("name", generate_name()); + } + + //////////////////////////////////////////////////////////////////////////// + annotation_information extract_annotation_information( + annotation const& ann, std::string const& name, + std::string const& codename) + { + execution_tree::annotation name_ann; + if (!ann.get_if("name", name_ann, name, codename) && + !ann.find("name", name_ann, name, codename)) + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "extract_localities_information", + util::generate_error_message( + "'localities' annotation type not given", name, codename)); + } + return annotation_information(name_ann, name, codename); + } }} diff --git a/src/execution_tree/locality_annotation.cpp b/src/execution_tree/locality_annotation.cpp index e02af4828..e5edf5b5f 100644 --- a/src/execution_tree/locality_annotation.cpp +++ b/src/execution_tree/locality_annotation.cpp @@ -44,19 +44,29 @@ namespace phylanx { namespace execution_tree extract_scalar_integer_value(*++it, name, codename)); } - locality_information extract_locality_information( - execution_tree::annotation const& ann, std::string const& name, - std::string const& codename) + execution_tree::annotation locality_information::as_annotation() const { - if (ann.get_type() != "locality") + return execution_tree::annotation( + "locality", static_cast(locality_id_), + static_cast(num_localities_)); + } + + //////////////////////////////////////////////////////////////////////////// + locality_information + extract_locality_information(execution_tree::annotation const& ann, + std::string const& name, std::string const& codename) + { + execution_tree::annotation locality; + if (!ann.get_if("locality", locality, name, codename) && + !ann.find("locality", locality, name, codename)) { HPX_THROW_EXCEPTION(hpx::bad_parameter, - "detail::extract_locality_information", + "execution_tree::extract_locality_information", util::generate_error_message( "'locality' annotation type not given", name, codename)); } - return locality_information(ann.get_data(), name, codename); + return locality_information(locality.get_data(), name, codename); } }} diff --git a/src/execution_tree/meta_annotation.cpp b/src/execution_tree/meta_annotation.cpp index 85e1f952f..9481f847d 100644 --- a/src/execution_tree/meta_annotation.cpp +++ b/src/execution_tree/meta_annotation.cpp @@ -26,14 +26,16 @@ namespace phylanx { namespace execution_tree { //////////////////////////////////////////////////////////////////////////// hpx::future meta_annotation(annotation const& locality_ann, - annotation&& ann, std::string const& name, std::string const& codename) + annotation&& ann, std::string const& ann_name, + std::string const& name, std::string const& codename) { locality_information locality_info = extract_locality_information(locality_ann, name, codename); - hpx::future> f = hpx::all_to_all(name.c_str(), - std::move(ann), locality_info.num_localities_, std::size_t(-1), - locality_info.locality_id_); + hpx::future> f = + hpx::all_to_all(("all_to_all_" + ann_name).c_str(), std::move(ann), + locality_info.num_localities_, std::size_t(-1), + locality_info.locality_id_); return f.then(hpx::launch::sync, [](hpx::future>&& f) -> annotation @@ -56,10 +58,11 @@ namespace phylanx { namespace execution_tree annotation meta_annotation(hpx::launch::sync_policy, annotation const& locality_ann, annotation&& ann, - std::string const& name, std::string const& codename) + std::string const& ann_name, std::string const& name, + std::string const& codename) { - return meta_annotation(locality_ann, std::move(ann), name, codename) - .get(); + return meta_annotation( + locality_ann, std::move(ann), ann_name, name, codename).get(); } //////////////////////////////////////////////////////////////////////////// @@ -83,7 +86,8 @@ namespace phylanx { namespace execution_tree // ) // annotation localities_annotation(annotation& locality_ann, - annotation&& ann, std::string const& name, std::string const& codename) + annotation&& ann, annotation_information const& ann_info, + std::string const& name, std::string const& codename) { // defaults to locality_id and num_localities execution_tree::locality_information loc; @@ -92,7 +96,7 @@ namespace phylanx { namespace execution_tree // locality of the data we should perform an all_to_all // operation to collect the information about all connected // objects. - if (ann.find("locality", locality_ann, name, codename)) + if (locality_ann.get_type() == "locality") { loc = execution_tree::extract_locality_information( locality_ann, name, codename); @@ -114,10 +118,15 @@ namespace phylanx { namespace execution_tree // communicate with all other localities to generate set of all meta // entries auto localities_ann = meta_annotation(hpx::launch::sync, locality_ann, - std::move(meta_locality_ann), name, codename); + std::move(meta_locality_ann), ann_info.generate_name(), name, + codename); // now generate the overall annotation localities_ann.add_annotation(std::move(locality_ann), name, codename); + + // attach globally unique name to returned annotation + localities_ann.add_annotation(ann_info.as_annotation(), name, codename); + return localities_ann; } }} diff --git a/src/execution_tree/primitives/annotate_primitive.cpp b/src/execution_tree/primitives/annotate_primitive.cpp index 6a76096d7..526a75c8d 100644 --- a/src/execution_tree/primitives/annotate_primitive.cpp +++ b/src/execution_tree/primitives/annotate_primitive.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -36,13 +37,13 @@ namespace phylanx { namespace execution_tree { namespace primitives } //////////////////////////////////////////////////////////////////////////// - constexpr const char* const helpstring = R"( + constexpr const char* const annotate_helpstring = R"( target, args Args: target : the value that has to be annotated - *args (arg list) : a list of arguments + *args (arg list) : an optional list of annotations (default is `None`) Returns: @@ -55,17 +56,32 @@ namespace phylanx { namespace execution_tree { namespace primitives "annotate(_1_target, __arg(_2_args, nil))" }, &create_annotate, &create_primitive, - helpstring) + annotate_helpstring) }; + constexpr const char* const annotate_d_helpstring = R"( + target, name, args + + Args: + + target : the value that has to be annotated + name : a unique string identifying the annotated object across + localities + *args (arg list) : an optional list of annotations (default is `None`) + + Returns: + + The `target` annotated with the list of values given by `*args`. The + `target` is also identified by the given `name` across localities.)"; + match_pattern_type const annotate_primitive::match_data_annotate_d = { hpx::util::make_tuple("annotate_d", std::vector{ - "annotate_d(_1_target, __arg(_2_args, nil))" + "annotate_d(_1_target, _2_name, __arg(_3_args, nil))" }, &create_annotate, &create_primitive, - helpstring) + annotate_d_helpstring) }; //////////////////////////////////////////////////////////////////////////// @@ -87,29 +103,28 @@ namespace phylanx { namespace execution_tree { namespace primitives //////////////////////////////////////////////////////////////////////////// primitive_argument_type annotate_primitive::annotate_d( - primitive_argument_type&& target, ir::range&& args) const + primitive_argument_type&& target, std::string&& ann_name, + ir::range&& args) const { // retrieve local annotation and generate the overall annotation + annotation_information ann_info{std::move(ann_name), 0ll}; annotation locality_ann; - auto localities = localities_annotation( - locality_ann, annotation{std::move(args)}, name_, codename_); + auto localities = localities_annotation(locality_ann, + annotation{std::move(args)}, ann_info, name_, codename_); target.set_annotation(std::move(localities), name_, codename_); return std::move(target); } //////////////////////////////////////////////////////////////////////////// - hpx::future annotate_primitive::eval( + hpx::future annotate_primitive::eval_annotate( primitive_arguments_type const& operands, primitive_arguments_type const& args, eval_context ctx) const { - // operands_[0] is expected to be the target, - // operands_[1] is a list of arguments used for annotation - if (operands.size() != 2) { HPX_THROW_EXCEPTION(hpx::bad_parameter, - "annotate_primitive::annotate", + "annotate_primitive::eval_annotate", generate_error_message( "the annotate primitive requires two operands")); } @@ -123,14 +138,54 @@ namespace phylanx { namespace execution_tree { namespace primitives hpx::future&& args) -> primitive_argument_type { - if (this_->func_name_ == "annotate_d") - { - return this_->annotate_d(target.get(), args.get()); - } return this_->annotate(target.get(), args.get()); }, std::move(f), list_operand(operands[1], args, name_, codename_, std::move(ctx))); } + + hpx::future annotate_primitive::eval_annotate_d( + primitive_arguments_type const& operands, + primitive_arguments_type const& args, eval_context ctx) const + { + if (operands.size() != 3) + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "annotate_primitive::eval_annotate_d", + generate_error_message( + "the annotate primitive requires three operands")); + } + + auto ftarget = value_operand(operands[0], args, name_, codename_, ctx); + auto fname = string_operand(operands[1], args, name_, codename_, ctx); + + auto this_ = this->shared_from_this(); + return hpx::dataflow(hpx::launch::sync, + [this_ = std::move(this_)]( + hpx::future&& target, + hpx::future&& name, + hpx::future&& args) + -> primitive_argument_type + { + return this_->annotate_d(target.get(), name.get(), args.get()); + }, + std::move(ftarget), std::move(fname), + list_operand(operands[2], args, name_, codename_, std::move(ctx))); + } + + hpx::future annotate_primitive::eval( + primitive_arguments_type const& operands, + primitive_arguments_type const& args, eval_context ctx) const + { + // operands_[0] is expected to be the target, + // operands_[1] is a list of arguments used for annotation + + if (func_name_ == "annotate_d") + { + return eval_annotate_d(operands, args, std::move(ctx)); + } + + return eval_annotate(operands, args, std::move(ctx)); + } }}} diff --git a/src/ir/ranges.cpp b/src/ir/ranges.cpp index 4b28c3102..46d0ef655 100644 --- a/src/ir/ranges.cpp +++ b/src/ir/ranges.cpp @@ -628,14 +628,14 @@ namespace phylanx { namespace ir { int_range_type& int_range = util::get<0>(data_); ar << int_range.start() << int_range.stop() << int_range.step(); - break; } + break; case 1: // wrapped_args_type { ar << util::get<1>(data_); - break; } + break; case 2: // arg_pair_type { @@ -644,16 +644,16 @@ namespace phylanx { namespace ir m.reserve(size()); std::copy(p.first, p.second, std::back_inserter(m)); ar << m; - break; } + break; default: + HPX_THROW_EXCEPTION(hpx::invalid_status, + "phylanx::ir::range::serialize()", + "range object holds unsupported data type"); break; } - HPX_THROW_EXCEPTION(hpx::invalid_status, - "phylanx::ir::range::serialize()", - "range object holds unsupported data type"); } void range::serialize(hpx::serialization::input_archive& ar, unsigned) { @@ -667,8 +667,8 @@ namespace phylanx { namespace ir std::int64_t start, stop, step; ar >> start >> stop >> step; data_ = int_range_type{start, stop, step}; - break; } + break; case 1: // wrapped_args_type case 2: // arg_pair_type (serialized as wrapped_args_type) @@ -676,13 +676,14 @@ namespace phylanx { namespace ir args_type m; ar >> m; data_ = std::move(m); - break; } + break; default: HPX_THROW_EXCEPTION(hpx::invalid_status, "phylanx::ir::range::serialize()", "range object holds unsupported data type"); + break; } } }} diff --git a/src/plugins/dist_matrixops/dist_dot_operation.cpp b/src/plugins/dist_matrixops/dist_dot_operation.cpp index 42f7533e0..aa4ed7ce3 100644 --- a/src/plugins/dist_matrixops/dist_dot_operation.cpp +++ b/src/plugins/dist_matrixops/dist_dot_operation.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -109,23 +110,31 @@ namespace phylanx { namespace dist_matrixops { namespace primitives std::move(lhs), std::move(rhs), name_, codename_); } + localities_information lhs_localities = + extract_localities_information(lhs, name_, codename_); + localities_information rhs_localities = + extract_localities_information(rhs, name_, codename_); + switch (extract_common_type(lhs, rhs)) { case node_data_type_bool: return dot1d( extract_boolean_value(std::move(lhs), name_, codename_), - extract_boolean_value(std::move(rhs), name_, codename_)); + extract_boolean_value(std::move(rhs), name_, codename_), + lhs_localities, rhs_localities); case node_data_type_int64: return dot1d( extract_integer_value(std::move(lhs), name_, codename_), - extract_integer_value(std::move(rhs), name_, codename_)); + extract_integer_value(std::move(rhs), name_, codename_), + lhs_localities, rhs_localities); case node_data_type_unknown: HPX_FALLTHROUGH; case node_data_type_double: return dot1d( extract_numeric_value(std::move(lhs), name_, codename_), - extract_numeric_value(std::move(rhs), name_, codename_)); + extract_numeric_value(std::move(rhs), name_, codename_), + lhs_localities, rhs_localities); default: break; @@ -150,23 +159,31 @@ namespace phylanx { namespace dist_matrixops { namespace primitives std::move(lhs), std::move(rhs), name_, codename_); } + localities_information lhs_localities = + extract_localities_information(lhs, name_, codename_); + localities_information rhs_localities = + extract_localities_information(rhs, name_, codename_); + switch (extract_common_type(lhs, rhs)) { case node_data_type_bool: return dot2d( extract_boolean_value(std::move(lhs), name_, codename_), - extract_boolean_value(std::move(rhs), name_, codename_)); + extract_boolean_value(std::move(rhs), name_, codename_), + lhs_localities, rhs_localities); case node_data_type_int64: return dot2d( extract_integer_value(std::move(lhs), name_, codename_), - extract_integer_value(std::move(rhs), name_, codename_)); + extract_integer_value(std::move(rhs), name_, codename_), + lhs_localities, rhs_localities); case node_data_type_unknown: HPX_FALLTHROUGH; case node_data_type_double: return dot2d( extract_numeric_value(std::move(lhs), name_, codename_), - extract_numeric_value(std::move(rhs), name_, codename_)); + extract_numeric_value(std::move(rhs), name_, codename_), + lhs_localities, rhs_localities); default: break; @@ -192,23 +209,31 @@ namespace phylanx { namespace dist_matrixops { namespace primitives std::move(lhs), std::move(rhs), name_, codename_); } + localities_information lhs_localities = + extract_localities_information(lhs, name_, codename_); + localities_information rhs_localities = + extract_localities_information(rhs, name_, codename_); + switch (extract_common_type(lhs, rhs)) { case node_data_type_bool: return dot3d( extract_boolean_value(std::move(lhs), name_, codename_), - extract_boolean_value(std::move(rhs), name_, codename_)); + extract_boolean_value(std::move(rhs), name_, codename_), + lhs_localities, rhs_localities); case node_data_type_int64: return dot3d( extract_integer_value(std::move(lhs), name_, codename_), - extract_integer_value(std::move(rhs), name_, codename_)); + extract_integer_value(std::move(rhs), name_, codename_), + lhs_localities, rhs_localities); case node_data_type_unknown: HPX_FALLTHROUGH; case node_data_type_double: return dot3d( extract_numeric_value(std::move(lhs), name_, codename_), - extract_numeric_value(std::move(rhs), name_, codename_)); + extract_numeric_value(std::move(rhs), name_, codename_), + lhs_localities, rhs_localities); default: break; diff --git a/src/plugins/dist_matrixops/dist_dot_operation_double.cpp b/src/plugins/dist_matrixops/dist_dot_operation_double.cpp index 007ae322e..00451c963 100644 --- a/src/plugins/dist_matrixops/dist_dot_operation_double.cpp +++ b/src/plugins/dist_matrixops/dist_dot_operation_double.cpp @@ -9,6 +9,7 @@ #include #include #include +#include /////////////////////////////////////////////////////////////////////////////// namespace phylanx { namespace dist_matrixops { namespace primitives @@ -20,13 +21,19 @@ namespace phylanx { namespace dist_matrixops { namespace primitives ir::node_data&&, ir::node_data&&) const; template execution_tree::primitive_argument_type dist_dot_operation::dot1d( - ir::node_data&&, ir::node_data&&) const; + ir::node_data&&, ir::node_data&&, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const; template execution_tree::primitive_argument_type dist_dot_operation::dot2d( - ir::node_data&&, ir::node_data&&) const; + ir::node_data&&, ir::node_data&&, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const; #if defined(PHYLANX_HAVE_BLAZE_TENSOR) template execution_tree::primitive_argument_type dist_dot_operation::dot3d( - ir::node_data&&, ir::node_data&&) const; + ir::node_data&&, ir::node_data&&, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const; #endif }}} diff --git a/src/plugins/dist_matrixops/dist_dot_operation_int64.cpp b/src/plugins/dist_matrixops/dist_dot_operation_int64.cpp index ca94f6c41..e8873425c 100644 --- a/src/plugins/dist_matrixops/dist_dot_operation_int64.cpp +++ b/src/plugins/dist_matrixops/dist_dot_operation_int64.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -22,13 +23,19 @@ namespace phylanx { namespace dist_matrixops { namespace primitives ir::node_data&&, ir::node_data&&) const; template execution_tree::primitive_argument_type dist_dot_operation::dot1d( - ir::node_data&&, ir::node_data&&) const; + ir::node_data&&, ir::node_data&&, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const; template execution_tree::primitive_argument_type dist_dot_operation::dot2d( - ir::node_data&&, ir::node_data&&) const; + ir::node_data&&, ir::node_data&&, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const; #if defined(PHYLANX_HAVE_BLAZE_TENSOR) template execution_tree::primitive_argument_type dist_dot_operation::dot3d( - ir::node_data&&, ir::node_data&&) const; + ir::node_data&&, ir::node_data&&, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const; #endif }}} diff --git a/src/plugins/dist_matrixops/dist_dot_operation_uint8.cpp b/src/plugins/dist_matrixops/dist_dot_operation_uint8.cpp index d0a97d3e1..9ac786688 100644 --- a/src/plugins/dist_matrixops/dist_dot_operation_uint8.cpp +++ b/src/plugins/dist_matrixops/dist_dot_operation_uint8.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -22,13 +23,19 @@ namespace phylanx { namespace dist_matrixops { namespace primitives ir::node_data&&, ir::node_data&&) const; template execution_tree::primitive_argument_type dist_dot_operation::dot1d( - ir::node_data&&, ir::node_data&&) const; + ir::node_data&&, ir::node_data&&, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const; template execution_tree::primitive_argument_type dist_dot_operation::dot2d( - ir::node_data&&, ir::node_data&&) const; + ir::node_data&&, ir::node_data&&, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const; #if defined(PHYLANX_HAVE_BLAZE_TENSOR) template execution_tree::primitive_argument_type dist_dot_operation::dot3d( - ir::node_data&&, ir::node_data&&) const; + ir::node_data&&, ir::node_data&&, + localities_information const& lhs_localities, + localities_information const& rhs_localities) const; #endif }}} diff --git a/src/plugins/dist_matrixops/dist_transpose_operation.cpp b/src/plugins/dist_matrixops/dist_transpose_operation.cpp index b528cfc04..849090cda 100644 --- a/src/plugins/dist_matrixops/dist_transpose_operation.cpp +++ b/src/plugins/dist_matrixops/dist_transpose_operation.cpp @@ -5,13 +5,14 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include #include #include #include #include +#include #include #include +#include #include #include @@ -119,77 +120,84 @@ namespace phylanx { namespace dist_matrixops { namespace primitives } /////////////////////////////////////////////////////////////////////////// + namespace detail + { + execution_tree::annotation tiling_1d_annotation( + localities_information&& localities, std::string const& name, + std::string const& codename) + { + tiling_information_1d tile_info( + localities.tiles_[localities.locality_.locality_id_], + name, codename); + tile_info.transpose(); + ++localities.annotation_.generation_; + + return execution_tree::localities_annotation( + localities.locality_.as_annotation(), + tile_info.as_annotation(name, codename), + localities.annotation_, name, codename); + } + } + execution_tree::primitive_argument_type dist_transpose_operation::transpose1d( execution_tree::primitive_argument_type&& arg) const { - std::string meta_tag = - hpx::util::format("meta_{}", hpx::get_locality_id()); - - execution_tree::annotation meta; - if (!arg.get_annotation_if(meta_tag, meta, name_, codename_) && - !arg.find_annotation(meta_tag, meta, name_, codename_)) + execution_tree::annotation loc_ann; + if (!arg.get_annotation_if("localities", loc_ann, name_, codename_) && + !arg.find_annotation("localities", loc_ann, name_, codename_)) { return common::transpose0d1d(std::move(arg)); } - execution_tree::annotation locality_ann; - if (!arg.find_annotation("locality", locality_ann, name_, codename_)) - { - HPX_THROW_EXCEPTION(hpx::bad_parameter, - "dist_transpose_operation::transpose1d", - generate_error_message( - "meta annotation does not hold any locality annotation")); - } - - execution_tree::annotation tile_ann; - if (!meta.find("tile", tile_ann, name_, codename_)) - { - HPX_THROW_EXCEPTION(hpx::bad_parameter, - "dist_transpose_operation::transpose1d", - generate_error_message( - "meta annotation does not hold any tiling annotation")); - } - // construct new tiling annotation - tiling_annotations_1d tile_info(tile_ann, name_, codename_); - tile_info.transpose(); - arg.set_annotation( - execution_tree::localities_annotation( - locality_ann, tile_info.as_annotation(), name_, codename_), + detail::tiling_1d_annotation( + extract_localities_information(arg, name_, codename_), + name_, codename_), name_, codename_); return std::move(arg); } /////////////////////////////////////////////////////////////////////////// - template - execution_tree::primitive_argument_type - dist_transpose_operation::transpose2d(ir::node_data&& arg, - execution_tree::annotation&& meta, - execution_tree::annotation&& locality_ann) const + namespace detail { - execution_tree::annotation tile_ann; - if (!meta.find("tile", tile_ann, name_, codename_)) + execution_tree::annotation tiling_2d_annotation( + localities_information&& localities, bool transpose, std::string const& name, + std::string const& codename) { - HPX_THROW_EXCEPTION(hpx::bad_parameter, - "dist_transpose_operation::transpose2d", - generate_error_message( - "meta annotation does not hold any tiling annotation")); + tiling_information_2d tile_info( + localities.tiles_[localities.locality_.locality_id_], + name, codename); + if (transpose) + { + tile_info.transpose(); + } + + ++localities.annotation_.generation_; + + return execution_tree::localities_annotation( + localities.locality_.as_annotation(), + tile_info.as_annotation(name, codename), + localities.annotation_, name, codename); } + } + template + execution_tree::primitive_argument_type + dist_transpose_operation::transpose2d(ir::node_data&& arg, + localities_information&& localities) const + { // perform actual operation arg = blaze::trans(arg.matrix()); - // construct new tiling annotation - tiling_annotations_2d tile_info(tile_ann, name_, codename_); - tile_info.transpose(); - execution_tree::primitive_argument_type result{std::move(arg)}; + + // construct new tiling annotation result.set_annotation( - execution_tree::localities_annotation( - locality_ann, tile_info.as_annotation(), name_, codename_), + detail::tiling_2d_annotation( + std::move(localities), true, name_, codename_), name_, codename_); return result; @@ -201,42 +209,33 @@ namespace phylanx { namespace dist_matrixops { namespace primitives { using namespace execution_tree; - std::string meta_tag = - hpx::util::format("meta_{}", hpx::get_locality_id()); - - execution_tree::annotation meta; - if (!arg.get_annotation_if(meta_tag, meta, name_, codename_) && - !arg.find_annotation(meta_tag, meta, name_, codename_)) + execution_tree::annotation localities; + if (!arg.get_annotation_if("localities", localities, name_, codename_) && + !arg.find_annotation("localities", localities, name_, codename_)) { return common::transpose2d(std::move(arg), name_, codename_); } - execution_tree::annotation locality_ann; - if (!arg.find_annotation("locality", locality_ann, name_, codename_)) - { - HPX_THROW_EXCEPTION(hpx::bad_parameter, - "dist_transpose_operation::transpose2d", - generate_error_message( - "meta annotation does not hold any locality annotation")); - } + auto localities_info = + extract_localities_information(arg, name_, codename_); switch (extract_common_type(arg)) { case node_data_type_bool: return transpose2d( extract_boolean_value_strict(std::move(arg), name_, codename_), - std::move(meta), std::move(locality_ann)); + std::move(localities_info)); case node_data_type_int64: return transpose2d( extract_integer_value_strict(std::move(arg), name_, codename_), - std::move(meta), std::move(locality_ann)); + std::move(localities_info)); case node_data_type_unknown: HPX_FALLTHROUGH; case node_data_type_double: return transpose2d( extract_numeric_value(std::move(arg), name_, codename_), - std::move(meta), std::move(locality_ann)); + std::move(localities_info)); default: break; @@ -246,7 +245,7 @@ namespace phylanx { namespace dist_matrixops { namespace primitives "dist_transpose_operation::transpose2d", generate_error_message( "the transpose primitive requires for its argument to " - "be numeric data type")); + "be a numeric data type")); } execution_tree::primitive_argument_type @@ -263,29 +262,23 @@ namespace phylanx { namespace dist_matrixops { namespace primitives axis += 2; } - if (v[0] == 0 && v[1] == 1) + execution_tree::annotation localities; + if (!arg.get_annotation_if("localities", localities, name_, codename_) && + !arg.find_annotation("localities", localities, name_, codename_)) { - return std::move(arg); // no-op + return common::transpose2d(std::move(arg), name_, codename_); } - std::string meta_tag = - hpx::util::format("meta_{}", hpx::get_locality_id()); - - execution_tree::annotation meta; - if (!arg.get_annotation_if(meta_tag, meta, name_, codename_) && - !arg.find_annotation(meta_tag, meta, name_, codename_)) - { - return common::transpose2d( - std::move(arg), std::move(axes), name_, codename_); - } + auto localities_info = + extract_localities_information(arg, name_, codename_); - execution_tree::annotation locality_ann; - if (!arg.find_annotation("locality", locality_ann, name_, codename_)) + if (v[0] == 0 && v[1] == 1) { - HPX_THROW_EXCEPTION(hpx::bad_parameter, - "dist_transpose_operation::transpose2d", - generate_error_message( - "meta annotation does not hold any locality annotation")); + arg.set_annotation( + detail::tiling_2d_annotation( + std::move(localities_info), false, name_, codename_), + name_, codename_); + return std::move(arg); // no-op } switch (extract_common_type(arg)) @@ -293,18 +286,18 @@ namespace phylanx { namespace dist_matrixops { namespace primitives case node_data_type_bool: return transpose2d( extract_boolean_value_strict(std::move(arg), name_, codename_), - std::move(meta), std::move(locality_ann)); + std::move(localities_info)); case node_data_type_int64: return transpose2d( extract_integer_value_strict(std::move(arg), name_, codename_), - std::move(meta), std::move(locality_ann)); + std::move(localities_info)); case node_data_type_unknown: HPX_FALLTHROUGH; case node_data_type_double: return transpose2d( extract_numeric_value(std::move(arg), name_, codename_), - std::move(meta), std::move(locality_ann)); + std::move(localities_info)); default: break; @@ -314,37 +307,47 @@ namespace phylanx { namespace dist_matrixops { namespace primitives "dist_transpose_operation::transpose2d", generate_error_message( "the transpose primitive requires for its argument to " - "be numeric data type")); + "be a numeric data type")); } /////////////////////////////////////////////////////////////////////////// #if defined(PHYLANX_HAVE_BLAZE_TENSOR) + namespace detail + { + execution_tree::annotation tiling_3d_annotation( + localities_information&& localities, std::int64_t const* indices, + std::size_t count, std::string const& name, + std::string const& codename) + { + tiling_information_3d tile_info( + localities.tiles_[localities.locality_.locality_id_], + name, codename); + tile_info.transpose(indices, count); + ++localities.annotation_.generation_; + + return execution_tree::localities_annotation( + localities.locality_.as_annotation(), + tile_info.as_annotation(name, codename), + localities.annotation_, name, codename); + } + } + template execution_tree::primitive_argument_type dist_transpose_operation::transpose3d( - ir::node_data&& arg, execution_tree::annotation&& meta, - execution_tree::annotation&& locality_ann) const + ir::node_data&& arg, localities_information&& localities) const { - execution_tree::annotation tile_ann; - if (!meta.find("tile", tile_ann, name_, codename_)) - { - HPX_THROW_EXCEPTION(hpx::bad_parameter, - "dist_transpose_operation::transpose2d", - generate_error_message( - "meta annotation does not hold any tiling annotation")); - } + static constexpr std::int64_t indices[] = {2, 1, 0}; // perform actual operation - arg = blaze::trans(arg.tensor(), {2, 1, 0}); - - // construct new tiling annotation - tiling_annotations_3d tile_info(tile_ann, name_, codename_); - tile_info.transpose({2, 1, 0}); + arg = blaze::trans(arg.tensor(), indices, 3); execution_tree::primitive_argument_type result{std::move(arg)}; + + // construct new tiling annotation result.set_annotation( - execution_tree::localities_annotation( - locality_ann, tile_info.as_annotation(), name_, codename_), + detail::tiling_3d_annotation( + std::move(localities), indices, 3, name_, codename_), name_, codename_); return result; @@ -356,42 +359,33 @@ namespace phylanx { namespace dist_matrixops { namespace primitives { using namespace execution_tree; - std::string meta_tag = - hpx::util::format("meta_{}", hpx::get_locality_id()); - - execution_tree::annotation meta; - if (!arg.get_annotation_if(meta_tag, meta, name_, codename_) && - !arg.find_annotation(meta_tag, meta, name_, codename_)) + execution_tree::annotation localities; + if (!arg.get_annotation_if("localities", localities, name_, codename_) && + !arg.find_annotation("localities", localities, name_, codename_)) { return common::transpose3d(std::move(arg), name_, codename_); } - execution_tree::annotation locality_ann; - if (!arg.find_annotation("locality", locality_ann, name_, codename_)) - { - HPX_THROW_EXCEPTION(hpx::bad_parameter, - "dist_transpose_operation::transpose2d", - generate_error_message( - "meta annotation does not hold any locality annotation")); - } + auto localities_info = + extract_localities_information(arg, name_, codename_); switch (extract_common_type(arg)) { case node_data_type_bool: return transpose3d( extract_boolean_value_strict(std::move(arg), name_, codename_), - std::move(meta), std::move(locality_ann)); + std::move(localities_info)); case node_data_type_int64: return transpose3d( extract_integer_value_strict(std::move(arg), name_, codename_), - std::move(meta), std::move(locality_ann)); + std::move(localities_info)); case node_data_type_unknown: HPX_FALLTHROUGH; case node_data_type_double: return transpose3d( extract_numeric_value(std::move(arg), name_, codename_), - std::move(meta), std::move(locality_ann)); + std::move(localities_info)); default: break; @@ -408,18 +402,8 @@ namespace phylanx { namespace dist_matrixops { namespace primitives execution_tree::primitive_argument_type dist_transpose_operation::transpose3d(ir::node_data&& arg, ir::node_data&& axes, - execution_tree::annotation&& meta, - execution_tree::annotation&& locality_ann) const + localities_information&& localities) const { - execution_tree::annotation tile_ann; - if (!meta.find("tile", tile_ann, name_, codename_)) - { - HPX_THROW_EXCEPTION(hpx::bad_parameter, - "dist_transpose_operation::transpose2d", - generate_error_message( - "meta annotation does not hold any tiling annotation")); - } - // perform actual operation auto v = axes.vector(); for (auto& axis : v) @@ -430,14 +414,12 @@ namespace phylanx { namespace dist_matrixops { namespace primitives arg = blaze::trans(arg.tensor(), v.data(), v.size()); - // construct new tiling annotation - tiling_annotations_3d tile_info(tile_ann, name_, codename_); - tile_info.transpose(v.data(), v.size()); - execution_tree::primitive_argument_type result{std::move(arg)}; + + // construct new tiling annotation result.set_annotation( - execution_tree::localities_annotation( - locality_ann, tile_info.as_annotation(), name_, codename_), + detail::tiling_3d_annotation( + std::move(localities), v.data(), v.size(), name_, codename_), name_, codename_); return result; @@ -450,43 +432,34 @@ namespace phylanx { namespace dist_matrixops { namespace primitives { using namespace execution_tree; - std::string meta_tag = - hpx::util::format("meta_{}", hpx::get_locality_id()); - - execution_tree::annotation meta; - if (!arg.get_annotation_if(meta_tag, meta, name_, codename_) && - !arg.find_annotation(meta_tag, meta, name_, codename_)) + execution_tree::annotation localities; + if (!arg.get_annotation_if("localities", localities, name_, codename_) && + !arg.find_annotation("localities", localities, name_, codename_)) { return common::transpose3d( std::move(arg), std::move(axes), name_, codename_); } - execution_tree::annotation locality_ann; - if (!arg.find_annotation("locality", locality_ann, name_, codename_)) - { - HPX_THROW_EXCEPTION(hpx::bad_parameter, - "dist_transpose_operation::transpose2d", - generate_error_message( - "meta annotation does not hold any locality annotation")); - } + auto localities_info = + extract_localities_information(arg, name_, codename_); switch (extract_common_type(arg)) { case node_data_type_bool: return transpose3d( extract_boolean_value_strict(std::move(arg), name_, codename_), - std::move(axes), std::move(meta), std::move(locality_ann)); + std::move(axes), std::move(localities_info)); case node_data_type_int64: return transpose3d( extract_integer_value_strict(std::move(arg), name_, codename_), - std::move(axes), std::move(meta), std::move(locality_ann)); + std::move(axes), std::move(localities_info)); case node_data_type_unknown: HPX_FALLTHROUGH; case node_data_type_double: return transpose3d( extract_numeric_value(std::move(arg), name_, codename_), - std::move(axes), std::move(meta), std::move(locality_ann)); + std::move(axes), std::move(localities_info)); default: break; diff --git a/src/plugins/dist_matrixops/localities_annotation.cpp b/src/plugins/dist_matrixops/localities_annotation.cpp new file mode 100644 index 000000000..aa66fef0e --- /dev/null +++ b/src/plugins/dist_matrixops/localities_annotation.cpp @@ -0,0 +1,249 @@ +// Copyright (c) 2019 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////// +namespace phylanx { namespace dist_matrixops +{ + //////////////////////////////////////////////////////////////////////////// + localities_information::localities_information( + execution_tree::annotation const& ann, std::string const& name, + std::string const& codename) + { + auto&& key = ann.get_type(name, codename); + if (key != "localities") + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "localities_information::localities_information", + util::generate_error_message( + hpx::util::format("unexpected annotation type ({})", key), + name, codename)); + } + + locality_ = + execution_tree::extract_locality_information(ann, name, codename); + + // extract the globally unique name identifying this object + execution_tree::annotation name_ann; + if (!ann.find("name", name_ann, name, codename)) + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "dist_transpose_operation::transpose1d", + util::generate_error_message( + "locality annotation does not hold a globally unique name", + name, codename)); + } + + annotation_ = execution_tree::extract_annotation_information( + name_ann, name, codename); + + // extract all tile information + tiles_.reserve(locality_.num_localities_); + for (std::size_t i = 0; i != locality_.num_localities_; ++i) + { + std::string meta_key = hpx::util::format("meta_{}", i); + execution_tree::annotation meta; + if (!ann.find(meta_key, meta, name, codename)) + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "localities_information::localities_information", + util::generate_error_message( + hpx::util::format( + "annotation {} missing from localities information", + meta_key), + name, codename)); + } + + execution_tree::annotation tile; + if (!meta.find("tile", tile, name, codename)) + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "localities_information::localities_information", + util::generate_error_message( + hpx::util::format( + "annotation 'tile' missing from {} information", + meta_key), + name, codename)); + } + tiles_.emplace_back(std::move(tile), name, codename); + } + + // make sure that all tiles have the same dimensionality + if (tiles_.empty()) + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "localities_information::localities_information", + util::generate_error_message( + "no tile information available", + name, codename)); + } + + std::size_t dims = tiles_[0].dimensions(); + auto it = std::find_if( + tiles_.begin(), tiles_.end(), + [&](tiling_information const& v) + { + return v.dimensions() != dims; + }); + + if (it != tiles_.end()) + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "localities_information::localities_information", + util::generate_error_message( + "inconsistent dimensionalities in tiles", + name, codename)); + } + } + + localities_information::localities_information(std::size_t dim, + std::array const& dims) + { + static std::atomic count(0); + + locality_ = execution_tree::locality_information(0, 1); + annotation_ = execution_tree::annotation_information( + hpx::util::format( + "annotation_{}_{}", hpx::get_locality_id(), ++count), + 0ll); + tiles_.emplace_back(dim, dims); + } + + //////////////////////////////////////////////////////////////////////////// + localities_information extract_localities_information( + execution_tree::primitive_argument_type const& arg, + std::string const& name, std::string const& codename) + { + execution_tree::annotation localities; + if (!arg.get_annotation_if("localities", localities, name, codename) && + !arg.find_annotation("localities", localities, name, codename)) + { + std::size_t dim = execution_tree::extract_numeric_value_dimension( + arg, name, codename); + auto dims = execution_tree::extract_numeric_value_dimensions( + arg, name, codename); + + return localities_information(dim, dims); + } + return localities_information(localities, name, codename); + } + + //////////////////////////////////////////////////////////////////////////// + std::size_t localities_information::dimensions() const + { + HPX_ASSERT(tiles_.size() == locality_.num_localities_); + return tiles_[locality_.locality_id_].dimensions(); + } + + namespace detail + { + template + std::size_t dimension(std::vector const& tiles) + { + HPX_ASSERT(!tiles.empty()); + auto it_min = std::min_element(tiles.begin(), tiles.end(), + [&](tiling_information const& v, tiling_information const& smallest) + { + HPX_ASSERT(N < v.spans_.size()); + return v.spans_[N].start_ < smallest.spans_[N].start_; + }); + + auto it_max = std::max_element(tiles.begin(), tiles.end(), + [&](tiling_information const& largest, tiling_information const& v) + { + HPX_ASSERT(N < v.spans_.size()); + return largest.spans_[N].stop_ < v.spans_[N].stop_; + }); + + return it_max->spans_[N].stop_ - it_min->spans_[N].start_; + } + } + + std::size_t localities_information::size() const + { + return detail::dimension<0>(tiles_); + } + + std::size_t localities_information::pages() const + { + return detail::dimension<2>(tiles_); + } + + std::size_t localities_information::rows() const + { + return detail::dimension<1>(tiles_); + } + + std::size_t localities_information::columns() const + { + return detail::dimension<0>(tiles_); + } + + //////////////////////////////////////////////////////////////////////////// + bool localities_information::has_span(std::size_t dim) const + { + HPX_ASSERT(locality_.locality_id_ < tiles_.size()); + HPX_ASSERT(dim < dimensions()); + + return tiles_[locality_.locality_id_].spans_[dim].is_valid(); + } + + tiling_span localities_information::get_span(std::size_t dim) const + { + HPX_ASSERT(locality_.locality_id_ < tiles_.size()); + HPX_ASSERT(dim < dimensions()); + + return tiles_[locality_.locality_id_].spans_[dim]; + } + + // project given (global) span onto local span + tiling_span localities_information::project_coords( + std::uint32_t loc, std::size_t dim, tiling_span const& span) const + { + HPX_ASSERT(loc < tiles_.size()); + HPX_ASSERT(dim < dimensions()); + + auto const& gspan = tiles_[loc].spans_[dim]; + tiling_span result{ + span.start_ - gspan.start_, span.stop_ - gspan.start_}; + return result; + } + +// // convert into an annotation +// execution_tree::annotation localities_information::as_annotation( +// std::string const& name, std::string const& codename) const +// { +// execution_tree::annotation meta; +// for (std::size_t i = 0; i != locality_.num_localities_; ++i) +// { +// auto tile_ann = tiles_[i].as_annotation(name, codename); +// meta.add_annotation(hpx::util::format("meta_{}", i), +// tile_ann.get_data(), name, codename); +// } +// +// return execution_tree::annotation("localities", +// locality_.as_annotation(), std::move(meta), +// annotation_.as_annotation()); +// } +}} + + diff --git a/src/plugins/dist_matrixops/tiling_annotations.cpp b/src/plugins/dist_matrixops/tiling_annotations.cpp index 655d06d14..b86211221 100644 --- a/src/plugins/dist_matrixops/tiling_annotations.cpp +++ b/src/plugins/dist_matrixops/tiling_annotations.cpp @@ -8,9 +8,11 @@ #include #include +#include #include #include +#include #include #include @@ -44,7 +46,8 @@ namespace phylanx { namespace dist_matrixops std::string const& codename) { execution_tree::annotation key_ann; - if (!ann.find(key, key_ann, name, codename)) + if (!ann.get_if(key, key_ann, name, codename) && + !ann.find(key, key_ann, name, codename)) { HPX_THROW_EXCEPTION(hpx::bad_parameter, "tiling_annotations_1d::tiling_annotations_1d", @@ -58,72 +61,170 @@ namespace phylanx { namespace dist_matrixops } //////////////////////////////////////////////////////////////////////////// - tiling_annotations_1d::tiling_annotations_1d( + tiling_information::tiling_information(execution_tree::annotation const& ann, + std::string const& name, std::string const& codename) + { + auto&& key = ann.get_type(name, codename); + if (key != "tile") + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "tiling_annotations::tiling_annotations", + util::generate_error_message( + hpx::util::format( + "unexpected annotation type ({})", key), + name, codename)); + } + + for (std::size_t i = 0; i != 3; ++i) + { + execution_tree::annotation tile_ann; + if (!ann.find(get_span_name(i), tile_ann, name, codename)) + { + spans_.emplace_back(); + } + else + { + spans_.push_back(detail::extract_span( + tile_ann, get_span_name(i), name, codename)); + } + } + } + + tiling_information::tiling_information(std::size_t dim, + std::array const& dims) + { + spans_.reserve(dim); + for (std::size_t d : dims) + { + spans_.emplace_back(0, d); + } + } + + //////////////////////////////////////////////////////////////////////////// + tiling_information_1d::tiling_information_1d( execution_tree::annotation const& ann, std::string const& name, std::string const& codename) : type_(ann.has_key("columns", name, codename) ? columns : rows) { - if (ann.get_type(name, codename) != "tile") + auto&& key = ann.get_type(name, codename); + if (key != "tile" && key != "tile1d") { HPX_THROW_EXCEPTION(hpx::bad_parameter, - "tiling_annotations_1d::tiling_annotations_1d", + "tiling_annotation_1d::tiling_annotations", util::generate_error_message( - "unexpected annotation type", name, codename)); + hpx::util::format("unexpected annotation type ({})", key), + name, codename)); } span_ = detail::extract_span(ann, tile1d_typename(type_), name, codename); } - execution_tree::annotation tiling_annotations_1d::as_annotation() const + tiling_information_1d::tiling_information_1d( + tiling_information const& tile, std::string const& name, + std::string const& codename) + : type_(columns) + { + if (tile.spans_.empty()) + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "tiling_annotation_1d::tiling_annotations", + util::generate_error_message( + hpx::util::format("unexpected annotation type"), + name, codename)); + } + + if (tile.spans_[0].is_valid()) + { + span_ = tile.spans_[0]; + } + else if (tile.spans_.size() >= 2 && tile.spans_[1].is_valid()) + { + type_ = rows; + span_ = tile.spans_[1]; + } + else + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "tiling_annotation_1d::tiling_annotations", + util::generate_error_message( + hpx::util::format("unexpected annotation type"), + name, codename)); + } + } + + execution_tree::annotation tiling_information_1d::as_annotation( + std::string const& name, std::string const& codename) const { return execution_tree::annotation{ir::range("tile", ir::range(tile1d_typename(type_), span_.start_, span_.stop_))}; } - void tiling_annotations_1d::transpose() + void tiling_information_1d::transpose() { type_ = (type_ == columns) ? rows : columns; } //////////////////////////////////////////////////////////////////////////// - tiling_annotations_2d::tiling_annotations_2d( + tiling_information_2d::tiling_information_2d( execution_tree::annotation const& ann, std::string const& name, std::string const& codename) { - if (ann.get_type(name, codename) != "tile") + auto&& key = ann.get_type(name, codename); + if (key != "tile" && key != "tile2d") { HPX_THROW_EXCEPTION(hpx::bad_parameter, - "tiling_annotations_2d::tiling_annotations_1d", + "tiling_annotation_2d::tiling_annotations", util::generate_error_message( - "unexpected annotation type", name, codename)); + hpx::util::format("unexpected annotation type ({})", key), + name, codename)); } - row_span_ = detail::extract_span(ann, "rows", name, codename); - column_span_ = detail::extract_span(ann, "columns", name, codename); + spans_[1] = detail::extract_span(ann, "rows", name, codename); + spans_[0] = detail::extract_span(ann, "columns", name, codename); } - execution_tree::annotation tiling_annotations_2d::as_annotation() const + tiling_information_2d::tiling_information_2d( + tiling_information const& tile, std::string const& name, + std::string const& codename) + { + if (tile.spans_.size() < 2) + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "tiling_annotation_2d::tiling_annotations", + util::generate_error_message( + hpx::util::format("unexpected annotation type"), + name, codename)); + } + + spans_[1] = tile.spans_[1]; + spans_[0] = tile.spans_[0]; + } + + execution_tree::annotation tiling_information_2d::as_annotation( + std::string const& name, std::string const& codename) const { return execution_tree::annotation{ir::range("tile", - ir::range("rows", row_span_.start_, row_span_.stop_), - ir::range("columns", column_span_.start_, column_span_.stop_))}; + ir::range("rows", spans_[1].start_, spans_[1].stop_), + ir::range("columns", spans_[0].start_, spans_[0].stop_))}; } - void tiling_annotations_2d::transpose() + void tiling_information_2d::transpose() { - std::swap(column_span_, row_span_); + std::swap(spans_[0], spans_[1]); } //////////////////////////////////////////////////////////////////////////// - tiling_annotations_3d::tiling_annotations_3d( + tiling_information_3d::tiling_information_3d( execution_tree::annotation const& ann, std::string const& name, std::string const& codename) { - if (ann.get_type(name, codename) != "tile") + auto&& key = ann.get_type(name, codename); + if (key != "tile" && key != "tile3d") { HPX_THROW_EXCEPTION(hpx::bad_parameter, - "tiling_annotations_3d::tiling_annotations_1d", + "tiling_annotation_3d::tiling_annotations", util::generate_error_message( - "unexpected annotation type", name, codename)); + hpx::util::format("unexpected annotation type ({})", key), + name, codename)); } spans_[2] = detail::extract_span(ann, "pages", name, codename); @@ -131,7 +232,26 @@ namespace phylanx { namespace dist_matrixops spans_[0] = detail::extract_span(ann, "columns", name, codename); } - execution_tree::annotation tiling_annotations_3d::as_annotation() const + tiling_information_3d::tiling_information_3d( + tiling_information const& tile, std::string const& name, + std::string const& codename) + { + if (tile.spans_.size() < 3) + { + HPX_THROW_EXCEPTION(hpx::bad_parameter, + "tiling_annotation_3d::tiling_annotations", + util::generate_error_message( + hpx::util::format("unexpected annotation type"), + name, codename)); + } + + spans_[2] = tile.spans_[2]; + spans_[1] = tile.spans_[1]; + spans_[0] = tile.spans_[0]; + } + + execution_tree::annotation tiling_information_3d::as_annotation( + std::string const& name, std::string const& codename) const { return execution_tree::annotation{ir::range("tile", ir::range("pages", spans_[2].start_, spans_[2].stop_), @@ -139,7 +259,7 @@ namespace phylanx { namespace dist_matrixops ir::range("columns", spans_[0].start_, spans_[0].stop_))}; } - void tiling_annotations_3d::transpose( + void tiling_information_3d::transpose( std::int64_t const* data, std::size_t count) { HPX_ASSERT(count == 3); diff --git a/src/plugins/support_components.cpp b/src/plugins/support_components.cpp new file mode 100644 index 000000000..2d6890320 --- /dev/null +++ b/src/plugins/support_components.cpp @@ -0,0 +1,23 @@ +// Copyright (c) 2019 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +#include + +#include + +//////////////////////////////////////////////////////////////////////////////// +using std_int64_t = std::int64_t; +using std_uint8_t = std::uint8_t; + +REGISTER_DISTRIBUTED_VECTOR(double); +REGISTER_DISTRIBUTED_VECTOR(std_int64_t); +REGISTER_DISTRIBUTED_VECTOR(std_uint8_t); + +HPX_REGISTER_ALLREDUCE(double); +HPX_REGISTER_ALLREDUCE(std_int64_t); +HPX_REGISTER_ALLREDUCE(std_uint8_t); diff --git a/src/util/repr_manip.cpp b/src/util/repr_manip.cpp index edc04e1ac..dcc512f9d 100644 --- a/src/util/repr_manip.cpp +++ b/src/util/repr_manip.cpp @@ -39,13 +39,19 @@ namespace phylanx { namespace util /////////////////////////////////////////////////////////////////////////// repr_wrapper::repr_wrapper(std::ostream& strm) - : strm_(strm) + : strm_(strm), has_repr_(is_repr(strm_)) { - strm_ << repr; + if (!has_repr_) + { + strm_ << repr; + } } repr_wrapper::~repr_wrapper() { - strm_ << norepr; + if (!has_repr_) + { + strm_ << norepr; + } } }} diff --git a/tests/unit/plugins/dist_matrixops/CMakeLists.txt b/tests/unit/plugins/dist_matrixops/CMakeLists.txt index 2712bf2d0..e4d5f55db 100644 --- a/tests/unit/plugins/dist_matrixops/CMakeLists.txt +++ b/tests/unit/plugins/dist_matrixops/CMakeLists.txt @@ -4,10 +4,11 @@ # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) set(tests + dist_dot_operation dist_transpose_operation ) -set(dist_transpose_operation_PARAMETERS LOCALITIES 2) +set(dist_dot_operation_PARAMETERS LOCALITIES 2) foreach(test ${tests}) set(sources ${test}.cpp) diff --git a/tests/unit/plugins/dist_matrixops/dist_dot_operation.cpp b/tests/unit/plugins/dist_matrixops/dist_dot_operation.cpp new file mode 100644 index 000000000..b61a35417 --- /dev/null +++ b/tests/unit/plugins/dist_matrixops/dist_dot_operation.cpp @@ -0,0 +1,167 @@ +// Copyright (c) 2017-2019 Hartmut Kaiser +// Copyright (c) 2019 Bita Hasheminezhad +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include +#include + +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +phylanx::execution_tree::primitive_argument_type compile_and_run( + std::string const& name, std::string const& codestr) +{ + phylanx::execution_tree::compiler::function_list snippets; + phylanx::execution_tree::compiler::environment env = + phylanx::execution_tree::compiler::default_environment(); + + auto const& code = + phylanx::execution_tree::compile(name, codestr, snippets, env); + return code.run(); +} + +/////////////////////////////////////////////////////////////////////////////// +void test_dot_operation(std::string const& name, std::string const& code, + std::string const& expected_str) +{ + HPX_TEST_EQ( + compile_and_run(name, code), compile_and_run(name, expected_str)); +} + +//////////////////////////////////////////////////////////////////////////////// +void test_dot_1d_0() +{ + if (hpx::get_locality_id() == 0) + { + test_dot_operation("test1d_0", + R"( + dot_d( + annotate_d( + [1, 2, 3], + "test1d_0_1", + list("tile", list("columns", 0, 3)) + ), + annotate_d( + [4, 5, 6], + "test1d_0_2", + list("tile", list("columns", 3, 6)) + ) + ) + )", + "91"); + } + else + { + test_dot_operation("test1d_0", + R"( + dot_d( + annotate_d( + [4, 5, 6], + "test1d_0_1", + list("tile", list("columns", 3, 6)) + ), + annotate_d( + [1, 2, 3], + "test1d_0_2", + list("tile", list("columns", 0, 3)) + ) + ) + )", + "91"); + } +} + +void test_dot_1d_1() +{ + if (hpx::get_locality_id() == 0) + { + test_dot_operation("test1d_1", + R"( + dot_d( + annotate_d( + [1, 2, 3], + "test1d_1_1", + list("tile", list("columns", 0, 3)) + ), + [1, 2, 3, 4, 5, 6] + ) + )", + "91"); + } + else + { + test_dot_operation("test1d_1", + R"( + dot_d( + annotate_d( + [4, 5, 6], + "test1d_1_1", + list("tile", list("columns", 3, 6)) + ), + [1, 2, 3, 4, 5, 6] + ) + )", + "91"); + } +} + +void test_dot_1d_2() +{ + if (hpx::get_locality_id() == 0) + { + test_dot_operation("test1d_2", + R"( + dot_d( + [1, 2, 3, 4, 5, 6], + annotate_d( + [1, 2, 3], + "test1d_2_1", + list("tile", list("columns", 0, 3)) + ) + ) + )", + "91"); + } + else + { + test_dot_operation("test1d_2", + R"( + dot_d( + [1, 2, 3, 4, 5, 6], + annotate_d( + [4, 5, 6], + "test1d_2_1", + list("tile", list("columns", 3, 6)) + ) + ) + )", + "91"); + } +} + +//////////////////////////////////////////////////////////////////////////////// +int hpx_main(int argc, char* argv[]) +{ + test_dot_1d_0(); + test_dot_1d_1(); + test_dot_1d_2(); + + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + std::vector cfg = { + "hpx.run_hpx_main!=1" + }; + + return hpx::init(argc, argv, cfg); +} diff --git a/tests/unit/plugins/dist_matrixops/dist_transpose_operation.cpp b/tests/unit/plugins/dist_matrixops/dist_transpose_operation.cpp index f2bba8861..70ada20d6 100644 --- a/tests/unit/plugins/dist_matrixops/dist_transpose_operation.cpp +++ b/tests/unit/plugins/dist_matrixops/dist_transpose_operation.cpp @@ -45,6 +45,7 @@ void test_transpose_1d() transpose_d( annotate_d( [1, 2, 3], + "test1d_1", list("tile", list("rows", 0, 3)) ) ) @@ -52,6 +53,7 @@ void test_transpose_1d() R"( annotate_d( [1, 2, 3], + "test1d_1/1", list("tile", list("columns", 0, 3)) ) )"); @@ -60,6 +62,7 @@ void test_transpose_1d() transpose_d( annotate_d( [1, 2, 3], + "test1d_2", list("tile", list("columns", 0, 3)) ) ) @@ -67,6 +70,7 @@ void test_transpose_1d() R"( annotate_d( [1, 2, 3], + "test1d_2/1", list("tile", list("rows", 0, 3)) ) )"); @@ -80,6 +84,7 @@ void test_transpose_2d() transpose_d( annotate_d( [[1, 2, 3], [3, 4, 1]], + "test2d_1", list("tile", list("columns", 0, 3), list("rows", 0, 2)) ) ) @@ -87,6 +92,7 @@ void test_transpose_2d() R"( annotate_d( [[1, 3], [2, 4], [3, 1]], + "test2d_1/1", list("tile", list("rows", 0, 3), list("columns", 0, 2)) ) )"); @@ -97,6 +103,7 @@ void test_transpose_2d() transpose_d( annotate_d( [[1, 2, 3], [3, 4, 1]], + "test2d_2", list("tile", list("columns", 0, 3), list("rows", 0, 2)) ), [0, 1] @@ -105,7 +112,8 @@ void test_transpose_2d() R"( annotate_d( [[1, 2, 3], [3, 4, 1]], - list("tile", list("columns", 0, 3), list("rows", 0, 2)) + "test2d_2/1", + list("tile", list("rows", 0, 2), list("columns", 0, 3)) ) )"); @@ -115,6 +123,7 @@ void test_transpose_2d() transpose_d( annotate_d( [[1, 2, 3], [3, 4, 1]], + "test2d_3", list("tile", list("columns", 0, 3), list("rows", 0, 2)) ), [1, 0] @@ -123,6 +132,7 @@ void test_transpose_2d() R"( annotate_d( [[1, 3], [2, 4], [3, 1]], + "test2d_3/1", list("tile", list("rows", 0, 3), list("columns", 0, 2)) ) )"); @@ -137,46 +147,5 @@ int main(int argc, char* argv[]) test_transpose_1d(); test_transpose_2d(); -// #if defined(PHYLANX_HAVE_BLAZE_TENSOR) -// test_transpose_operation( -// "transpose([[[1,2,3],[4,5,6]]])", "[[[1], [4]],[[2], [5]],[[3], [6]]]"); -// test_transpose_operation( -// "transpose([[[1,2,3],[4,5,6]], [[7,8,9],[10,11,12]]," -// "[[13,14,15],[16,17,18]], [[19,20,21],[22,23,24]]], [2, 1, 0])", -// "[[[ 1, 7, 13, 19],[ 4, 10, 16, 22]],[[ 2, 8, 14, 20]," -// "[ 5, 11, 17, 23]],[[ 3, 9, 15, 21],[ 6, 12, 18, 24]]]"); -// test_transpose_operation( -// "transpose([[[1,2,3],[4,5,6]], [[7,8,9],[10,11,12]]," -// "[[13,14,15],[16,17,18]],[[19,20,21],[22,23,24]]], make_list(1, 0, 2))", -// "[[[ 1, 2, 3],[ 7, 8, 9],[13, 14, 15],[19, 20, 21]]," -// "[[ 4, 5, 6],[10, 11, 12],[16, 17, 18],[22, 23, 24]]]"); -// test_transpose_operation( -// "transpose([[[1,2,3],[4,5,6]], [[7,8,9],[10,11,12]]," -// "[[13,14,15],[16,17,18]], [[19,20,21],[22,23,24]]], [0, 2, 1])", -// "[[[ 1, 4],[ 2, 5],[ 3, 6]], [[ 7, 10],[ 8, 11],[ 9, 12]]," -// "[[13, 16],[14, 17],[15, 18]], [[19, 22],[20, 23],[21, 24]]]"); -// test_transpose_operation( -// "transpose([[[1,2,3],[4,5,6]], [[7,8,9],[10,11,12]]," -// "[[13,14,15],[16,17,18]],[[19,20,21],[22,23,24]]], make_list(1, 2, 0))", -// "[[[ 1, 7, 13, 19],[ 2, 8, 14, 20],[ 3, 9, 15, 21]]," -// "[[ 4, 10, 16, 22],[ 5, 11, 17, 23],[ 6, 12, 18, 24]]]"); -// test_transpose_operation( -// "transpose([[[1,2,3],[4,5,6]], [[7,8,9],[10,11,12]]," -// "[[13,14,15],[16,17,18]], [[19,20,21],[22,23,24]]], [1, -1, -3])", -// "[[[ 1, 7, 13, 19],[ 2, 8, 14, 20],[ 3, 9, 15, 21]]," -// "[[ 4, 10, 16, 22],[ 5, 11, 17, 23],[ 6, 12, 18, 24]]]"); -// test_transpose_operation( -// "transpose([[[1,2,3],[4,5,6]], [[7,8,9],[10,11,12]]," -// "[[13,14,15],[16,17,18]], [[19,20,21],[22,23,24]]], [2, 0, 1])", -// "[[[ 1, 4],[ 7, 10],[13, 16],[19, 22]]," -// "[[ 2, 5],[ 8, 11],[14, 17],[20, 23]]," -// "[[ 3, 6],[ 9, 12],[15, 18],[21, 24]]]"); -// test_transpose_operation( -// "transpose([[[1,2,3],[4,5,6]], [[7,8,9],[10,11,12]]," -// "[[13,14,15],[16,17,18]], [[19,20,21],[22,23,24]]], [0, -2, -1])", -// "[[[ 1, 2, 3],[ 4, 5, 6]],[[ 7, 8, 9],[10, 11, 12]]," -// "[[13, 14, 15],[16, 17, 18]],[[19, 20, 21],[22, 23, 24]]]"); -// #endif - return hpx::util::report_errors(); }