|  | #ifndef CAFFE2_OPERATORS_MINMAX_OPS_H_ | 
|  | #define CAFFE2_OPERATORS_MINMAX_OPS_H_ | 
|  |  | 
|  | #include "caffe2/core/context.h" | 
|  | #include "caffe2/core/logging.h" | 
|  | #include "caffe2/core/operator.h" | 
|  | #include "caffe2/core/types.h" | 
|  | #include "caffe2/utils/math.h" | 
|  | #include <c10/util/irange.h> | 
|  |  | 
|  | namespace caffe2 { | 
|  |  | 
|  | template <typename T, class Context> | 
|  | class MaxOp final : public Operator<Context> { | 
|  | public: | 
|  | USE_OPERATOR_CONTEXT_FUNCTIONS; | 
|  |  | 
|  | USE_SIMPLE_CTOR_DTOR(MaxOp) | 
|  |  | 
|  | bool RunOnDevice() override { | 
|  | const auto& X0 = Input(0); | 
|  | auto* Y = Output(0); | 
|  | Y->ResizeLike(X0); | 
|  | const T* X0_data = X0.template data<T>(); | 
|  | T* Y_data = Y->template mutable_data<T>(); | 
|  | const int N = X0.numel(); | 
|  | if (InputSize() == 1) { | 
|  | if (Y != &X0) { | 
|  | context_.template CopySameDevice<T>(N, X0_data, Y_data); | 
|  | } | 
|  | return true; | 
|  | } | 
|  | const auto& X1 = Input(1); | 
|  | CAFFE_ENFORCE_EQ( | 
|  | X0.sizes(), | 
|  | Y->sizes(), | 
|  | "Description: Input #1, input dimension:", | 
|  | X1.sizes(), | 
|  | " should match output dimension: ", | 
|  | Y->sizes()); | 
|  | const T* X1_data = X1.template data<T>(); | 
|  | math::Max<T, Context>(N, X0_data, X1_data, Y_data, &context_); | 
|  | for (const auto i : c10::irange(2, InputSize())) { | 
|  | const auto& Xi = Input(i); | 
|  | CAFFE_ENFORCE_EQ( | 
|  | Xi.sizes(), | 
|  | Y->sizes(), | 
|  | "Description: Input #", | 
|  | i, | 
|  | ", input dimension:", | 
|  | Input(i).sizes(), | 
|  | " should match output dimension: ", | 
|  | Y->sizes()); | 
|  | const T* Xi_data = Xi.template data<T>(); | 
|  | math::Max<T, Context>(N, Y_data, Xi_data, Y_data, &context_); | 
|  | } | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T, class Context> | 
|  | class MinOp final : public Operator<Context> { | 
|  | public: | 
|  | USE_OPERATOR_CONTEXT_FUNCTIONS; | 
|  |  | 
|  | USE_SIMPLE_CTOR_DTOR(MinOp) | 
|  |  | 
|  | bool RunOnDevice() override { | 
|  | const auto& X0 = Input(0); | 
|  | auto* Y = Output(0); | 
|  | Y->ResizeLike(X0); | 
|  | const T* X0_data = X0.template data<T>(); | 
|  | T* Y_data = Y->template mutable_data<T>(); | 
|  | const int N = X0.numel(); | 
|  | if (InputSize() == 1) { | 
|  | if (Y != &X0) { | 
|  | context_.template CopySameDevice<T>(N, X0_data, Y_data); | 
|  | } | 
|  | return true; | 
|  | } | 
|  | const auto& X1 = Input(1); | 
|  | CAFFE_ENFORCE_EQ( | 
|  | X0.sizes(), | 
|  | Y->sizes(), | 
|  | "Description: Input #1, input dimension:", | 
|  | X1.sizes(), | 
|  | " should match output dimension: ", | 
|  | Y->sizes()); | 
|  | const T* X1_data = X1.template data<T>(); | 
|  | math::Min<T, Context>(N, X0_data, X1_data, Y_data, &context_); | 
|  | for (const auto i : c10::irange(2, InputSize())) { | 
|  | const auto& Xi = Input(i); | 
|  | CAFFE_ENFORCE_EQ( | 
|  | Xi.sizes(), | 
|  | Y->sizes(), | 
|  | "Description: Input #", | 
|  | i, | 
|  | ", input dimension:", | 
|  | Input(i).sizes(), | 
|  | " should match output dimension: ", | 
|  | Y->sizes()); | 
|  | const T* Xi_data = Xi.template data<T>(); | 
|  | math::Min<T, Context>(N, Y_data, Xi_data, Y_data, &context_); | 
|  | } | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T, class Context> | 
|  | class SelectGradientOpBase : public Operator<Context> { | 
|  | public: | 
|  | USE_OPERATOR_CONTEXT_FUNCTIONS; | 
|  | USE_SIMPLE_CTOR_DTOR(SelectGradientOpBase) | 
|  |  | 
|  | bool RunOnDevice() override; | 
|  | }; | 
|  |  | 
|  | template <typename T, class Context> | 
|  | class MaxGradientOp final : public SelectGradientOpBase<T, Context> { | 
|  | public: | 
|  | template <class... Args> | 
|  | explicit MaxGradientOp(Args&&... args) | 
|  | : SelectGradientOpBase<T, Context>(std::forward<Args>(args)...) {} | 
|  |  | 
|  | ~MaxGradientOp() = default; | 
|  | }; | 
|  |  | 
|  | template <typename T, class Context> | 
|  | class MinGradientOp final : public SelectGradientOpBase<T, Context> { | 
|  | public: | 
|  | template <class... Args> | 
|  | explicit MinGradientOp(Args&&... args) | 
|  | : SelectGradientOpBase<T, Context>(std::forward<Args>(args)...) {} | 
|  |  | 
|  | ~MinGradientOp() = default; | 
|  | }; | 
|  |  | 
|  | } // namespace caffe2 | 
|  |  | 
|  | #endif // CAFFE2_OPERATORS_MINMAX_OPS_H_ |