Skip to content

Commit

Permalink
made dense and sparse matrices iterable, fixed josdejong#1184
Browse files Browse the repository at this point in the history
  • Loading branch information
cshaa committed Apr 1, 2021
1 parent 1df5b44 commit fd0e02f
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/type/matrix/DenseMatrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const createDenseMatrixClass = /* #__PURE__ */ factory(name, dependencies
/**
* Dense Matrix implementation. A regular, dense matrix, supporting multi-dimensional matrices. This is the default matrix type.
* @class DenseMatrix
* @enum {{ value, index: number[] }}
*/
function DenseMatrix (data, datatype) {
if (!(this instanceof DenseMatrix)) { throw new SyntaxError('Constructor must be called with the new operator') }
Expand Down Expand Up @@ -575,6 +576,23 @@ export const createDenseMatrixClass = /* #__PURE__ */ factory(name, dependencies
recurse(this._data, [])
}

/**
* Iterate over the matrix elements
* @return {Iterable<{ value, index: number[] }>}
*/
DenseMatrix.prototype[Symbol.iterator] = function * () {
const recurse = function * (value, index) {
if (isArray(value)) {
for (let i = 0; i < value.length; i++) {
yield * recurse(value[i], index.concat(i))
}
} else {
yield ({ value, index })
}
}
yield * recurse(this._data, [])
}

/**
* Create an Array with a copy of the data of the DenseMatrix
* @memberof DenseMatrix
Expand Down
9 changes: 9 additions & 0 deletions src/type/matrix/Matrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,15 @@ export const createMatrixClass = /* #__PURE__ */ factory(name, dependencies, ()
throw new Error('Cannot invoke forEach on a Matrix interface')
}

/**
* Iterate over the matrix elements
* @return {Iterable<{ value, index: number[] }>}
*/
Matrix.prototype[Symbol.iterator] = function () {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot iterate a Matrix interface')
}

/**
* Create an Array with a copy of the data of the Matrix
* @returns {Array} array
Expand Down
24 changes: 24 additions & 0 deletions src/type/matrix/SparseMatrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,8 @@ export const createSparseMatrixClass = /* #__PURE__ */ factory(name, dependencie
* parameters: the value of the element, the index
* of the element, and the Matrix being traversed.
* @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
* If false, the indices are guaranteed to be in order,
* if true, the indices can be unordered.
*/
SparseMatrix.prototype.forEach = function (callback, skipZeros) {
// check it is a pattern matrix
Expand Down Expand Up @@ -980,6 +982,28 @@ export const createSparseMatrixClass = /* #__PURE__ */ factory(name, dependencie
}
}

/**
* Iterate over the matrix elements, skipping zeros
* @return {Iterable<{ value, index: number[] }>}
*/
SparseMatrix.prototype[Symbol.iterator] = function * () {
if (!this._values) { throw new Error('Cannot iterate a Pattern only matrix') }

const columns = this._size[1]

for (let j = 0; j < columns; j++) {
const k0 = this._ptr[j]
const k1 = this._ptr[j + 1]

for (let k = k0; k < k1; k++) {
// row index
const i = this._index[k]

yield ({ value: this._values[k], index: [i, j] })
}
}
}

/**
* Create an Array with a copy of the data of the SparseMatrix
* @memberof SparseMatrix
Expand Down
31 changes: 31 additions & 0 deletions test/unit-tests/type/matrix/DenseMatrix.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,37 @@ describe('DenseMatrix', function () {
})
})

describe('iterable', function () {
it('should iterate in the same order as forEach', function () {
let m, expected

m = new DenseMatrix([
[[1, 2], [3, 4]],
[[5, 6], [7, 8]],
[[9, 10], [11, 12]],
[[13, 14], [15, 16]]
])
expected = []
m.forEach((value, index) => { expected.push({ value, index }) })
assert.deepStrictEqual(expected, [...m])

m = new DenseMatrix([1])
expected = []
m.forEach((value, index) => { expected.push({ value, index }) })
assert.deepStrictEqual(expected, [...m])

m = new DenseMatrix([1, 2, 3])
expected = []
m.forEach((value, index) => { expected.push({ value, index }) })
assert.deepStrictEqual(expected, [...m])

m = new DenseMatrix([])
expected = []
m.forEach((value, index) => { expected.push({ value, index }) })
assert.deepStrictEqual(expected, [...m])
})
})

describe('clone', function () {
it('should clone the matrix properly', function () {
const m1 = new DenseMatrix(
Expand Down
36 changes: 36 additions & 0 deletions test/unit-tests/type/matrix/SparseMatrix.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1512,6 +1512,42 @@ describe('SparseMatrix', function () {
})
})

describe('iterable', function () {
it('should iterate in the same order as forEach', function () {
let m, expected

expected = []
m = new SparseMatrix({
values: [1, 3, 2, 4],
index: [0, 1, 0, 1],
ptr: [0, 2, 4],
size: [2, 2]
})
m.forEach((value, index) => expected.push({ value, index }), true)
assert.deepStrictEqual(expected, [...m])

expected = []
m = new SparseMatrix({
values: [3, 1, 4, 2],
index: [1, 0, 1, 0],
ptr: [0, 2, 4],
size: [2, 2]
})
m.forEach((value, index) => expected.push({ value, index }), true)
assert.deepStrictEqual(expected, [...m])

expected = []
m = math.matrix([
[0, 0, 1, 0, 0, 1, 1, 0, 0],
[0, 1, 0, 0, 1, 0, 0, 0, 1],
[1, 0, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 1, 0, 0, 0, 1, 0]
], 'sparse')
m.forEach((value, index) => expected.push({ value, index }), true)
assert.deepStrictEqual(expected, [...m])
})
})

describe('clone', function () {
it('should clone the matrix properly', function () {
const m1 = new SparseMatrix(
Expand Down

0 comments on commit fd0e02f

Please sign in to comment.