static */
| 928 | } |
| 929 | |
| 930 | /* static */ Shape ShapeUtil::PermuteDimensions( |
| 931 | absl::Span<const int64> permutation, const Shape& shape) { |
| 932 | Shape new_shape = shape; |
| 933 | new_shape.clear_dimensions(); |
| 934 | for (auto dim : Permute(permutation, shape.dimensions())) { |
| 935 | new_shape.add_dimensions(dim); |
| 936 | } |
| 937 | for (int64 i = 0; i < shape.rank(); i++) { |
| 938 | new_shape.set_dynamic_dimension(permutation[i], |
| 939 | shape.is_dynamic_dimension(i)); |
| 940 | } |
| 941 | |
| 942 | // If `shape` has a layout, by contract we choose a new layout such that the |
| 943 | // transpose defined by this permutation is a bitcast. |
| 944 | // |
| 945 | // Some formalism helps to understand the correct way to do this. We're going |
| 946 | // to do algebra in the group of permutations of the dimensions of `shape`. |
| 947 | // |
| 948 | // Since the order of `shape`'s dimensions is not permuted relative to itself, |
| 949 | // `shape`'s list of dimensions is isomorphic to the identity I. |
| 950 | // |
| 951 | // Let `shape`'s layout be L. A layout is a permutation which maps a |
| 952 | // minor-to-major physical layout to the order of a shape's logical dims. |
| 953 | // Therefore inverse of a layout maps from logical to physical dims, and so |
| 954 | // the physical layout of I is simply L'.I = L', where L' is the inverse of L. |
| 955 | // |
| 956 | // Let the argument `permutation` be P. This is a permutation over `shape`'s |
| 957 | // dimensions, so our return value will be a shape with dims P.I = P. Our |
| 958 | // goal is to construct a layout permutation L* that we can apply to P such |
| 959 | // that the physical dimension ordering of the returned shape is the same |
| 960 | // as that of the original shape, namely L'. |
| 961 | // |
| 962 | // Our returned shape has dims P and layout L*, so its in-memory layout is |
| 963 | // L*'.P. Setting this equal to L' and solving for L*, we get: |
| 964 | // |
| 965 | // L*'.P = L' => |
| 966 | // L*' = L'P' => |
| 967 | // L* = P.L |
| 968 | // |
| 969 | if (shape.has_layout()) { |
| 970 | CHECK(LayoutUtil::IsDenseArray(shape)); |
| 971 | Layout* new_layout = new_shape.mutable_layout(); |
| 972 | new_layout->set_format(DENSE); |
| 973 | new_layout->clear_minor_to_major(); |
| 974 | for (auto index : ComposePermutations( |
| 975 | permutation, AsInt64Slice(shape.layout().minor_to_major()))) { |
| 976 | new_layout->add_minor_to_major(index); |
| 977 | } |
| 978 | // The permutation accepted by TransposeIsBitcast is the inverse of the |
| 979 | // permutation here. |
| 980 | CHECK(TransposeIsBitcast(shape, new_shape, InversePermutation(permutation))) |
| 981 | << "shape=" << HumanStringWithLayout(shape) |
| 982 | << ", new_shape=" << HumanStringWithLayout(new_shape) |
| 983 | << ", permutation={" << absl::StrJoin(permutation, ",") << "}"; |
| 984 | } |
| 985 | return new_shape; |
| 986 | } |
| 987 |
nothing calls this directly
no test coverage detected