From ecca11340a154324e7a67c8aead05f97523b8743 Mon Sep 17 00:00:00 2001 From: Yulong Wang <7679871+fs-eire@users.noreply.github.com> Date: Tue, 11 Jul 2023 21:07:36 -0700 Subject: [PATCH] [js/common] allow creating (u)int64 tensors in 2 ways (#16541) ### Description allow creating (u)int64 tensors from either a number array or a bigint array. before: ```js // TypeScript think is good, but actually does not work // runtime error: Uncaught TypeError: Cannot convert 1 to a BigInt const myTensor1 = new Tensor('int64', [1, 2, 3, 4], [2, 2]); // runtime good, but TypeScript thinks myTensor2 is a string tensor const myTensor2 = new Tensor('int64', [1n, 2n, 3n, 4n], [2, 2]); ``` after: ```js // both work at runtime and TypeScript populates the correct types const myTensor1 = new Tensor('int64', [1, 2, 3, 4], [2, 2]); const myTensor2 = new Tensor('int64', [1n, 2n, 3n, 4n], [2, 2]); ``` --- js/common/lib/tensor-impl.ts | 21 ++++++++++++--- js/common/lib/tensor.ts | 50 ++++++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/js/common/lib/tensor-impl.ts b/js/common/lib/tensor-impl.ts index a133ce5d26..2ac13d42b9 100644 --- a/js/common/lib/tensor-impl.ts +++ b/js/common/lib/tensor-impl.ts @@ -103,11 +103,24 @@ export class Tensor implements TensorInterface { // Throw error here because when user try to use number array as data, // e.g. new Tensor('float16', [1, 2, 3, 4], dims)), it will actually call // Uint16Array.from(arg1) which generates wrong data. - throw new TypeError(`Unsupported tensor type: ${arg0}.`); + throw new TypeError( + 'Creating a float16 tensor from number array is not supported. Please use Uint16Array as data.'); + } else if (arg0 === 'uint64' || arg0 === 'int64') { + // use 'as any' here because: + // 1. TypeScript's check on type of 'Array.isArray()' does not work with readonly arrays. + // see https://github.com/microsoft/TypeScript/issues/17002 + // 2. TypeScript's check on union type of '(BigInt64ArrayConstructor|BigUint64ArrayConstructor).from()' does + // not accept parameter mapFn. + // 3. parameters of 'SupportedTypedArrayConstructors.from()' does not match the requirement of the union + // type. + + // assume 'arg1' is of type "readonly number[]|readonly bigint[]" here. + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data = (typedArrayConstructor as any).from(arg1, BigInt); } else { - // use 'as any' here because TypeScript's check on type of 'SupportedTypedArrayConstructors.from()' produces - // incorrect results. - // 'typedArrayConstructor' should be one of the typed array prototype objects. + // assume 'arg1' is of type "readonly number[]" here. + // eslint-disable-next-line @typescript-eslint/no-explicit-any data = (typedArrayConstructor as any).from(arg1); } diff --git a/js/common/lib/tensor.ts b/js/common/lib/tensor.ts index d827f50272..90e3be9acb 100644 --- a/js/common/lib/tensor.ts +++ b/js/common/lib/tensor.ts @@ -88,7 +88,7 @@ export interface TensorConstructor { * Construct a new string tensor object from the given type, data and dims. * * @param type - Specify the element type. - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(type: 'string', data: Tensor.DataTypeMap['string']|readonly string[], @@ -98,19 +98,30 @@ export interface TensorConstructor { * Construct a new bool tensor object from the given type, data and dims. * * @param type - Specify the element type. - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(type: 'bool', data: Tensor.DataTypeMap['bool']|readonly boolean[], dims?: readonly number[]): TypedTensor<'bool'>; + /** + * Construct a new 64-bit integer typed tensor object from the given type, data and dims. + * + * @param type - Specify the element type. + * @param data - Specify the tensor data. + * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. + */ + new( + type: T, data: Tensor.DataTypeMap[T]|readonly bigint[]|readonly number[], + dims?: readonly number[]): TypedTensor; + /** * Construct a new numeric tensor object from the given type, data and dims. * * @param type - Specify the element type. - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ - new>( + new>( type: T, data: Tensor.DataTypeMap[T]|readonly number[], dims?: readonly number[]): TypedTensor; // #endregion @@ -119,7 +130,7 @@ export interface TensorConstructor { /** * Construct a new float32 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Float32Array, dims?: readonly number[]): TypedTensor<'float32'>; @@ -127,7 +138,7 @@ export interface TensorConstructor { /** * Construct a new int8 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Int8Array, dims?: readonly number[]): TypedTensor<'int8'>; @@ -135,7 +146,7 @@ export interface TensorConstructor { /** * Construct a new uint8 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Uint8Array, dims?: readonly number[]): TypedTensor<'uint8'>; @@ -143,7 +154,7 @@ export interface TensorConstructor { /** * Construct a new uint16 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Uint16Array, dims?: readonly number[]): TypedTensor<'uint16'>; @@ -151,7 +162,7 @@ export interface TensorConstructor { /** * Construct a new int16 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Int16Array, dims?: readonly number[]): TypedTensor<'int16'>; @@ -159,7 +170,7 @@ export interface TensorConstructor { /** * Construct a new int32 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Int32Array, dims?: readonly number[]): TypedTensor<'int32'>; @@ -167,7 +178,7 @@ export interface TensorConstructor { /** * Construct a new int64 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: BigInt64Array, dims?: readonly number[]): TypedTensor<'int64'>; @@ -175,7 +186,7 @@ export interface TensorConstructor { /** * Construct a new string tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: readonly string[], dims?: readonly number[]): TypedTensor<'string'>; @@ -183,7 +194,7 @@ export interface TensorConstructor { /** * Construct a new bool tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: readonly boolean[], dims?: readonly number[]): TypedTensor<'bool'>; @@ -191,7 +202,7 @@ export interface TensorConstructor { /** * Construct a new float64 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Float64Array, dims?: readonly number[]): TypedTensor<'float64'>; @@ -199,7 +210,7 @@ export interface TensorConstructor { /** * Construct a new uint32 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Uint32Array, dims?: readonly number[]): TypedTensor<'uint32'>; @@ -207,7 +218,7 @@ export interface TensorConstructor { /** * Construct a new uint64 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: BigUint64Array, dims?: readonly number[]): TypedTensor<'uint64'>; @@ -220,15 +231,16 @@ export interface TensorConstructor { * Construct a new tensor object from the given type, data and dims. * * @param type - Specify the element type. - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ - new(type: Tensor.Type, data: Tensor.DataType|readonly number[]|readonly boolean[], dims?: readonly number[]): Tensor; + new(type: Tensor.Type, data: Tensor.DataType|readonly number[]|readonly string[]|readonly bigint[]|readonly boolean[], + dims?: readonly number[]): Tensor; /** * Construct a new tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Tensor.DataType, dims?: readonly number[]): Tensor;