* Repeats this tensor along the specified dimensions. * @param {...number} repeats The number of times to repeat this tensor along each dimension. * @returns {Tensor} The repeated tensor. * @throws {Error} If the number of repeats is less than the number of dimensions.
(...repeats)
| 829 | * @throws {Error} If the number of repeats is less than the number of dimensions. |
| 830 | */ |
| 831 | repeat(...repeats) { |
| 832 | if (repeats.length < this.dims.length) { |
| 833 | throw new Error( |
| 834 | `Number of dimensions of repeat dims (${repeats.length}) cannot be smaller than number of dimensions of tensor (${this.dims.length})`, |
| 835 | ); |
| 836 | } |
| 837 | |
| 838 | // Optimization: if all repeats are 1, just clone with potentially expanded dims |
| 839 | if (repeats.every((r) => r === 1)) { |
| 840 | if (repeats.length === this.dims.length) { |
| 841 | return this.clone(); |
| 842 | } |
| 843 | // Need to expand dimensions by prepending 1s |
| 844 | const numPrependedDims = repeats.length - this.dims.length; |
| 845 | const newDims = Array(numPrependedDims).fill(1).concat(this.dims); |
| 846 | return new Tensor(this.type, this.data.slice(), newDims); |
| 847 | } |
| 848 | |
| 849 | // If repeats has more dimensions than the tensor, prepend 1s to tensor dims |
| 850 | const numPrependedDims = repeats.length - this.dims.length; |
| 851 | const expandedDims = Array(numPrependedDims).fill(1).concat(this.dims); |
| 852 | |
| 853 | // Calculate the output dimensions |
| 854 | const outputDims = expandedDims.map((dim, i) => dim * repeats[i]); |
| 855 | |
| 856 | // Calculate total output size |
| 857 | const outputSize = outputDims.reduce((a, b) => a * b, 1); |
| 858 | |
| 859 | // Allocate output data |
| 860 | const this_data = this.data; |
| 861 | // @ts-ignore |
| 862 | const data = new this_data.constructor(outputSize); |
| 863 | |
| 864 | // Calculate strides for the expanded input tensor |
| 865 | const inputStrides = dimsToStride(expandedDims); |
| 866 | const outputStrides = dimsToStride(outputDims); |
| 867 | |
| 868 | // Fill the output tensor |
| 869 | for (let i = 0; i < outputSize; ++i) { |
| 870 | // Convert flat index to multi-dimensional indices in output |
| 871 | let remaining = i; |
| 872 | let inputIndex = 0; |
| 873 | |
| 874 | for (let d = 0; d < outputDims.length; ++d) { |
| 875 | const outputCoord = Math.floor(remaining / outputStrides[d]); |
| 876 | remaining = remaining % outputStrides[d]; |
| 877 | |
| 878 | // Map output coordinate to input coordinate using modulo |
| 879 | const inputCoord = outputCoord % expandedDims[d]; |
| 880 | inputIndex += inputCoord * inputStrides[d]; |
| 881 | } |
| 882 | |
| 883 | data[i] = this_data[inputIndex]; |
| 884 | } |
| 885 | |
| 886 | return new Tensor(this.type, data, outputDims); |
| 887 | } |
| 888 |
no test coverage detected