reduce_task.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2013 Virginia Tech
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #ifndef TILEDARRAY_REDUCE_TASK_H__INCLUDED
21 #define TILEDARRAY_REDUCE_TASK_H__INCLUDED
22 
23 #include <TiledArray/config.h>
24 #include <TiledArray/error.h>
26 
27 #ifdef TILEDARRAY_HAS_CUDA
31 #include <TiledArray/util/time.h>
32 #endif
33 
34 namespace TiledArray {
35 namespace detail {
36 
37 template <typename T>
39  typedef Future<T> type;
40 }; // struct ArgumentHelper
41 
42 template <typename T>
43 struct ArgumentHelper<Future<T> > {
44  typedef Future<T> type;
45 }; // struct ArgumentHelper
46 
47 template <typename T, typename U>
48 struct ArgumentHelper<std::pair<Future<T>, Future<U> > > {
49  typedef std::pair<Future<T>, Future<U> > type;
50 }; // struct ArgumentHelper
51 
53 
55 template <typename opT>
57  public:
58  typedef typename opT::result_type result_type;
60  typedef typename std::remove_cv<typename std::remove_reference<
61  typename opT::first_argument_type>::type>::type first_argument_type;
63  typedef typename std::remove_cv<typename std::remove_reference<
64  typename opT::second_argument_type>::type>::type second_argument_type;
66  typedef std::pair<Future<first_argument_type>, Future<second_argument_type> >
69 
70  private:
71  opT op_;
72 
73  public:
75  ReducePairOpWrapper() : op_() {}
76 
78 
80  ReducePairOpWrapper(const opT& op) : op_(op) {}
81 
83 
85  ReducePairOpWrapper(const ReducePairOpWrapper<opT>& other) : op_(other.op_) {}
86 
89 
91 
95  op_ = other.op_;
96  return *this;
97  }
98 
100  result_type operator()() const { return op_(); }
101 
102  result_type operator()(result_type& temp) const { return op_(temp); }
103 
105 
108  void operator()(result_type& result, const result_type& arg) {
109  op_(result, arg);
110  }
111 
113 
116  void operator()(result_type& result, const argument_type& arg) const {
117  op_(result, arg.first, arg.second);
118  }
119 
120 }; // class ReducePairOpWrapper
121 
123 
199 template <typename opT>
200 class ReduceTask {
201  private:
202  typedef typename opT::result_type result_type;
203  typedef typename std::remove_const<
204  typename std::remove_reference<typename opT::argument_type>::type>::type
205  argument_type;
206 
208 
212  class ReduceTaskImpl : public madness::TaskInterface {
213  public:
215 
218  class ReduceObject : public madness::CallbackInterface {
219  private:
220  ReduceTaskImpl* parent_;
222  arg_;
223  madness::CallbackInterface* callback_;
224  madness::AtomicInt count_;
225 
227 
230  template <typename T>
231  void register_callbacks(Future<T>& f) {
232  if (f.probe()) {
233  parent_->ready(this);
234  } else {
235  count_ = 1;
236  f.register_callback(this);
237  }
238  }
239 
241 
245  template <typename T, typename U>
246  void register_callbacks(std::pair<Future<T>, Future<U> >& p) {
247  if (p.first.probe() && p.second.probe()) {
248  parent_->ready(this);
249  } else {
250  count_ = 2;
251  p.first.register_callback(this);
252  p.second.register_callback(this);
253  }
254  }
255 
256  public:
258 
264  template <typename Arg>
265  ReduceObject(ReduceTaskImpl* parent, const Arg& arg,
266  madness::CallbackInterface* callback)
267  : parent_(parent), arg_(arg), callback_(callback) {
268  TA_ASSERT(parent_);
269  register_callbacks(arg_);
270  }
271 
272  virtual ~ReduceObject() {}
273 
275  virtual void notify() {
276  if ((--count_) == 0) parent_->ready(this);
277  }
278 
280 
282  const argument_type& arg() const { return arg_; }
283 
285 
288  static void destroy(const ReduceObject* object) {
289  static constexpr const bool trace_tasks =
290 #ifdef TILEDARRAY_ENABLE_TASK_DEBUG_TRACE
291  true
292 #else
293  false
294 #endif
295  ;
296  if (object->callback_) {
297  if (trace_tasks)
298  object->callback_->notify_debug("destroy(*ReduceObject)");
299  else
300  object->callback_->notify();
301  }
302  delete object;
303  }
304 
305  }; // class ReduceObject
306 
307 #ifdef TILEDARRAY_HAS_CUDA
308 
309  static void CUDART_CB cuda_reduceobject_delete_callback(void* userData) {
310  const auto t0 = TiledArray::now();
311 
312  std::vector<void*>* objects = static_cast<std::vector<void*>*>(userData);
313 
315  madness::World* world = static_cast<madness::World*>((*objects)[0]);
316 
317  auto destroy_vector = [](std::vector<void*>* objects) {
318  std::size_t n_objects = objects->size();
320  for (std::size_t i = 1; i < n_objects; i++) {
321  // convert void* to ReduceObject*
322  ReduceObject* reduce_object =
323  static_cast<ReduceObject*>((*objects)[i]);
324  // delete ReduceObject
325  ReduceObject::destroy(reduce_object);
326  }
328  delete objects;
329  // std::cout << std::to_string(
330  // TiledArray::get_default_world().rank()) +
331  // " call 1\n";
332  };
333 
336  world->taskq.add(destroy_vector, objects, TaskAttributes::hipri());
337 
338  const auto t1 = TiledArray::now();
339  TiledArray::detail::cuda_callback_duration_ns<0>() +=
341  }
342 
343  static void CUDART_CB cuda_dependency_dec_callback(void* userData) {
344  const auto t0 = TiledArray::now();
345 
346  std::vector<void*>* objects = static_cast<std::vector<void*>*>(userData);
347 
348  for (auto& item : *objects) {
349  // convert void* to DependencyInterface
350  ReduceTaskImpl* dep = static_cast<ReduceTaskImpl*>(item);
351  // call dec
352  dep->dec();
353  }
354  delete objects;
355  // std::cout <<
356  // std::to_string(TiledArray::get_default_world().rank()) +
357  // " call 2\n";
358 
359  const auto t1 = TiledArray::now();
360  TiledArray::detail::cuda_callback_duration_ns<1>() +=
362  }
363 
364  static void CUDART_CB
365  cuda_dependency_dec_reduceobject_delete_callback(void* userData) {
366  const auto t0 = TiledArray::now();
367 
368  std::vector<void*>* objects = static_cast<std::vector<void*>*>(userData);
369 
370  assert(objects->size() == 3);
371 
373  madness::World* world = static_cast<madness::World*>(objects->at(0));
374 
375  // convert void* to DependencyInterface
376  ReduceTaskImpl* dep = static_cast<ReduceTaskImpl*>(objects->at(1));
377  // call dec
378  dep->dec();
379 
380  // convert void* to ReduceObject*
381  ReduceObject* reduce_object = static_cast<ReduceObject*>(objects->at(2));
382 
383  auto destroy = [](ReduceObject* object) {
384  ReduceObject::destroy(object);
385  // std::cout << std::to_string(
386  // TiledArray::get_default_world().rank()) +
387  // " call 3\n";
388  };
389 
390  // delete ReduceObject
391  world->taskq.add(destroy, reduce_object, TaskAttributes::hipri());
392 
393  delete objects;
394 
395  const auto t1 = TiledArray::now();
396  TiledArray::detail::cuda_callback_duration_ns<2>() +=
398  }
399 
400  static void CUDART_CB cuda_readyresult_reset_callback(void* userData) {
401  const auto t0 = TiledArray::now();
402 
403  std::vector<void*>* objects = static_cast<std::vector<void*>*>(userData);
404 
406  madness::World* world = static_cast<madness::World*>((*objects)[0]);
407 
408  auto reset = [](std::vector<void*>* objects) {
409  // skip the first one since it always be madness::World*
410  // convert void* to the correct type
411  std::shared_ptr<result_type>* result =
412  static_cast<std::shared_ptr<result_type>*>((*objects)[1]);
413  // call reset on shared_ptr
414  result->reset();
415  delete objects;
416  // std::cout <<
417  // std::to_string(TiledArray::get_default_world().rank()) +
418  // " call 4\n";
419  };
420 
421  world->taskq.add(reset, objects, TaskAttributes::hipri());
422 
423  const auto t1 = TiledArray::now();
424  TiledArray::detail::cuda_callback_duration_ns<3>() +=
426  }
427 
428 #endif
429  virtual void get_id(std::pair<void*, unsigned short>& id) const {
430  return PoolTaskInterface::make_id(id, *this);
431  }
432 
434 
441  void reduce(std::shared_ptr<result_type>& result) {
442  while (result) {
443  lock_.lock(); // <<< Begin critical section
444  if (ready_object_) {
445  // Get the ready argument
446  ReduceObject* ready_object = const_cast<ReduceObject*>(ready_object_);
447  ready_object_ = nullptr;
448  lock_.unlock(); // <<< End critical section
449 
450  // Reduce the argument that was held by ready_object_
451  op_(*result, ready_object->arg());
452 
453  // cleanup the argument
454 #ifdef TILEDARRAY_HAS_CUDA
455  auto stream_ptr = tls_cudastream_accessor();
456 
458  if (stream_ptr == nullptr) {
459  ReduceObject::destroy(ready_object);
460  this->dec();
461  } else {
462  auto callback_object = new std::vector<void*>(3);
463  (*callback_object)[0] = &world_;
464  (*callback_object)[1] = this;
465  (*callback_object)[2] = ready_object;
466  CudaSafeCall(
467  cudaSetDevice(cudaEnv::instance()->current_cuda_device_id()));
468  CudaSafeCall(cudaLaunchHostFunc(
469  *stream_ptr, cuda_dependency_dec_reduceobject_delete_callback,
470  callback_object));
471  synchronize_stream(nullptr);
472  // std::cout << std::to_string(world().rank()) + "
473  // add 3\n";
474  }
475 #else
476  ReduceObject::destroy(ready_object);
477  this->dec();
478 #endif
479  } else if (ready_result_) {
480  // Get the ready result
481  std::shared_ptr<result_type> ready_result = ready_result_;
482  ready_result_.reset();
483  lock_.unlock(); // <<< End critical section
484 
485  // Reduce the result that was held by ready_result_
486  op_(*result, *ready_result);
487 
488  // cleanup the result
489 #ifdef TILEDARRAY_HAS_CUDA
490  auto stream_ptr = tls_cudastream_accessor();
491  if (stream_ptr == nullptr) {
492  ready_result.reset();
493  } else {
494  auto ready_result_heap =
495  new std::shared_ptr<result_type>(ready_result);
496  auto callback_object = new std::vector<void*>(2);
497  (*callback_object)[0] = &world_;
498  (*callback_object)[1] = ready_result_heap;
499  CudaSafeCall(
500  cudaSetDevice(cudaEnv::instance()->current_cuda_device_id()));
501  CudaSafeCall(cudaLaunchHostFunc(
502  *stream_ptr, cuda_readyresult_reset_callback, callback_object));
503  synchronize_stream(nullptr);
504  // std::cout << std::to_string(world().rank()) + "
505  // add 4\n";
506  }
507 #else
508  ready_result.reset();
509 #endif
510  } else {
511  // Nothing is ready, so place result in the ready state.
512  ready_result_ = result;
513  result.reset();
514  lock_.unlock(); // <<< End critical section
515  }
516  }
517  }
518 
520 
523  void reduce_result_object(std::shared_ptr<result_type> result,
524  const ReduceObject* object) {
525  // Reduce the argument
526  op_(*result, object->arg());
527 
528  // Cleanup the argument
529 #ifdef TILEDARRAY_HAS_CUDA
530  auto stream_ptr = tls_cudastream_accessor();
531  if (stream_ptr == nullptr) {
532  ReduceObject::destroy(object);
533  } else {
534  auto callback_object = new std::vector<void*>(2);
535  (*callback_object)[0] = &world_;
536  (*callback_object)[1] = const_cast<ReduceObject*>(object);
537  CudaSafeCall(
538  cudaSetDevice(cudaEnv::instance()->current_cuda_device_id()));
539  CudaSafeCall(cudaLaunchHostFunc(
540  *stream_ptr, cuda_reduceobject_delete_callback, callback_object));
541  synchronize_stream(nullptr);
542  // std::cout << std::to_string(world().rank()) + " add 1\n";
543  }
544 #else
545  ReduceObject::destroy(object);
546 #endif
547  // Check for more reductions
548  reduce(result);
549 
550  // Decrement the dependency counter for the argument. This must
551  // be done after the reduce call to avoid a race condition.
552 #ifdef TILEDARRAY_HAS_CUDA
553  if (stream_ptr == nullptr) {
554  this->dec();
555  } else {
556  auto callback_object2 = new std::vector<void*>(1);
557  (*callback_object2)[0] = this;
558  CudaSafeCall(
559  cudaSetDevice(cudaEnv::instance()->current_cuda_device_id()));
560  CudaSafeCall(cudaLaunchHostFunc(
561  *stream_ptr, cuda_dependency_dec_callback, callback_object2));
562  // std::cout << std::to_string(world().rank()) + " add 2\n";
563  }
564 #else
565  this->dec();
566 #endif
567  }
568 
570  void reduce_object_object(const ReduceObject* object1,
571  const ReduceObject* object2) {
572  // Construct an empty result object
573  auto result = std::make_shared<result_type>(op_());
574 
575  // Reduce the two arguments
576  op_(*result, object1->arg());
577  op_(*result, object2->arg());
578 
579  // Cleanup arguments
580 #ifdef TILEDARRAY_HAS_CUDA
581  auto stream_ptr = tls_cudastream_accessor();
582  if (stream_ptr == nullptr) {
583  ReduceObject::destroy(object1);
584  ReduceObject::destroy(object2);
585  } else {
586  auto callback_object1 = new std::vector<void*>(3);
587  (*callback_object1)[0] = &world_;
588  (*callback_object1)[1] = const_cast<ReduceObject*>(object1);
589  (*callback_object1)[2] = const_cast<ReduceObject*>(object2);
590  CudaSafeCall(
591  cudaSetDevice(cudaEnv::instance()->current_cuda_device_id()));
592  CudaSafeCall(cudaLaunchHostFunc(
593  *stream_ptr, cuda_reduceobject_delete_callback, callback_object1));
594  synchronize_stream(nullptr);
595  // std::cout << std::to_string(world().rank()) + " add 1\n";
596  }
597 #else
598  ReduceObject::destroy(object1);
599  ReduceObject::destroy(object2);
600 #endif
601 
602  // Check for more reductions
603  reduce(result);
604 
605  // Decrement the dependency counter for the two arguments. This
606  // must be done after the reduce call to avoid a race condition.
607 #ifdef TILEDARRAY_HAS_CUDA
608  if (stream_ptr == nullptr) {
609  this->dec();
610  this->dec();
611  } else {
612  auto callback_object2 = new std::vector<void*>(2);
613  (*callback_object2)[0] = this;
614  (*callback_object2)[1] = this;
615  CudaSafeCall(
616  cudaSetDevice(cudaEnv::instance()->current_cuda_device_id()));
617  CudaSafeCall(cudaLaunchHostFunc(
618  *stream_ptr, cuda_dependency_dec_callback, callback_object2));
619  // std::cout << std::to_string(world().rank()) + " add 2\n";
620  }
621 
622 #else
623  this->dec();
624  this->dec();
625 #endif
626  }
627 
628 #ifdef TILEDARRAY_HAS_CUDA
629  template <typename Result = result_type>
630  std::enable_if_t<detail::is_cuda_tile_v<Result>, void> internal_run(
631  const madness::TaskThreadEnv&) {
632  TA_ASSERT(ready_result_);
633 
634  auto post_result = madness::add_cuda_task(world_, op_, *ready_result_);
635  result_.set(post_result);
636 
637  if (callback_) {
638  result_.register_callback(callback_);
639  }
640  }
641 
642  template <typename Result = result_type>
643  std::enable_if_t<!detail::is_cuda_tile_v<Result>, void>
644 #else
645  void
646 #endif
647  internal_run(const madness::TaskThreadEnv&) {
648  TA_ASSERT(ready_result_);
649  result_.set(op_(*ready_result_));
650 
651  if (callback_) callback_->notify();
652  }
653 
654  World& world_;
655  opT op_;
656  std::shared_ptr<result_type>
657  ready_result_;
658  volatile ReduceObject*
659  ready_object_;
660  Future<result_type> result_;
661  madness::Spinlock lock_;
662  madness::CallbackInterface* callback_;
663 
664  public:
666 
671  ReduceTaskImpl(World& world, opT op, madness::CallbackInterface* callback)
672  : madness::TaskInterface(1, TaskAttributes::hipri()),
673  world_(world),
674  op_(op),
675  ready_result_(std::make_shared<result_type>(op())),
676  ready_object_(nullptr),
677  result_(),
678  lock_(),
679  callback_(callback) {}
680 
681  virtual ~ReduceTaskImpl() {}
682 
684  virtual void run(const madness::TaskThreadEnv& threadEnv) {
685  internal_run(threadEnv);
686  }
687 
689 
694  void ready(ReduceObject* object) {
695  TA_ASSERT(object);
696  lock_.lock(); // <<< Begin critical section
697  if (ready_result_) {
698  std::shared_ptr<result_type> ready_result = ready_result_;
699  ready_result_.reset();
700  lock_.unlock(); // <<< End critical section
701  TA_ASSERT(ready_result);
702  world_.taskq.add(this, &ReduceTaskImpl::reduce_result_object,
703  ready_result, object, TaskAttributes::hipri());
704  } else if (ready_object_) {
705  ReduceObject* ready_object = const_cast<ReduceObject*>(ready_object_);
706  ready_object_ = nullptr;
707  lock_.unlock(); // <<< End critical section
708  TA_ASSERT(ready_object);
709  world_.taskq.add(this, &ReduceTaskImpl::reduce_object_object, object,
710  ready_object, TaskAttributes::hipri());
711  } else {
712  ready_object_ = object;
713  lock_.unlock(); // <<< End critical section
714  }
715  }
716 
718 
720  const Future<result_type>& result() const { return result_; }
721 
723 
725  World& world() const { return world_; }
726 
727  }; // class ReduceTaskImpl
728 
729  ReduceTaskImpl* pimpl_;
730  std::size_t count_;
731 
732  public:
734  ReduceTask() : pimpl_(nullptr), count_(0ul) {}
735 
737 
742  ReduceTask(World& world, const opT& op = opT(),
743  madness::CallbackInterface* callback = nullptr)
744  : pimpl_(new ReduceTaskImpl(world, op, callback)), count_(0ul) {}
745 
747 
749  ReduceTask(ReduceTask<opT>&& other) noexcept
750  : pimpl_(other.pimpl_), count_(other.count_) {
751  other.pimpl_ = nullptr;
752  other.count_ = 0ul;
753  }
754 
756 
759  ~ReduceTask() { delete pimpl_; }
760 
762 
765  pimpl_ = other.pimpl_;
766  count_ = other.count_;
767  other.pimpl_ = nullptr;
768  other.count_ = 0;
769  return *this;
770  }
771 
772  // Non-copyable
773  ReduceTask(const ReduceTask<opT>&) = delete;
775 
777 
785  template <typename Arg>
786  int add(const Arg& arg, madness::CallbackInterface* callback = nullptr) {
787  TA_ASSERT(pimpl_);
788  pimpl_->inc();
789  new typename ReduceTaskImpl::ReduceObject(pimpl_, arg, callback);
790  return ++count_;
791  }
792 
794 
796  int count() const { return count_; }
797 
799 
804  TA_ASSERT(pimpl_);
805 
806  // Get the result before submitting/running the task, otherwise the
807  // task could run and be deleted before we are done here.
808  Future<result_type> result = pimpl_->result();
809 
810  pimpl_->dec();
811  World& world = pimpl_->world();
812  world.taskq.add(pimpl_);
813 
814  pimpl_ = nullptr;
815  return result;
816  }
817 
819 
821  operator bool() const { return pimpl_ != nullptr; }
822 
823 }; // class ReduceTask
824 
826 
909 template <typename opT>
910 class ReducePairTask : public ReduceTask<ReducePairOpWrapper<opT> > {
911  private:
913  typedef typename op_type::first_argument_type
914  first_argument_type;
915  typedef typename op_type::second_argument_type
916  second_argument_type;
917  typedef typename op_type::argument_type
918  argument_type;
920 
921  public:
924 
926 
931  ReducePairTask(World& world, const opT& op = opT(),
932  madness::CallbackInterface* callback = nullptr)
933  : ReduceTask_(world, op_type(op), callback) {}
934 
936 
939  : ReduceTask_(std::move(other)) {}
940 
942 
945  ReduceTask_::operator=(std::move(other));
946  return *this;
947  }
948 
952 
954 
965  template <typename L, typename R>
966  void add(const L& left, const R& right,
967  madness::CallbackInterface* callback = nullptr) {
968  ReduceTask_::add(argument_type(Future<first_argument_type>(left),
970  callback);
971  }
972 
973 }; // class ReducePairTask
974 
975 } // namespace detail
976 } // namespace TiledArray
977 
978 #endif // TILEDARRAY_REDUCE_TASK_H__INCLUDED
ReduceTask(World &world, const opT &op=opT(), madness::CallbackInterface *callback=nullptr)
Constructor.
Definition: reduce_task.h:742
void add(const L &left, const R &right, madness::CallbackInterface *callback=nullptr)
Add a pair of arguments to the reduction task.
Definition: reduce_task.h:966
void operator()(result_type &result, const result_type &arg)
Reduce two result objects.
Definition: reduce_task.h:108
std::remove_cv< typename std::remove_reference< typename opT::second_argument_type >::type >::type second_argument_type
The right-hand argument type.
Definition: reduce_task.h:64
ReducePairTask< opT > operator=(const ReducePairTask< opT > &)=delete
result_type operator()(result_type &temp) const
Definition: reduce_task.h:102
ReducePairOpWrapper(const opT &op)
Constructor.
Definition: reduce_task.h:80
ReducePairTask(const ReducePairTask< opT > &)=delete
Non-copyable.
ReducePairTask(ReducePairTask< opT > &&other) noexcept
Move constructor.
Definition: reduce_task.h:938
int64_t duration_in_ns(time_point const &t0, time_point const &t1)
Definition: time.h:45
Wrapper that to convert a pair-wise reduction into a standard reduction.
Definition: reduce_task.h:56
ReducePairOpWrapper< opT > & operator=(const ReducePairOpWrapper< opT > &other)
Copy assignment operator.
Definition: reduce_task.h:94
std::enable_if<!detail::is_scalar_v< Arg > >::type destroy_vector(const std::size_t n, Arg *const arg)
Definition: vector_op.h:706
result_type operator()() const
Create an default reduction object.
Definition: reduce_task.h:100
time_point now()
Definition: time.h:35
std::pair< Future< first_argument_type >, Future< second_argument_type > > argument_type
The combine argument type.
Definition: reduce_task.h:67
ReduceTask()
Default constructor.
Definition: reduce_task.h:734
#define TA_ASSERT(EXPR,...)
Definition: error.h:39
Future< result_type > submit()
Submit the reduction task to the task queue.
Definition: reduce_task.h:803
ReducePairTask< opT > & operator=(ReducePairTask< opT > &&other) noexcept
Move assignment operator.
Definition: reduce_task.h:944
static void destroy(const ReduceObject *object)
Destroy the object.
Definition: reduce_task.h:288
int add(const Arg &arg, madness::CallbackInterface *callback=nullptr)
Add an argument to the reduction task.
Definition: reduce_task.h:786
ReduceObject(ReduceTaskImpl *parent, const Arg &arg, madness::CallbackInterface *callback)
Constructor.
Definition: reduce_task.h:265
ReduceTask< opT > & operator=(const ReduceTask< opT > &)=delete
ReducePairOpWrapper(const ReducePairOpWrapper< opT > &other)
Copy constructor.
Definition: reduce_task.h:85
ReducePairOpWrapper()
Default constructor.
Definition: reduce_task.h:75
ReduceTask(const ReduceTask< opT > &)=delete
std::remove_cv< typename std::remove_reference< typename opT::first_argument_type >::type >::type first_argument_type
The left-hand argument type.
Definition: reduce_task.h:61
void operator()(result_type &result, const argument_type &arg) const
Reduce an argument pair.
Definition: reduce_task.h:116
ReduceTask< opT > & operator=(ReduceTask< opT > &&other) noexcept
Move assignment operator.
Definition: reduce_task.h:764
ReducePairTask(World &world, const opT &op=opT(), madness::CallbackInterface *callback=nullptr)
Constructor.
Definition: reduce_task.h:931
ReducePairTask()
Default constructor.
Definition: reduce_task.h:923
opT::result_type result_type
The result type of this reduction operation.
Definition: reduce_task.h:58
int count() const
Argument count.
Definition: reduce_task.h:796
ReduceTask(ReduceTask< opT > &&other) noexcept
Move constructor.
Definition: reduce_task.h:749
virtual void notify()
Callback function that is invoked when the argument is ready.
Definition: reduce_task.h:275
const argument_type & arg() const
Argument accessor.
Definition: reduce_task.h:282