| 128 | explicit LowerBoundOp(OpKernelConstruction* ctx) : OpKernel(ctx) {} |
| 129 | |
| 130 | void Compute(OpKernelContext* ctx) override { |
| 131 | const Tensor& sorted_inputs_t = ctx->input(0); |
| 132 | const Tensor& values_t = ctx->input(1); |
| 133 | |
| 134 | // inputs must be at least a matrix |
| 135 | OP_REQUIRES( |
| 136 | ctx, sorted_inputs_t.shape().dims() >= 2, |
| 137 | errors::InvalidArgument("sorted input argument must be a matrix")); |
| 138 | // must have same batch dim_size for both |
| 139 | OP_REQUIRES(ctx, sorted_inputs_t.dim_size(0) == values_t.dim_size(0), |
| 140 | Status(error::INVALID_ARGUMENT, |
| 141 | "Leading dim_size of both tensors must match.")); |
| 142 | |
| 143 | // this is required because we do indexing in int32 on the GPU |
| 144 | OP_REQUIRES(ctx, values_t.NumElements() < std::numeric_limits<int>::max(), |
| 145 | Status(error::INVALID_ARGUMENT, |
| 146 | "values tensor size must less than INT_MAX")); |
| 147 | |
| 148 | Tensor* output_t; |
| 149 | OP_REQUIRES_OK(ctx, ctx->allocate_output(0, values_t.shape(), &output_t)); |
| 150 | |
| 151 | if (output_t->dtype() == DT_INT32) { |
| 152 | OP_REQUIRES(ctx, |
| 153 | FastBoundsCheck(sorted_inputs_t.dim_size(1), |
| 154 | std::numeric_limits<int>::max()), |
| 155 | errors::InvalidArgument("trailing dim_size must less than " |
| 156 | "INT_MAX for int32 output type, was ", |
| 157 | sorted_inputs_t.dim_size(1))); |
| 158 | } |
| 159 | |
| 160 | auto output = output_t->template flat<OutType>(); |
| 161 | const auto sorted_inputs = sorted_inputs_t.template flat<T>(); |
| 162 | const auto values = values_t.template flat<T>(); |
| 163 | OP_REQUIRES_OK( |
| 164 | ctx, functor::LowerBoundFunctor<Device, T, OutType>::Compute( |
| 165 | ctx, sorted_inputs, values, sorted_inputs_t.dim_size(0), |
| 166 | sorted_inputs_t.dim_size(1), values_t.dim_size(1), &output)); |
| 167 | } |
| 168 | }; |
| 169 | |
| 170 | #define REGISTER_KERNELS(type) \ |
nothing calls this directly
no test coverage detected