| 72 | } |
| 73 | |
| 74 | XlaOp GetMatrixDiagonal(XlaOp x, int k) { |
| 75 | XlaBuilder* builder = x.builder(); |
| 76 | return builder->ReportErrorOrReturn([&]() -> StatusOr<XlaOp> { |
| 77 | TF_ASSIGN_OR_RETURN(Shape shape, builder->GetShape(x)); |
| 78 | auto n_dims = static_cast<int32>(shape.rank()); |
| 79 | TF_RET_CHECK(n_dims >= 2); |
| 80 | const int64 m = shape.dimensions(n_dims - 2); |
| 81 | const int64 n = shape.dimensions(n_dims - 1); |
| 82 | |
| 83 | if (k <= -m || k >= n) { |
| 84 | auto zero_size_shape = shape; |
| 85 | zero_size_shape.DeleteDimension(n_dims - 1); |
| 86 | zero_size_shape.set_dimensions(n_dims - 2, 0); |
| 87 | return ConstantLiteral(builder, Literal{zero_size_shape}); |
| 88 | } |
| 89 | auto mask = GetDiagonalMask(x, k); |
| 90 | |
| 91 | int64 reduce_dim = n_dims - 1; |
| 92 | if ((k == 0 && m >= n) || k < 0) { |
| 93 | reduce_dim = n_dims - 2; |
| 94 | } |
| 95 | auto result = Reduce( |
| 96 | Select(mask, x, Zeros(builder, shape)), ScalarLike(x, 0), |
| 97 | CreateScalarIdentityWithZeroComputation(shape.element_type(), builder), |
| 98 | {reduce_dim}); |
| 99 | // k == 0, we can save one slice op. |
| 100 | if (k == 0) { |
| 101 | return result; |
| 102 | } |
| 103 | return SliceInMinorDims(result, {0}, |
| 104 | {k > 0 ? std::min(m, n - k) : std::min(n, m + k)}); |
| 105 | }); |
| 106 | } |
| 107 | |
| 108 | XlaOp GetMatrixDiagonalViaGather(XlaOp x, int k) { |
| 109 | XlaBuilder* builder = x.builder(); |