Validating Matrix Operations Testing in javascript-algorithms
This test suite validates matrix operations and manipulations in JavaScript, covering essential matrix functions including multiplication, addition, subtraction, and shape calculations. The tests ensure robust matrix handling with comprehensive error checking and dimension validation.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
trekhleb/javascript-algorithms
src/algorithms/math/matrix/__tests__/Matrix.test.js
import * as mtrx from '../Matrix';
describe('Matrix', () => {
it('should throw when trying to add matrices of invalid shapes', () => {
expect(
() => mtrx.dot([0], [1]),
).toThrowError('Invalid matrix format');
expect(
() => mtrx.dot([[0]], [1]),
).toThrowError('Invalid matrix format');
expect(
() => mtrx.dot([[[0]]], [[1]]),
).toThrowError('Matrix is not of 2D shape');
expect(
() => mtrx.dot([[0]], [[1], [2]]),
).toThrowError('Matrices have incompatible shape for multiplication');
});
it('should calculate matrices dimensions', () => {
expect(mtrx.shape([])).toEqual([0]);
expect(mtrx.shape([
[],
])).toEqual([1, 0]);
expect(mtrx.shape([
[0],
])).toEqual([1, 1]);
expect(mtrx.shape([
[0, 0],
])).toEqual([1, 2]);
expect(mtrx.shape([
[0, 0],
[0, 0],
])).toEqual([2, 2]);
expect(mtrx.shape([
[0, 0, 0],
[0, 0, 0],
])).toEqual([2, 3]);
expect(mtrx.shape([
[0, 0],
[0, 0],
[0, 0],
])).toEqual([3, 2]);
expect(mtrx.shape([
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
])).toEqual([3, 3]);
expect(mtrx.shape([
[0],
[0],
[0],
])).toEqual([3, 1]);
expect(mtrx.shape([
[[0], [0], [0]],
[[0], [0], [0]],
[[0], [0], [0]],
])).toEqual([3, 3, 1]);
expect(mtrx.shape([
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
])).toEqual([3, 3, 3]);
});
it('should generate the matrix of zeros', () => {
expect(mtrx.zeros([1, 0])).toEqual([
[],
]);
expect(mtrx.zeros([1, 1])).toEqual([
[0],
]);
expect(mtrx.zeros([1, 3])).toEqual([
[0, 0, 0],
]);
expect(mtrx.zeros([3, 3])).toEqual([
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
]);
expect(mtrx.zeros([3, 3, 1])).toEqual([
[[0], [0], [0]],
[[0], [0], [0]],
[[0], [0], [0]],
]);
});
it('should generate the matrix with custom values', () => {
expect(mtrx.generate([1, 0], () => 1)).toEqual([
[],
]);
expect(mtrx.generate([1, 1], () => 1)).toEqual([
[1],
]);
expect(mtrx.generate([1, 3], () => 1)).toEqual([
[1, 1, 1],
]);
expect(mtrx.generate([3, 3], () => 1)).toEqual([
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
]);
expect(mtrx.generate([3, 3, 1], () => 1)).toEqual([
[[1], [1], [1]],
[[1], [1], [1]],
[[1], [1], [1]],
]);
});
it('should generate a custom matrix based on specific cell indices', () => {
const indicesCallback = jest.fn((indices) => {
return indices[0] * 10 + indices[1];
});
const m = mtrx.generate([3, 3], indicesCallback);
expect(indicesCallback).toHaveBeenCalledTimes(3 * 3);
expect(indicesCallback.mock.calls[0][0]).toEqual([0, 0]);
expect(indicesCallback.mock.calls[1][0]).toEqual([0, 1]);
expect(indicesCallback.mock.calls[2][0]).toEqual([0, 2]);
expect(indicesCallback.mock.calls[3][0]).toEqual([1, 0]);
expect(indicesCallback.mock.calls[4][0]).toEqual([1, 1]);
expect(indicesCallback.mock.calls[5][0]).toEqual([1, 2]);
expect(indicesCallback.mock.calls[6][0]).toEqual([2, 0]);
expect(indicesCallback.mock.calls[7][0]).toEqual([2, 1]);
expect(indicesCallback.mock.calls[8][0]).toEqual([2, 2]);
expect(m).toEqual([
[0, 1, 2],
[10, 11, 12],
[20, 21, 22],
]);
});
it('should multiply two matrices', () => {
let c;
c = mtrx.dot(
[
[1, 2],
[3, 4],
],
[
[5, 6],
[7, 8],
],
);
expect(mtrx.shape(c)).toEqual([2, 2]);
expect(c).toEqual([
[19, 22],
[43, 50],
]);
c = mtrx.dot(
[
[1, 2],
[3, 4],
],
[
[5],
[6],
],
);
expect(mtrx.shape(c)).toEqual([2, 1]);
expect(c).toEqual([
[17],
[39],
]);
c = mtrx.dot(
[
[1, 2, 3],
[4, 5, 6],
],
[
[7, 8],
[9, 10],
[11, 12],
],
);
expect(mtrx.shape(c)).toEqual([2, 2]);
expect(c).toEqual([
[58, 64],
[139, 154],
]);
c = mtrx.dot(
[
[3, 4, 2],
],
[
[13, 9, 7, 5],
[8, 7, 4, 6],
[6, 4, 0, 3],
],
);
expect(mtrx.shape(c)).toEqual([1, 4]);
expect(c).toEqual([
[83, 63, 37, 45],
]);
});
it('should transpose matrices', () => {
expect(mtrx.t([[1, 2, 3]])).toEqual([
[1],
[2],
[3],
]);
expect(mtrx.t([
[1],
[2],
[3],
])).toEqual([
[1, 2, 3],
]);
expect(mtrx.t([
[1, 2, 3],
[4, 5, 6],
])).toEqual([
[1, 4],
[2, 5],
[3, 6],
]);
expect(mtrx.t([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
])).toEqual([
[1, 4, 7],
[2, 5, 8],
[3, 6, 9],
]);
});
it('should throw when trying to transpose non 2D matrix', () => {
expect(() => {
mtrx.t([[[1]]]);
}).toThrowError('Matrix is not of 2D shape');
});
it('should add two matrices', () => {
expect(mtrx.add([[1]], [[2]])).toEqual([[3]]);
expect(mtrx.add(
[[1, 2, 3]],
[[4, 5, 6]],
))
.toEqual(
[[5, 7, 9]],
);
expect(mtrx.add(
[[1], [2], [3]],
[[4], [5], [6]],
))
.toEqual(
[[5], [7], [9]],
);
expect(mtrx.add(
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
],
[
[10, 11, 12],
[13, 14, 15],
[16, 17, 18],
],
))
.toEqual(
[
[11, 13, 15],
[17, 19, 21],
[23, 25, 27],
],
);
expect(mtrx.add(
[
[[1], [2], [3]],
[[4], [5], [6]],
[[7], [8], [9]],
],
[
[[10], [11], [12]],
[[13], [14], [15]],
[[16], [17], [18]],
],
))
.toEqual(
[
[[11], [13], [15]],
[[17], [19], [21]],
[[23], [25], [27]],
],
);
});
it('should throw when trying to add matrices of different shape', () => {
expect(() => mtrx.add([[0]], [[[0]]])).toThrowError(
'Matrices have different dimensions',
);
expect(() => mtrx.add([[0]], [[0, 0]])).toThrowError(
'Matrices have different shapes',
);
});
it('should do element wise multiplication two matrices', () => {
expect(mtrx.mul([[2]], [[3]])).toEqual([[6]]);
expect(mtrx.mul(
[[1, 2, 3]],
[[4, 5, 6]],
))
.toEqual(
[[4, 10, 18]],
);
expect(mtrx.mul(
[[1], [2], [3]],
[[4], [5], [6]],
))
.toEqual(
[[4], [10], [18]],
);
expect(mtrx.mul(
[
[1, 2],
[3, 4],
],
[
[5, 6],
[7, 8],
],
))
.toEqual(
[
[5, 12],
[21, 32],
],
);
expect(mtrx.mul(
[
[[1], [2]],
[[3], [4]],
],
[
[[5], [6]],
[[7], [8]],
],
))
.toEqual(
[
[[5], [12]],
[[21], [32]],
],
);
});
it('should throw when trying to multiply matrices element-wise of different shape', () => {
expect(() => mtrx.mul([[0]], [[[0]]])).toThrowError(
'Matrices have different dimensions',
);
expect(() => mtrx.mul([[0]], [[0, 0]])).toThrowError(
'Matrices have different shapes',
);
});
it('should do element wise subtraction two matrices', () => {
expect(mtrx.sub([[3]], [[2]])).toEqual([[1]]);
expect(mtrx.sub(
[[10, 12, 14]],
[[4, 5, 6]],
))
.toEqual(
[[6, 7, 8]],
);
expect(mtrx.sub(
[[[10], [12], [14]]],
[[[4], [5], [6]]],
))
.toEqual(
[[[6], [7], [8]]],
);
expect(mtrx.sub(
[
[10, 20],
[30, 40],
],
[
[5, 6],
[7, 8],
],
))
.toEqual(
[
[5, 14],
[23, 32],
],
);
expect(mtrx.sub(
[
[[10], [20]],
[[30], [40]],
],
[
[[5], [6]],
[[7], [8]],
],
))
.toEqual(
[
[[5], [14]],
[[23], [32]],
],
);
});
it('should throw when trying to subtract matrices element-wise of different shape', () => {
expect(() => mtrx.sub([[0]], [[[0]]])).toThrowError(
'Matrices have different dimensions',
);
expect(() => mtrx.sub([[0]], [[0, 0]])).toThrowError(
'Matrices have different shapes',
);
});
});