| // Returns the frequency of elements of input non-negative integer tensor. |
| |
| #include <ATen/ATen.h> |
| #include <ATen/Dispatch.h> |
| #include <c10/util/irange.h> |
| |
| #include <tuple> |
| |
| namespace at { namespace native { |
| |
| ///////////////// bincount ///////////////// |
| namespace { |
| |
| template <typename input_t, typename weights_t> |
| Tensor _bincount_cpu_template( |
| const Tensor& self, |
| const Tensor& weights, |
| int64_t minlength) { |
| if (minlength < 0) { |
| AT_ERROR("minlength should be >= 0"); |
| } |
| if (self.dim() == 1 && self.numel() == 0) { |
| return at::zeros({minlength}, kLong); |
| } |
| if (self.dim() != 1 || *self.min().data_ptr<input_t>() < 0) { |
| AT_ERROR("bincount only supports 1-d non-negative integral inputs."); |
| } |
| |
| bool has_weights = weights.defined(); |
| if (has_weights && weights.size(0) != self.size(0)) { |
| AT_ERROR("input and weights should have the same length"); |
| } |
| |
| Tensor output; |
| int64_t self_size = self.size(0); |
| int64_t nbins = static_cast<int64_t>(*self.max().data_ptr<input_t>()) + 1L; |
| nbins = std::max(nbins, minlength); // at least minlength # of bins |
| |
| const input_t* self_p = self.data_ptr<input_t>(); |
| if (has_weights) { |
| output = at::zeros( |
| {nbins}, |
| optTypeMetaToScalarType(weights.options().dtype_opt()), |
| weights.options().layout_opt(), |
| weights.options().device_opt(), |
| weights.options().pinned_memory_opt()); |
| weights_t* output_p = output.data_ptr<weights_t>(); |
| const weights_t* weights_p = weights.data_ptr<weights_t>(); |
| for (const auto i : c10::irange(self_size)) { |
| output_p[self_p[i]] += weights_p[i]; |
| } |
| } else { |
| output = at::zeros({nbins}, kLong); |
| int64_t* output_p = output.data_ptr<int64_t>(); |
| for (const auto i : c10::irange(self_size)) { |
| output_p[self_p[i]] += 1L; |
| } |
| } |
| return output; |
| } |
| } // namespace |
| |
| Tensor |
| _bincount_cpu(const Tensor& self, const c10::optional<Tensor>& weights_opt, int64_t minlength) { |
| // See [Note: hacky wrapper removal for optional tensor] |
| c10::MaybeOwned<Tensor> weights_maybe_owned = at::borrow_from_optional_tensor(weights_opt); |
| const Tensor& weights = *weights_maybe_owned; |
| |
| return AT_DISPATCH_INTEGRAL_TYPES(self.scalar_type(), "bincount_cpu", [&] { |
| const auto scalar = weights.scalar_type(); |
| if (scalar == ScalarType::Undefined || scalar == ScalarType::Float) |
| return _bincount_cpu_template<scalar_t, float>(self.contiguous(), weights.contiguous(), minlength); |
| return _bincount_cpu_template<scalar_t, double>( |
| self.contiguous(), weights.contiguous().to(kDouble), minlength); |
| }); |
| } |
| |
| }} // namespace at::native |