| 146 | } |
| 147 | |
| 148 | void Compute(OpKernelContext* ctx) override { |
| 149 | const Tensor& shape_t = ctx->input(0); |
| 150 | const Tensor& alpha_t = ctx->input(1); |
| 151 | |
| 152 | OP_REQUIRES(ctx, |
| 153 | TensorShapeUtils::IsVector(shape_t.shape()) && |
| 154 | (shape_t.dtype() == DataType::DT_INT32 || |
| 155 | shape_t.dtype() == DataType::DT_INT64), |
| 156 | errors::InvalidArgument( |
| 157 | "shape must be a vector of {int32,int64}, got shape: ", |
| 158 | shape_t.DebugString())); |
| 159 | TensorShape samples_shape; |
| 160 | if (shape_t.dtype() == DataType::DT_INT32) { |
| 161 | auto vec = shape_t.flat<int32>(); |
| 162 | OP_REQUIRES_OK(ctx, TensorShapeUtils::MakeShape(vec.data(), vec.size(), |
| 163 | &samples_shape)); |
| 164 | } else if (shape_t.dtype() == DataType::DT_INT64) { |
| 165 | auto vec = shape_t.flat<int64>(); |
| 166 | OP_REQUIRES_OK(ctx, TensorShapeUtils::MakeShape(vec.data(), vec.size(), |
| 167 | &samples_shape)); |
| 168 | } |
| 169 | const int64 num_samples = samples_shape.num_elements(); |
| 170 | |
| 171 | samples_shape.AppendShape(alpha_t.shape()); |
| 172 | // Allocate output samples. |
| 173 | Tensor* samples_t = nullptr; |
| 174 | OP_REQUIRES_OK(ctx, ctx->allocate_output(0, samples_shape, &samples_t)); |
| 175 | |
| 176 | if (samples_shape.num_elements() == 0) return; |
| 177 | |
| 178 | using random::PhiloxRandom; |
| 179 | |
| 180 | typedef random::NormalDistribution<PhiloxRandom, double> Normal; |
| 181 | typedef random::UniformDistribution<PhiloxRandom, double> Uniform; |
| 182 | #define UNIFORM(X) \ |
| 183 | if (uniform_remaining == 0) { \ |
| 184 | uniform_remaining = Uniform::kResultElementCount; \ |
| 185 | uniform_result = uniform(&gen); \ |
| 186 | } \ |
| 187 | uniform_remaining--; \ |
| 188 | double X = uniform_result[uniform_remaining] |
| 189 | |
| 190 | // Each attempt is 95+% successful, and requires 1-2 normal + 1 uniform |
| 191 | static constexpr int kReservedSamplesPerOutput = 256; |
| 192 | |
| 193 | const auto alpha_flat = alpha_t.flat<T>().data(); |
| 194 | const int64 num_alphas = alpha_t.NumElements(); |
| 195 | OP_REQUIRES(ctx, num_alphas > 0, |
| 196 | errors::InvalidArgument( |
| 197 | "Input alpha should have non-zero element count, got: ", |
| 198 | num_alphas)); |
| 199 | auto samples_flat = samples_t->flat<T>().data(); |
| 200 | PhiloxRandom rng = generator_.ReserveRandomOutputs( |
| 201 | num_samples * num_alphas, kReservedSamplesPerOutput); |
| 202 | |
| 203 | // We partition work first across alphas then across samples-per-alpha to |
| 204 | // avoid a couple flops which can be done on a per-alpha basis. |
| 205 |
nothing calls this directly
no test coverage detected