| 425 | } |
| 426 | |
| 427 | core::TensorValue graph_transpose( |
| 428 | core::ModuleBuildContext & ctx, |
| 429 | const core::TensorValue & input, |
| 430 | const std::array<int, core::kMaxTensorRank> & axes, |
| 431 | size_t rank) { |
| 432 | if (rank != input.shape.rank) { |
| 433 | throw std::runtime_error("ZipEnhancer transpose rank mismatch"); |
| 434 | } |
| 435 | core::TensorShape output_shape = {}; |
| 436 | output_shape.rank = rank; |
| 437 | std::array<bool, core::kMaxTensorRank> seen = {false, false, false, false}; |
| 438 | std::array<int, core::kMaxTensorRank> ggml_axes = {0, 1, 2, 3}; |
| 439 | for (size_t out_axis = 0; out_axis < rank; ++out_axis) { |
| 440 | const int in_axis = axes[out_axis]; |
| 441 | if (in_axis < 0 || in_axis >= static_cast<int>(rank) || seen[static_cast<size_t>(in_axis)]) { |
| 442 | throw std::runtime_error("ZipEnhancer transpose axes must be a permutation"); |
| 443 | } |
| 444 | seen[static_cast<size_t>(in_axis)] = true; |
| 445 | output_shape.dims[out_axis] = input.shape.dims[static_cast<size_t>(in_axis)]; |
| 446 | const int out_ggml_axis = core::logical_axis_to_ggml_axis(rank, static_cast<int>(out_axis)); |
| 447 | const int in_ggml_axis = core::logical_axis_to_ggml_axis(rank, in_axis); |
| 448 | ggml_axes[static_cast<size_t>(in_ggml_axis)] = out_ggml_axis; |
| 449 | } |
| 450 | const auto contiguous = core::ensure_backend_addressable_layout(ctx, input); |
| 451 | return core::wrap_tensor( |
| 452 | ggml_permute(ctx.ggml, contiguous.tensor, ggml_axes[0], ggml_axes[1], ggml_axes[2], ggml_axes[3]), |
| 453 | output_shape, |
| 454 | input.type); |
| 455 | } |
| 456 | |
| 457 | core::TensorValue graph_concat_all( |
| 458 | core::ModuleBuildContext & ctx, |
no test coverage detected