| 83 | explicit UpperBoundOp(OpKernelConstruction* ctx) : OpKernel(ctx) {} |
| 84 | |
| 85 | void Compute(OpKernelContext* ctx) override { |
| 86 | const Tensor& sorted_inputs_t = ctx->input(0); |
| 87 | const Tensor& values_t = ctx->input(1); |
| 88 | |
| 89 | // inputs must be at least a matrix |
| 90 | OP_REQUIRES( |
| 91 | ctx, sorted_inputs_t.shape().dims() >= 2, |
| 92 | errors::InvalidArgument("sorted input argument must be a matrix")); |
| 93 | // must have same batch dim_size for both |
| 94 | OP_REQUIRES(ctx, sorted_inputs_t.dim_size(0) == values_t.dim_size(0), |
| 95 | Status(error::INVALID_ARGUMENT, |
| 96 | "Leading dim_size of both tensors must match.")); |
| 97 | |
| 98 | // this is required because we do indexing in int32 on the GPU |
| 99 | OP_REQUIRES(ctx, values_t.NumElements() < std::numeric_limits<int>::max(), |
| 100 | Status(error::INVALID_ARGUMENT, |
| 101 | "values tensor size must less than INT_MAX")); |
| 102 | |
| 103 | Tensor* output_t; |
| 104 | OP_REQUIRES_OK(ctx, ctx->allocate_output(0, values_t.shape(), &output_t)); |
| 105 | |
| 106 | if (output_t->dtype() == DT_INT32) { |
| 107 | OP_REQUIRES(ctx, |
| 108 | FastBoundsCheck(sorted_inputs_t.dim_size(1), |
| 109 | std::numeric_limits<int>::max()), |
| 110 | errors::InvalidArgument("trailing dim_size must less than " |
| 111 | "INT_MAX for int32 output type, was ", |
| 112 | sorted_inputs_t.dim_size(1))); |
| 113 | } |
| 114 | |
| 115 | auto output = output_t->template flat<OutType>(); |
| 116 | const auto sorted_inputs = sorted_inputs_t.template flat<T>(); |
| 117 | const auto values = values_t.template flat<T>(); |
| 118 | OP_REQUIRES_OK( |
| 119 | ctx, functor::UpperBoundFunctor<Device, T, OutType>::Compute( |
| 120 | ctx, sorted_inputs, values, sorted_inputs_t.dim_size(0), |
| 121 | sorted_inputs_t.dim_size(1), values_t.dim_size(1), &output)); |
| 122 | } |
| 123 | }; |
| 124 | |
| 125 | template <typename Device, typename T, typename OutType> |
nothing calls this directly
no test coverage detected