Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
48 changes: 34 additions & 14 deletions src/type/matrix/SparseMatrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,24 @@ export const createSparseMatrixClass = /* #__PURE__ */ factory(name, dependencie
}
}

/**
* Return the zero value for the given datatype.
* Uses typed.convert(0, datatype) where possible, but falls back for types
* such as 'boolean' (zero = false) and 'bigint' (zero = 0n) that have no
* registered conversion from the number 0.
* @param {string} datatype
* @returns {*} zero value
*/
function _zeroValue (datatype) {
try {
return typed.convert(0, datatype)
} catch (e) {
if (datatype === 'boolean') return false
if (datatype === 'bigint') return 0n
return 0
}
}

function _createFromArray (matrix, data, datatype) {
// initialize fields
matrix._values = []
Expand All @@ -102,8 +120,8 @@ export const createSparseMatrixClass = /* #__PURE__ */ factory(name, dependencie
if (isString(datatype)) {
// find signature that matches (datatype, datatype)
eq = typed.find(equalScalar, [datatype, datatype]) || equalScalar
// convert 0 to the same datatype
zero = typed.convert(0, datatype)
// get the zero value for this datatype
zero = _zeroValue(datatype)
}

// check we have rows (empty array)
Expand Down Expand Up @@ -510,8 +528,8 @@ export const createSparseMatrixClass = /* #__PURE__ */ factory(name, dependencie
if (isString(this._datatype)) {
// find signature that matches (datatype, datatype)
eq = typed.find(equalScalar, [this._datatype, this._datatype]) || equalScalar
// convert 0 to the same datatype
zero = typed.convert(0, this._datatype)
// get the zero value for this datatype
zero = _zeroValue(this._datatype)
}

// check we need to resize matrix
Expand Down Expand Up @@ -634,8 +652,8 @@ export const createSparseMatrixClass = /* #__PURE__ */ factory(name, dependencie
if (isString(matrix._datatype)) {
// find signature that matches (datatype, datatype)
eq = typed.find(equalScalar, [matrix._datatype, matrix._datatype]) || equalScalar
// convert 0 to the same datatype
zero = typed.convert(0, matrix._datatype)
// get the zero value for this datatype
zero = _zeroValue(matrix._datatype)
// convert value to the same datatype
value = typed.convert(value, matrix._datatype)
}
Expand Down Expand Up @@ -911,8 +929,8 @@ export const createSparseMatrixClass = /* #__PURE__ */ factory(name, dependencie
if (isString(matrix._datatype)) {
// find signature that matches (datatype, datatype)
eq = typed.find(equalScalar, [matrix._datatype, matrix._datatype]) || equalScalar
// convert 0 to the same datatype
zero = typed.convert(0, matrix._datatype)
// get the zero value for this datatype
zero = _zeroValue(matrix._datatype)
}

// invoke callback
Expand Down Expand Up @@ -1055,7 +1073,8 @@ export const createSparseMatrixClass = /* #__PURE__ */ factory(name, dependencie
* @returns {Array} array
*/
SparseMatrix.prototype.toArray = function () {
return _toArray(this._values, this._index, this._ptr, this._size, true)
const zero = isString(this._datatype) ? _zeroValue(this._datatype) : 0
return _toArray(this._values, this._index, this._ptr, this._size, true, zero)
}

/**
Expand All @@ -1064,10 +1083,11 @@ export const createSparseMatrixClass = /* #__PURE__ */ factory(name, dependencie
* @returns {Array} array
*/
SparseMatrix.prototype.valueOf = function () {
return _toArray(this._values, this._index, this._ptr, this._size, false)
const zero = isString(this._datatype) ? _zeroValue(this._datatype) : 0
return _toArray(this._values, this._index, this._ptr, this._size, false, zero)
}

function _toArray (values, index, ptr, size, copy) {
function _toArray (values, index, ptr, size, copy, zero = 0) {
// rows and columns
const rows = size[0]
const columns = size[1]
Expand All @@ -1078,7 +1098,7 @@ export const createSparseMatrixClass = /* #__PURE__ */ factory(name, dependencie
// initialize array
for (i = 0; i < rows; i++) {
a[i] = []
for (j = 0; j < columns; j++) { a[i][j] = 0 }
for (j = 0; j < columns; j++) { a[i][j] = zero }
}

// loop columns
Expand Down Expand Up @@ -1287,8 +1307,8 @@ export const createSparseMatrixClass = /* #__PURE__ */ factory(name, dependencie
if (isString(datatype)) {
// find signature that matches (datatype, datatype)
eq = typed.find(equalScalar, [datatype, datatype]) || equalScalar
// convert 0 to the same datatype
zero = typed.convert(0, datatype)
// get the zero value for this datatype
zero = _zeroValue(datatype)
}

const kSuper = k > 0 ? k : 0
Expand Down
20 changes: 20 additions & 0 deletions test/unit-tests/type/matrix/SparseMatrix.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,26 @@ describe('SparseMatrix', function () {
it('should throw an error when called with invalid datatype', function () {
assert.throws(function () { console.log(new SparseMatrix([], 1)) })
})

it('should create a Sparse Matrix from an array, boolean datatype', function () {
const m = new SparseMatrix([[true, false], [false, true]], 'boolean')
assert.deepStrictEqual(m._size, [2, 2])
// true entries are stored; false is the zero element and should NOT be stored
assert.deepStrictEqual(m._values, [true, true])
assert.deepStrictEqual(m._index, [0, 1])
assert.deepStrictEqual(m._ptr, [0, 1, 2])
assert.strictEqual(m._datatype, 'boolean')
})

it('should round-trip boolean false through valueOf() with boolean datatype', function () {
const m = new SparseMatrix([[true, false]], 'boolean')
assert.deepStrictEqual(m.valueOf(), [[true, false]])
})

it('should round-trip boolean false through valueOf() with bigint datatype', function () {
const m = new SparseMatrix([[1n, 0n, 2n]], 'bigint')
assert.deepStrictEqual(m.valueOf(), [[1n, 0n, 2n]])
})
})

describe('size', function () {
Expand Down