| 142 | // REQUIRES: perm is a permutation. |
| 143 | |
| 144 | void TransposeOp::Compute(OpKernelContext* ctx) { |
| 145 | const Tensor& input = ctx->input(0); |
| 146 | const Tensor& perm = ctx->input(1); |
| 147 | // Preliminary validation of sizes. |
| 148 | OP_REQUIRES(ctx, TensorShapeUtils::IsVector(perm.shape()), |
| 149 | errors::InvalidArgument("perm must be a vector, not ", |
| 150 | perm.shape().DebugString())); |
| 151 | |
| 152 | // Although Tperm may be an int64 type, an int32 is sufficient to hold |
| 153 | // dimension range values, so the narrowing here should be safe. |
| 154 | std::vector<int32> permutation; |
| 155 | const int dims = input.dims(); |
| 156 | if (perm.dtype() == DT_INT32) { |
| 157 | OP_REQUIRES_OK(ctx, PermutationHelper<int32>(perm, dims, &permutation)); |
| 158 | } else { |
| 159 | OP_REQUIRES_OK(ctx, PermutationHelper<int64>(perm, dims, &permutation)); |
| 160 | } |
| 161 | TensorShape shape; |
| 162 | |
| 163 | // Check whether permutation is a permutation of integers of [0 .. dims). |
| 164 | gtl::InlinedVector<bool, 8> bits(dims); |
| 165 | bool is_identity = true; |
| 166 | for (int i = 0; i < dims; ++i) { |
| 167 | const int32 d = permutation[i]; |
| 168 | OP_REQUIRES( |
| 169 | ctx, 0 <= d && d < dims, |
| 170 | errors::InvalidArgument(d, " is out of range [0 .. ", dims, ")")); |
| 171 | bits[d] = true; |
| 172 | const auto dim_size = input.dim_size(d); |
| 173 | shape.AddDim(dim_size); |
| 174 | if (d != i) { |
| 175 | is_identity = false; |
| 176 | } |
| 177 | } |
| 178 | for (int i = 0; i < dims; ++i) { |
| 179 | OP_REQUIRES(ctx, bits[i], |
| 180 | errors::InvalidArgument(i, " is missing from {", |
| 181 | absl::StrJoin(permutation, ","), "}.")); |
| 182 | } |
| 183 | |
| 184 | // 0-D, 1-D, and identity transposes do nothing. |
| 185 | if (!IsConjugate() && (dims <= 1 || is_identity)) { |
| 186 | ctx->set_output(0, input); |
| 187 | return; |
| 188 | } else if (!IsConjugate() && internal::NonSingletonDimensionsAlign( |
| 189 | input.shape(), permutation)) { |
| 190 | Tensor output; |
| 191 | OP_REQUIRES(ctx, output.CopyFrom(input, shape), |
| 192 | errors::Unknown("Error reshaping Tensor.")); |
| 193 | ctx->set_output(0, output); |
| 194 | return; |
| 195 | } |
| 196 | |
| 197 | Tensor* output = nullptr; |
| 198 | OP_REQUIRES_OK(ctx, ctx->allocate_output(0, shape, &output)); |
| 199 | if (shape.num_elements() > 0) { |
| 200 | OP_REQUIRES_OK(ctx, DoTranspose(ctx, input, permutation, output)); |
| 201 | } |
nothing calls this directly
no test coverage detected