Skip to content

Commit

Permalink
Merge pull request #20 from eduardoleao052/develop
Browse files Browse the repository at this point in the history
New `utils.test.ts` files, with `utils` unit tests. Types folder, and Nested Array type.
  • Loading branch information
eduardoleao052 authored Apr 3, 2024
2 parents e8c6802 + 468e607 commit 28303bf
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 17 deletions.
3 changes: 3 additions & 0 deletions src/types/utils.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
type NestedArray<T> = T | NestedArray<T>[];

export default NestedArray;
48 changes: 31 additions & 17 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import { Tensor } from "./tensor";
import NestedArray from "./types/utils.types";

/**
* Recursively gets the shape (length of every dimension) of the Tensor.
* @param {object} data - Iterable containing the data to be stored in the Tensor.
* @param {object} shape - Length of every dimension of the Tensor.
* @returns {object} Length of every dimension of the Tensor.
*/
export function getShape(data: Array<any> | number, shape: Array<any> = []): Array<any> {

export function getShape(
data: NestedArray<number> | number,
shape: Array<number> = []
): Array<number> {
// Edge case empty array:
if (data instanceof Array && data.length === 0) {
return [0];
}

// Base case:
if (typeof data === "number") {
// Return [1] for integers:
Expand All @@ -16,7 +26,8 @@ export function getShape(data: Array<any> | number, shape: Array<any> = []): Arr
// Return shape for objects:
return shape;
}
if (typeof data[0] === "number") {

if (typeof data[0] === "number" && Array.isArray(data)) {
for (const element of data) {
if (typeof element != "number") {
throw new Error("The requested array has an inhomogeneous shape.");
Expand All @@ -27,20 +38,22 @@ export function getShape(data: Array<any> | number, shape: Array<any> = []): Arr
return shape;
}

let elementLength = data[0].length;
// Iterate over elements in dimention to check if all have the same length (homogenous shape):
for (const element of data) {
// Throw error if the shape is inhomogenous:
if (elementLength != element.length) {
throw new Error("The requested array has an inhomogeneous shape.");
}
elementLength = element.length;
// Throw error if the element is not a number or another iterable:
if (typeof element != "object" && typeof element != "number") {
throw new Error("TypeError: the input data is not a number.");
if (Array.isArray(data[0])) {
let elementLength = data[0].length;
// Iterate over elements in dimention to check if all have the same length (homogenous shape):
for (const element of data) {
// Throw error if the element is not a number or another iterable:
if (typeof element != "object" && typeof element != "number") {
throw new Error("TypeError: the input data is not a number.");
} else if (Array.isArray(element) && elementLength != element.length) {
// Throw error if the shape is inhomogenous:
throw new Error("The requested array has an inhomogeneous shape.");
} else if (Array.isArray(element)) {
elementLength = element.length;
}
}
shape.push(data.length);
}
shape.push(data.length);
return getShape(data[0], shape);
}

Expand All @@ -49,7 +62,7 @@ export function getShape(data: Array<any> | number, shape: Array<any> = []): Arr
* @param {object} a - Any numeric iterable or number.
* @returns {object} Original iterable in an Array format.
*/
export function assureArray(a: Tensor | Array<any> | number): Array<any> {
export function assureArray(a: Tensor | Array<number> | number): Array<number> {
if (Array.isArray(a)) {
return a;
} else if (typeof a === "number") {
Expand All @@ -65,7 +78,9 @@ export function assureArray(a: Tensor | Array<any> | number): Array<any> {
* @param {object} a - Any numeric iterable or number.
* @returns {object} Original data in a vanilla format.
*/
export function getData(a: Tensor | Array<any> | number): Array<any> | number {
export function getData(
a: Tensor | Array<number> | number
): Array<number> | number {
if (Array.isArray(a)) {
return a;
}
Expand All @@ -74,4 +89,3 @@ export function getData(a: Tensor | Array<any> | number): Array<any> | number {
}
return a._data;
}

1 change: 1 addition & 0 deletions tests/benchmarks/formatTrainingResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export function formatTrainingResults(

return {
"Task Name": row["Task Name"],

"Average Time (ms)": Number(row["Average Time (ns)"]) / 1e6,
Margin: row["Margin"],
Samples: row["Samples"],
Expand Down
107 changes: 107 additions & 0 deletions tests/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { getShape, assureArray, getData } from '../src/utils';

describe('getShape with different data inputs', () => {
test('Given data is scalar should return an array of single number',() =>{
const data = 1;

const result = getShape(data);

expect(result).toEqual([1]);
})

test('Given data is an 1 dimensional Tensor should return an array of single number', () => {
const data = [1];

const result = getShape(data);

expect(result).toEqual([1]);
})

test('Given a data is a 2 dimensional Tensor should return an array of array of the shape of the data', () => {
const data = [[1,2],[3,4]];

const result = getShape(data);

expect(result).toEqual([2,2]);
})

test('Given the data is a 3 dimensional Tensor should return an array of the shape of the data',() => {
const data = [[[3,4]],[[7,8]]];

const result = getShape(data);

expect(result).toEqual([2,1,2]);
})

test('Given data is inhomogeneous shape it should throw an error', () => {
const data = [[1],[2,3]];

expect(() => getShape(data)).toThrow('The requested array has an inhomogeneous shape.')
})

test('Given data is an empty array should return an empty shape', () => {
const data:number[] = [];

const result = getShape(data);

expect(result).toEqual([0]);
});

test('Given a nested array with varying lengths at the same level should throw an error', () => {
const data = [[1, 2], [3, 4, 5], [6]];

expect(() => getShape(data)).toThrow('The requested array has an inhomogeneous shape.');
});

test('Given data is a very large array should return the correct shape quickly', () => {
const data = new Array(10000).fill(0);

const result = getShape(data);

expect(result).toEqual([10000]);
});

test('Given data is a deeply nested array should return the correct shape', () => {
const data = [[[[1]]]];

const result = getShape(data);

expect(result).toEqual([1, 1, 1, 1]);
});
})

describe('Assure array', () => {
test('Given data is an array should return input array', () => {
const data = [1,2,3,4];

const result = assureArray(data);

expect(result).toEqual(data);
})

test('Given data is a scalar should return an array with the scalar as array element',()=>{
const data = 1;

const result = assureArray(data);

expect(result).toEqual([data]);
})
})

describe('Get data', () => {
test('Given data is an array, should return the array',() => {
const data = [1,2,3,4];

const result = getData(data);

expect(result).toEqual(data);
})

test('Given data is a scalar, should return the scalar', () => {
const data = 1;

const result = getData(data);

expect(result).toBe(result);
})
})

0 comments on commit 28303bf

Please sign in to comment.