Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: IsNaN #474

Merged
merged 4 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
* [tensor.pow](framework/operators/tensor/tensor.pow.md)
* [tensor.sequence\_erase](framework/operators/tensor/tensor.sequence\_erase.md)
* [tensor.sequence\_insert](framework/operators/tensor/tensor.sequence\_insert.md)
* [tensor.is\_nan](framework/operators/tensor/tensor.is\_nan.md)
* [Neural Network](framework/operators/neural-network/README.md)
* [nn.relu](framework/operators/neural-network/nn.relu.md)
* [nn.leaky\_relu](framework/operators/neural-network/nn.leaky\_relu.md)
Expand Down
3 changes: 2 additions & 1 deletion docs/framework/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,6 @@ You can see below the list of current supported ONNX Operators:
| [ReduceL2](operators/tensor/tensor.reduce\_l2.md) | :white\_check\_mark: |
| [SequenceErase](operators/tensor/tensor.sequence\_erase.md) | :white\_check\_mark: |
| [SequenceInsert](operators/tensor/tensor.sequence\_insert.md) | :white\_check\_mark: |
| [IsNaN](operators/tensor/tensor.is\_nan.md) | :white\_check\_mark: |

Current Operators support: **82/156 (53%)**
Current Operators support: **83/156 (53%)**
1 change: 1 addition & 0 deletions docs/framework/operators/tensor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ use orion::operators::tensor::TensorTrait;
| [`tensor.binarizer`](tensor.binarizer.md) | Maps the values of a tensor element-wise to 0 or 1 based on the comparison against a threshold value. |
| [`tensor.array_feature_extractor`](tensor.array\_feature\_extractor.md) | Selects elements of the input tensor based on the indices passed applied to the last tensor axis. |
| [`tensor.reduce_min`](tensor.reduce\_min.md) | Computes the min of the input tensor's elements along the provided axes. |
| [`tensor.is_nan`](tensor.is\_nan.md) | Returns which elements of the input are NaN. |

## Arithmetic Operations

Expand Down
37 changes: 37 additions & 0 deletions docs/framework/operators/tensor/tensor.is_nan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## tensor.is_nan

```rust
fn is_nan(self: @Tensor<T>) -> Tensor<bool>;
```

Maps NaN to true and other values to false.

## Args

* `self`(`@Tensor<T>`) - The input tensor.

## Returns

A new `Tensor<bool>` instance with entries set to true iff the input tensors corresponding element was NaN.

## Examples

use array::{ArrayTrait, SpanTrait};
use orion::operators::tensor::{BoolTensor, TensorTrait, Tensor, FP8x23Tensor};
use orion::numbers::{FixedTrait, FP8x23};

fn is_nan_example() -> Tensor<bool> {
let mut shape = ArrayTrait::<usize>::new();
shape.append(4);

let mut data = ArrayTrait::new();
data.append(FP8x23 { mag: 10066329, sign: true });
data.append(FP8x23 { mag: 0, sign: false });
data.append(FixedTrait::NaN());
data.append(FP8x23 { mag: 23488102, sign: false });
let tensor = TensorTrait::new(shape.span(), data.span())

return tensor.is_nan();
}
>>> [false, false, true, false]
```
39 changes: 39 additions & 0 deletions nodegen/node/is_nan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import numpy as np
from nodegen.node import RunAll
from ..helpers import make_test, to_fp, Tensor, Dtype, FixedImpl


# NaN is represented with -0
NaN = -0

class Is_nan(RunAll):

@staticmethod
def is_nan_fp8x23():
def default():
input_0 = np.array([-1.2, 0, NaN, 2.8, NaN, NaN], dtype=np.float64)
output = np.array([False, False, True, False, True, True], dtype=bool)

input_0 = Tensor(Dtype.FP8x23, input_0.shape, to_fp(
input_0.flatten(), FixedImpl.FP8x23))
output = Tensor(Dtype.BOOL, output.shape, output.flatten())

name = "is_nan_fp8x23"
make_test([input_0], output, "TensorTrait::is_nan(@input_0)", name)

default()

@staticmethod
def is_nan_fp16x16():
def default():
input_0 = np.array([-1.2, 0, NaN, 2.8, NaN, NaN], dtype=np.float64)
output = np.array([False, False, True, False, True, True], dtype=bool)

input_0 = Tensor(Dtype.FP16x16, input_0.shape, to_fp(
input_0.flatten(), FixedImpl.FP16x16))
output = Tensor(Dtype.BOOL, output.shape, output.flatten())

name = "is_nan_fp16x16"
make_test([input_0], output, "TensorTrait::is_nan(@input_0)", name)

default()
40 changes: 40 additions & 0 deletions src/operators/tensor/core.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ impl TensorSerde<T, impl TSerde: Serde<T>, impl TDrop: Drop<T>> of Serde<Tensor<
/// binarizer - Maps the values of a tensor element-wise to 0 or 1 based on the comparison against a threshold value.
/// array_feature_extractor - Selects elements of the input tensor based on the indices passed applied to the last tensor axis.
/// reduce_min - Computes the min of the input tensor's elements along the provided axes.
/// is_nan - Returns which elements of the input are NaN.
///
trait TensorTrait<T> {
/// # tensor.new
Expand Down Expand Up @@ -4416,6 +4417,45 @@ trait TensorTrait<T> {
/// ```
///
fn sequence_length(self: Array<Tensor<T>>) -> Tensor<u32>;
/// ## tensor.is_nan
///
/// ```rust
/// fn is_nan(self: @Tensor<T>) -> Tensor<bool>;
/// ```
///
/// Maps NaN to true and other values to false.
///
/// ## Args
///
/// * `self`(`@Tensor<T>`) - The input tensor.
///
/// ## Returns
///
/// A new `Tensor<bool>` instance with entries set to true iff the input tensors corresponding element was NaN.
///
/// ## Examples
///
/// use array::{ArrayTrait, SpanTrait};
/// use orion::operators::tensor::{BoolTensor, TensorTrait, Tensor, FP8x23Tensor};
/// use orion::numbers::{FixedTrait, FP8x23};
///
/// fn is_nan_example() -> Tensor<bool> {
/// let mut shape = ArrayTrait::<usize>::new();
/// shape.append(4);
///
/// let mut data = ArrayTrait::new();
/// data.append(FP8x23 { mag: 10066329, sign: true });
/// data.append(FP8x23 { mag: 0, sign: false });
/// data.append(FixedTrait::NaN());
/// data.append(FP8x23 { mag: 23488102, sign: false });
/// let tensor = TensorTrait::new(shape.span(), data.span())
///
/// return tensor.is_nan();
/// }
/// >>> [false, false, true, false]
/// ```
///
fn is_nan(self: @Tensor<T>) -> Tensor<bool>;
}

/// 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 @@ -392,6 +392,10 @@ impl BoolTensor of TensorTrait<bool> {
fn sequence_insert(self: Array<Tensor<bool>>, tensor: @Tensor<bool>, position: Option<Tensor<i32>>) -> Array<Tensor<bool>> {
math::sequence_insert::sequence_insert(self, tensor, position)
}

fn is_nan(self: @Tensor<bool>) -> 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_fp16x16.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,10 @@ impl FP16x16Tensor of TensorTrait<FP16x16> {
fn sequence_insert(self: Array<Tensor<FP16x16>>, tensor: @Tensor<FP16x16>, position: Option<Tensor<i32>>) -> Array<Tensor<FP16x16>> {
math::sequence_insert::sequence_insert(self, tensor, position)
}

fn is_nan(self: @Tensor<FP16x16>) -> Tensor<bool> {
math::is_nan::is_nan(self)
}
}

/// 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 @@ -412,6 +412,10 @@ impl FP16x16WTensor of TensorTrait<FP16x16W> {
fn sequence_insert(self: Array<Tensor<FP16x16W>>, tensor: @Tensor<FP16x16W>, position: Option<Tensor<i32>>) -> Array<Tensor<FP16x16W>> {
math::sequence_insert::sequence_insert(self, tensor, position)
}

fn is_nan(self: @Tensor<FP16x16W>) -> Tensor<bool> {
math::is_nan::is_nan(self)
}
}

/// 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 @@ -443,6 +443,10 @@ impl FP32x32Tensor of TensorTrait<FP32x32> {
fn sequence_insert(self: Array<Tensor<FP32x32>>, tensor: @Tensor<FP32x32>, position: Option<Tensor<i32>>) -> Array<Tensor<FP32x32>> {
math::sequence_insert::sequence_insert(self, tensor, position)
}

fn is_nan(self: @Tensor<FP32x32>) -> Tensor<bool> {
math::is_nan::is_nan(self)
}
}

/// 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 @@ -445,6 +445,10 @@ impl FP64x64Tensor of TensorTrait<FP64x64> {
fn sequence_insert(self: Array<Tensor<FP64x64>>, tensor: @Tensor<FP64x64>, position: Option<Tensor<i32>>) -> Array<Tensor<FP64x64>> {
math::sequence_insert::sequence_insert(self, tensor, position)
}

fn is_nan(self: @Tensor<FP64x64>) -> Tensor<bool> {
math::is_nan::is_nan(self)
}
}

/// 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 @@ -443,6 +443,10 @@ impl FP8x23Tensor of TensorTrait<FP8x23> {
fn sequence_insert(self: Array<Tensor<FP8x23>>, tensor: @Tensor<FP8x23>, position: Option<Tensor<i32>>) -> Array<Tensor<FP8x23>> {
math::sequence_insert::sequence_insert(self, tensor, position)
}

fn is_nan(self: @Tensor<FP8x23>) -> Tensor<bool> {
math::is_nan::is_nan(self)
}
}

/// 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 @@ -402,6 +402,10 @@ impl FP8x23WTensor of TensorTrait<FP8x23W> {
fn sequence_insert(self: Array<Tensor<FP8x23W>>, tensor: @Tensor<FP8x23W>, position: Option<Tensor<i32>>) -> Array<Tensor<FP8x23W>> {
math::sequence_insert::sequence_insert(self, tensor, position)
}

fn is_nan(self: @Tensor<FP8x23W>) -> Tensor<bool> {
math::is_nan::is_nan(self)
}
}

/// 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 @@ -444,6 +444,10 @@ impl I32Tensor of TensorTrait<i32> {
fn sequence_insert(self: Array<Tensor<i32>>, tensor: @Tensor<i32>, position: Option<Tensor<i32>>) -> Array<Tensor<i32>> {
math::sequence_insert::sequence_insert(self, tensor, position)
}

fn is_nan(self: @Tensor<i32>) -> Tensor<bool> {
panic(array!['not supported!'])
}
}

/// 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 @@ -443,6 +443,10 @@ impl I8Tensor of TensorTrait<i8> {
fn sequence_insert(self: Array<Tensor<i8>>, tensor: @Tensor<i8>, position: Option<Tensor<i32>>) -> Array<Tensor<i8>> {
math::sequence_insert::sequence_insert(self, tensor, position)
}

fn is_nan(self: @Tensor<i8>) -> Tensor<bool> {
panic(array!['not supported!'])
}
}

/// 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 @@ -394,6 +394,10 @@ impl U32Tensor of TensorTrait<u32> {
fn sequence_insert(self: Array<Tensor<u32>>, tensor: @Tensor<u32>, position: Option<Tensor<i32>>) -> Array<Tensor<u32>> {
math::sequence_insert::sequence_insert(self, tensor, position)
}

fn is_nan(self: @Tensor<u32>) -> Tensor<bool> {
panic(array!['not supported!'])
}
}

/// 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 @@ -54,3 +54,4 @@ mod reduce_mean;
mod pow;
mod sequence_erase;
mod sequence_insert;
mod is_nan;
30 changes: 30 additions & 0 deletions src/operators/tensor/math/is_nan.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use array::ArrayTrait;
use option::OptionTrait;
use array::SpanTrait;

use orion::numbers::NumberTrait;
use orion::operators::tensor::core::{Tensor, TensorTrait};
use orion::operators::tensor::implementations::tensor_bool::BoolTensor;

/// Cf: TensorTrait::is_nan docstring
fn is_nan<
T,
MAG,
impl TNumber: NumberTrait<T, MAG>,
impl TTensor: TensorTrait<T>,
impl TCopy: Copy<T>,
impl TDrop: Drop<T>
>(x: @Tensor<T>) -> Tensor<bool> {
let mut data_result = ArrayTrait::<bool>::new();
let mut y: Span<T> = *x.data;
loop {
match y.pop_front() {
Option::Some(item) => {
data_result.append((*item).is_nan());
},
Option::None(_) => { break; }
};
};

return TensorTrait::new(*x.shape, data_result.span());
}
2 changes: 2 additions & 0 deletions tests/nodes.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -763,3 +763,5 @@ mod sequence_insert_fp8x23;
mod sequence_insert_i32;
mod sequence_insert_i8;
mod sequence_insert_u32;
mod is_nan_fp16x16;
mod is_nan_fp8x23;
22 changes: 22 additions & 0 deletions tests/nodes/is_nan_fp16x16.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
mod input_0;
mod output_0;


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

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

let y = TensorTrait::is_nan(@input_0);

assert_eq(y, z);
}
18 changes: 18 additions & 0 deletions tests/nodes/is_nan_fp16x16/input_0.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use array::{ArrayTrait, SpanTrait};
use orion::operators::tensor::{TensorTrait, Tensor};
use orion::operators::tensor::FP16x16Tensor;
use orion::numbers::{FixedTrait, FP16x16};

fn input_0() -> Tensor<FP16x16> {
let mut shape = ArrayTrait::<usize>::new();
shape.append(6);

let mut data = ArrayTrait::new();
data.append(FP16x16 { mag: 78643, sign: true });
data.append(FP16x16 { mag: 0, sign: false });
data.append(FixedTrait::NaN());
data.append(FP16x16 { mag: 183500, sign: false });
data.append(FixedTrait::NaN());
data.append(FixedTrait::NaN());
TensorTrait::new(shape.span(), data.span())
}
17 changes: 17 additions & 0 deletions tests/nodes/is_nan_fp16x16/output_0.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use array::{ArrayTrait, SpanTrait};
use orion::operators::tensor::{TensorTrait, Tensor};
use orion::operators::tensor::BoolTensor;

fn output_0() -> Tensor<bool> {
let mut shape = ArrayTrait::<usize>::new();
shape.append(6);

let mut data = ArrayTrait::new();
data.append(false);
data.append(false);
data.append(true);
data.append(false);
data.append(true);
data.append(true);
TensorTrait::new(shape.span(), data.span())
}
22 changes: 22 additions & 0 deletions tests/nodes/is_nan_fp8x23.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
mod input_0;
mod output_0;


use orion::utils::{assert_eq, assert_seq_eq};
use orion::operators::tensor::{TensorTrait, Tensor};
use orion::operators::tensor::FP8x23TensorPartialEq;
use orion::operators::tensor::BoolTensor;
use array::{ArrayTrait, SpanTrait};
use orion::operators::tensor::FP8x23Tensor;
use orion::operators::tensor::BoolTensorPartialEq;

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

let y = TensorTrait::is_nan(@input_0);

assert_eq(y, z);
}
Loading