Skip to content

Commit

Permalink
Feat: Tile
Browse files Browse the repository at this point in the history
  • Loading branch information
canacechan committed Apr 1, 2024
1 parent b02b601 commit cab5345
Show file tree
Hide file tree
Showing 32 changed files with 3,534 additions and 1 deletion.
43 changes: 43 additions & 0 deletions docs/framework/operators/tensor/tensor.tile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# TensorTrait::tile

```rust
fn tile(self: @Tensor<T>, repeats: Span<usize>) -> Tensor<T>;
```

Constructs a tensor by tiling a given tensor. This is the same as function tile in Numpy, but no broadcast.

For example A = [[1, 2], [3, 4]], B = [1, 2], tile(A, B) = [[1, 2, 1, 2], [3, 4, 3, 4]]

## Args

* `tensor`(`@Tensor<T>`) - Input tensor of any shape.
* `repeats`(Span<usize>) - 1D usize array of the same length as input's dimension number, includes numbers of repeated copies along input's dimensions.

## Returns

* Output tensor of the same dimensions and type as tensor input. output_dim[i] = input_dim[i] * repeats[i].

## Examples

```rust
use orion::operators::tensor::{I32Tensor, I32TensorAdd};
use core::array::{ArrayTrait, SpanTrait};
use orion::operators::tensor::{TensorTrait, Tensor};
use orion::utils::{assert_eq, assert_seq_eq};
use orion::operators::tensor::I32TensorPartialEq;


fn example() -> Tensor<i32> {
let mut shape = ArrayTrait::<usize>::new();
shape.append(1);
shape.append(2);

let mut data = ArrayTrait::new();
data.append(2);
data.append(1);
let input_0 = TensorTrait::new(shape.span(), data.span());

return input_0.tile(array![1, 4].span());
}
>>> [[2, 1, 2, 1, 2, 1, 2, 1]]
```
76 changes: 76 additions & 0 deletions nodegen/node/tile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import numpy as np
from nodegen.node import RunAll
from ..helpers import make_test, to_fp, Tensor, Dtype, FixedImpl, Trait, get_data_statement


class Tile(RunAll):

@staticmethod
# We test here with fp8x23 implementation.
def fp8x23():
x = np.random.randint(-3, 3, (2, 2, 4, 5)).astype(np.float64)
k = np.random.randint(0, 5, (4))
y = np.tile(x, k)

x = Tensor(Dtype.FP8x23, x.shape, to_fp(
x.flatten(), FixedImpl.FP8x23))
y = Tensor(Dtype.FP8x23, y.shape, to_fp(
y.flatten(), FixedImpl.FP8x23))

name = "tile_fp8x23"
make_test([x], y, f"input_0.tile(array!{k.tolist()}.span())", name)

@staticmethod
# We test here with fp16x16 implementation.
def fp16x16():
x = np.random.randint(-3, 3, (4, 7, 9)).astype(np.float64)
k = np.random.randint(0, 5, (3))
y = np.tile(x, k)

x = Tensor(Dtype.FP16x16, x.shape, to_fp(
x.flatten(), FixedImpl.FP16x16))
y = Tensor(Dtype.FP16x16, y.shape, to_fp(
y.flatten(), FixedImpl.FP16x16))

name = "tile_fp16x16"
make_test([x], y, f"input_0.tile(array!{k.tolist()}.span())", name)

@staticmethod
# We test here with i8 implementation.
def i8():
x = np.random.randint(0, 6, (5)).astype(np.int8)
k = np.random.randint(0, 5, (1))
y = np.tile(x, k)

x = Tensor(Dtype.I8, x.shape, x.flatten())
y = Tensor(Dtype.I8, y.shape, y.flatten())

name = "tile_i8"
make_test([x], y, f"input_0.tile(array!{k.tolist()}.span())", name)

@staticmethod
# We test here with i32 implementation.
def i32():
x = np.random.randint(0, 6, (5, 8)).astype(np.int32)
k = np.random.randint(0, 5, (2))
y = np.tile(x, k)

x = Tensor(Dtype.I32, x.shape, x.flatten())
y = Tensor(Dtype.I32, y.shape, y.flatten())

name = "tile_i32"
make_test([x], y, f"input_0.tile(array!{k.tolist()}.span())", name)

@staticmethod
# We test here with u32 implementation.
def u32():
x = np.random.randint(0, 6, (1, 2)).astype(np.uint32)
k = np.random.randint(0, 5, (2))
y = np.tile(x, k)

x = Tensor(Dtype.U32, x.shape, x.flatten())
y = Tensor(Dtype.U32, y.shape, y.flatten())

name = "tile_u32"
make_test([x], y, f"input_0.tile(array!{k.tolist()}.span())", name)

45 changes: 45 additions & 0 deletions src/operators/tensor/core.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5858,6 +5858,51 @@ trait TensorTrait<T> {
values: Option<Span<T>>,
values_tensor: Option<Tensor<T>>
) -> Tensor<T>;
/// # TensorTrait::tile
///
/// ```rust
/// fn tile(self: @Tensor<T>, repeats: Span<usize>) -> Tensor<T>;
/// ```
///
/// Constructs a tensor by tiling a given tensor. This is the same as function tile in Numpy, but no broadcast.
///
/// For example A = [[1, 2], [3, 4]], B = [1, 2], tile(A, B) = [[1, 2, 1, 2], [3, 4, 3, 4]]
///
/// ## Args
///
/// * `tensor`(`@Tensor<T>`) - Input tensor of any shape.
/// * `repeats`(Span<usize>) - 1D usize array of the same length as input's dimension number, includes numbers of repeated copies along input's dimensions.
///
/// ## Returns
///
/// * Output tensor of the same dimensions and type as tensor input. output_dim[i] = input_dim[i] * repeats[i].
///
/// ## Examples
///
/// ```rust
/// use orion::operators::tensor::{I32Tensor, I32TensorAdd};
/// use core::array::{ArrayTrait, SpanTrait};
/// use orion::operators::tensor::{TensorTrait, Tensor};
/// use orion::utils::{assert_eq, assert_seq_eq};
/// use orion::operators::tensor::I32TensorPartialEq;
///
///
/// fn example() -> Tensor<i32> {
/// let mut shape = ArrayTrait::<usize>::new();
/// shape.append(1);
/// shape.append(2);
///
/// let mut data = ArrayTrait::new();
/// data.append(2);
/// data.append(1);
/// let input_0 = TensorTrait::new(shape.span(), data.span());
///
/// return input_0.tile(array![1, 4].span());
/// }
/// >>> [[2, 1, 2, 1, 2, 1, 2, 1]]
/// ```
///
fn tile(self: @Tensor<T>, repeats: Span<usize>) -> Tensor<T>;
}

/// Cf: TensorTrait::new docstring
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_bool.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,10 @@ impl BoolTensor of TensorTrait<bool> {
) -> Tensor<bool> {
panic(array!['not supported!'])
}

fn tile(self: @Tensor<bool>, repeats: Span<usize>) -> Tensor<bool> {
panic(array!['not supported!'])
}
}

/// Implements partial equal for two `Tensor<bool>` using the `PartialEq` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_complex64.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,10 @@ impl Complex64Tensor of TensorTrait<complex64> {
) -> Tensor<complex64> {
panic(array!['not supported!'])
}

fn tile(self: @Tensor<complex64>, repeats: Span<usize>) -> Tensor<complex64> {
panic(array!['not supported!'])
}
}

/// Implements addition for `Tensor<complex64>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_fp16x16.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,10 @@ impl FP16x16Tensor of TensorTrait<FP16x16> {
self, default_list, default_tensor, keys, keys_tensor, values, values_tensor
)
}

fn tile(self: @Tensor<FP16x16>, repeats: Span<usize>) -> Tensor<FP16x16> {
math::tile::tile(*self, repeats)
}
}

/// Implements addition for `Tensor<FP16x16>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_fp16x16wide.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,10 @@ impl FP16x16WTensor of TensorTrait<FP16x16W> {
self, default_list, default_tensor, keys, keys_tensor, values, values_tensor
)
}

fn tile(self: @Tensor<FP16x16W>, repeats: Span<usize>) -> Tensor<FP16x16W> {
math::tile::tile(*self, repeats)
}
}

/// Implements addition for `Tensor<FP16x16W>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_fp32x32.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,10 @@ impl FP32x32Tensor of TensorTrait<FP32x32> {
self, default_list, default_tensor, keys, keys_tensor, values, values_tensor
)
}

fn tile(self: @Tensor<FP32x32>, repeats: Span<usize>) -> Tensor<FP32x32> {
math::tile::tile(*self, repeats)
}
}

/// Implements addition for `Tensor<FP32x32>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_fp64x64.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,10 @@ impl FP64x64Tensor of TensorTrait<FP64x64> {
self, default_list, default_tensor, keys, keys_tensor, values, values_tensor
)
}

fn tile(self: @Tensor<FP64x64>, repeats: Span<usize>) -> Tensor<FP64x64> {
math::tile::tile(*self, repeats)
}
}

/// Implements addition for `Tensor<FP64x64>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_fp8x23.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,10 @@ impl FP8x23Tensor of TensorTrait<FP8x23> {
self, default_list, default_tensor, keys, keys_tensor, values, values_tensor
)
}

fn tile(self: @Tensor<FP8x23>, repeats: Span<usize>) -> Tensor<FP8x23> {
math::tile::tile(*self, repeats)
}
}

/// Implements addition for `Tensor<FP8x23>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_fp8x23wide.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,10 @@ impl FP8x23WTensor of TensorTrait<FP8x23W> {
self, default_list, default_tensor, keys, keys_tensor, values, values_tensor
)
}

fn tile(self: @Tensor<FP8x23W>, repeats: Span<usize>) -> Tensor<FP8x23W> {
math::tile::tile(*self, repeats)
}
}

/// Implements addition for `Tensor<FP8x23W>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_i32.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,10 @@ impl I32Tensor of TensorTrait<i32> {
self, default_list, default_tensor, keys, keys_tensor, values, values_tensor
)
}

fn tile(self: @Tensor<i32>, repeats: Span<usize>) -> Tensor<i32> {
math::tile::tile(*self, repeats)
}
}

/// Implements addition for `Tensor<i32>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_i8.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,10 @@ impl I8Tensor of TensorTrait<i8> {
self, default_list, default_tensor, keys, keys_tensor, values, values_tensor
)
}

fn tile(self: @Tensor<i8>, repeats: Span<usize>) -> Tensor<i8> {
math::tile::tile(*self, repeats)
}
}

/// Implements addition for `Tensor<i8>` using the `Add` trait.
Expand Down
4 changes: 4 additions & 0 deletions src/operators/tensor/implementations/tensor_u32.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,10 @@ impl U32Tensor of TensorTrait<u32> {
self, default_list, default_tensor, keys, keys_tensor, values, values_tensor
)
}

fn tile(self: @Tensor<u32>, repeats: Span<usize>) -> Tensor<u32> {
math::tile::tile(*self, repeats)
}
}

/// Implements addition for `Tensor<u32>` using the `Add` trait.
Expand Down
1 change: 1 addition & 0 deletions src/operators/tensor/math.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,4 @@ mod hann_window;
mod hamming_window;
mod blackman_window;
mod scatter_nd;
mod tile;
42 changes: 42 additions & 0 deletions src/operators/tensor/math/tile.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use orion::numbers::fixed_point::core::FixedTrait;
use orion::numbers::NumberTrait;
use orion::operators::tensor::core::{Tensor, TensorTrait};

fn tile<
T,
MAG,
impl TTensor: TensorTrait<T>,
impl TNumber: NumberTrait<T, MAG>,
impl TAdd: Add<T>,
impl TSub: Sub<T>,
impl TMul: Mul<T>,
impl TDiv: Div<T>,
impl TTensorAdd: Add<Tensor<T>>,
impl TPartialOrd: PartialOrd<T>,
impl TAddEq: AddEq<T>,
impl TCopy: Copy<T>,
impl TDrop: Drop<T>,
>(self: Tensor<T>, repeats: Span<usize>) -> Tensor<T> {
let mut tensor = self;
let len = (tensor.shape).len();
let mut i: usize = 0;
while i != len {
let mut k = len - i - 1;
let mut arr: Array<Tensor<T>> = array![];
let mut j: usize = 0;
if (*repeats.at(k) == 0) {
tensor = TensorTrait::<T>::new(array![0].span(), array![].span());
i = len;
} else {
while j != *repeats.at(k) {
arr.append(tensor);
j += 1;
};
if (arr.len() > 1) {
tensor = TensorTrait::concat(arr.span(), k);
}
i += 1;
}
};
tensor
}
7 changes: 6 additions & 1 deletion tests/nodes.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,11 @@ mod label_encoder_fp8x23_default;
mod label_encoder_i8_default;
mod label_encoder_i32_default;
mod label_encoder_u32_default;
mod tile_u32;
mod tile_fp16x16;
mod tile_fp8x23;
mod tile_i32;
mod tile_i8;
mod gather_fp16x16_3d_default;
mod gather_fp16x16_3d_axis1;
mod gather_fp16x16_3d_axis2;
Expand Down Expand Up @@ -984,4 +989,4 @@ mod argmax_keepdims_select_last_index;
mod argmax_negative_axis_keepdims;
mod argmax_negative_axis_keepdims_select_last_index;
mod argmax_no_keepdims;
mod argmax_no_keepdims_select_last_index;
mod argmax_no_keepdims_select_last_index;
20 changes: 20 additions & 0 deletions tests/nodes/tile_fp16x16.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
mod input_0;
mod output_0;


use orion::operators::tensor::FP16x16TensorPartialEq;
use orion::operators::tensor::{FP16x16Tensor, FP16x16TensorAdd};
use orion::operators::tensor::{TensorTrait, Tensor};
use core::array::{ArrayTrait, SpanTrait};
use orion::utils::{assert_eq, assert_seq_eq};

#[test]
#[available_gas(2000000000)]
fn test_tile_fp16x16() {
let input_0 = input_0::input_0();
let z_0 = output_0::output_0();

let y_0 = input_0.tile(array![4, 1, 2].span());

assert_eq(y_0, z_0);
}
Loading

0 comments on commit cab5345

Please sign in to comment.