| 131 | : AsyncOpKernel(context) {} |
| 132 | |
| 133 | void ComputeAsync(OpKernelContext* context, DoneCallback done) final { |
| 134 | const Tensor& input = context->input(0); |
| 135 | const int ndims = input.dims(); |
| 136 | const int64 n = input.dim_size(ndims - 1); |
| 137 | // Validate inputs. |
| 138 | OP_REQUIRES_ASYNC( |
| 139 | context, ndims >= 2, |
| 140 | errors::InvalidArgument("Input must have rank >= 2, got ", ndims), |
| 141 | done); |
| 142 | OP_REQUIRES_ASYNC( |
| 143 | context, input.dim_size(ndims - 2) == n, |
| 144 | errors::InvalidArgument("Input matrices must be square, got", |
| 145 | input.dim_size(ndims - 2), " != ", n), |
| 146 | done); |
| 147 | |
| 148 | // Allocate output. |
| 149 | TensorShape out_shape; |
| 150 | for (int dim = 0; dim < ndims - 2; ++dim) { |
| 151 | out_shape.AddDim(input.dim_size(dim)); |
| 152 | } |
| 153 | out_shape.AppendShape(TensorShape({})); |
| 154 | Tensor* out; |
| 155 | OP_REQUIRES_OK_ASYNC(context, context->allocate_output(0, out_shape, &out), |
| 156 | done); |
| 157 | |
| 158 | // By definition, the determinant of an empty matrix is equal to one. |
| 159 | const GPUDevice& d = context->eigen_device<GPUDevice>(); |
| 160 | if (input.NumElements() == 0) { |
| 161 | functor::SetOneFunctor<GPUDevice, Scalar> f; |
| 162 | f(d, out->template flat<Scalar>()); |
| 163 | done(); |
| 164 | return; |
| 165 | } |
| 166 | |
| 167 | // TODO(rmlarsen): Convert to absl::make_unique when available. |
| 168 | std::unique_ptr<CudaSolver> solver(new CudaSolver(context)); |
| 169 | |
| 170 | // Reuse the input buffer or make a copy for the factorization step, |
| 171 | // depending on whether this ops owns it exclusively. |
| 172 | Tensor input_copy; |
| 173 | OP_REQUIRES_OK_ASYNC( |
| 174 | context, |
| 175 | solver->forward_input_or_allocate_scoped_tensor( |
| 176 | {0}, DataTypeToEnum<Scalar>::value, input.shape(), &input_copy), |
| 177 | done); |
| 178 | if (!input.SharesBufferWith(input_copy)) { |
| 179 | d.memcpy(input_copy.flat<Scalar>().data(), input.flat<Scalar>().data(), |
| 180 | input.NumElements() * sizeof(Scalar)); |
| 181 | } |
| 182 | auto input_copy_reshaped = input_copy.template flat_inner_dims<Scalar, 3>(); |
| 183 | const int64 batch_size = input_copy_reshaped.dimension(0); |
| 184 | |
| 185 | // Allocate pivots on the device. |
| 186 | Tensor pivots; |
| 187 | OP_REQUIRES_OK_ASYNC( |
| 188 | context, |
| 189 | solver->allocate_scoped_tensor(DataTypeToEnum<int>::value, |
| 190 | TensorShape{batch_size, n}, &pivots), |
nothing calls this directly
no test coverage detected