| 145 | std::array<bool, core::kMaxTensorRank> seen = {false, false, false, false}; |
| 146 | for (size_t i = 0; i < input_shape.rank; ++i) { |
| 147 | const int axis = config.axes[i]; |
| 148 | if (axis < 0 || axis >= static_cast<int>(input_shape.rank)) { |
| 149 | throw std::runtime_error("Transpose axis out of range"); |
| 150 | } |
| 151 | if (seen[axis]) { |
| 152 | throw std::runtime_error("Transpose axes must form a permutation"); |
| 153 | } |
| 154 | seen[axis] = true; |
| 155 | output.dims[i] = input_shape.dims[axis]; |
| 156 | } |
| 157 | return output; |
| 158 | } |
| 159 | |
| 160 | size_t checked_slice_offset_bytes(const core::TensorValue & input, int ggml_axis, int64_t start) { |
| 161 | if (start < 0 || start >= input.tensor->ne[ggml_axis]) { |
| 162 | throw std::runtime_error("Slice start is out of bounds"); |
| 163 | } |
| 164 | return static_cast<size_t>(start) * input.tensor->nb[ggml_axis]; |
| 165 | } |
| 166 | |
| 167 | ggml_tensor * make_view_with_shape( |
| 168 | core::ModuleBuildContext & ctx, |
| 169 | const core::TensorValue & input, |
| 170 | const core::TensorShape & output_shape, |
| 171 | size_t offset_bytes) { |
| 172 | const auto dims = core::to_ggml_dims(output_shape); |
| 173 | switch (output_shape.rank) { |
| 174 | case 1: |
| 175 | return ggml_view_1d(ctx.ggml, input.tensor, dims[0], offset_bytes); |
| 176 | case 2: |
| 177 | return ggml_view_2d(ctx.ggml, input.tensor, dims[0], dims[1], input.tensor->nb[1], offset_bytes); |
| 178 | case 3: |
| 179 | return ggml_view_3d( |
| 180 | ctx.ggml, |
| 181 | input.tensor, |
| 182 | dims[0], |
| 183 | dims[1], |
| 184 | dims[2], |
| 185 | input.tensor->nb[1], |
| 186 | input.tensor->nb[2], |
no test coverage detected