Skip to content

Matrix subset according to type of input #3485

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: v15
Choose a base branch
from
8 changes: 4 additions & 4 deletions src/function/algebra/sylvester.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export const createSylvester = /* #__PURE__ */ factory(name, dependencies, (

for (let k = 0; k < n; k++) {
if (k < (n - 1) && abs(subset(G, index(k + 1, k))) > 1e-5) {
let RHS = vc(subset(D, index(all, k)), subset(D, index(all, k + 1)))
let RHS = vc(subset(D, index(all, [k])), subset(D, index(all, [k + 1])))
for (let j = 0; j < k; j++) {
RHS = add(RHS,
vc(multiply(y[j], subset(G, index(j, k))), multiply(y[j], subset(G, index(j, k + 1))))
Expand All @@ -125,11 +125,11 @@ export const createSylvester = /* #__PURE__ */ factory(name, dependencies, (
hc(gkm, add(F, gmm))
)
const yAux = lusolve(LHS, RHS)
y[k] = yAux.subset(index(range(0, m), 0))
y[k + 1] = yAux.subset(index(range(m, 2 * m), 0))
y[k] = yAux.subset(index(range(0, m), [0]))
y[k + 1] = yAux.subset(index(range(m, 2 * m), [0]))
k++
} else {
let RHS = subset(D, index(all, k))
let RHS = subset(D, index(all, [k]))
for (let j = 0; j < k; j++) { RHS = add(RHS, multiply(y[j], subset(G, index(j, k)))) }
const gkk = subset(G, index(k, k))
const LHS = subtract(F, multiply(gkk, identity(m)))
Expand Down
2 changes: 1 addition & 1 deletion src/function/matrix/column.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const createColumn = /* #__PURE__ */ factory(name, dependencies, ({ typed
validateIndex(column, value.size()[1])

const rowRange = range(0, value.size()[0])
const index = new Index(rowRange, column)
const index = new Index(rowRange, [column])
const result = value.subset(index)
return isMatrix(result)
? result
Expand Down
2 changes: 1 addition & 1 deletion src/function/matrix/row.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const createRow = /* #__PURE__ */ factory(name, dependencies, ({ typed, I
validateIndex(row, value.size()[0])

const columnRange = range(0, value.size()[1])
const index = new Index(row, columnRange)
const index = new Index([row], columnRange)
const result = value.subset(index)
return isMatrix(result)
? result
Expand Down
23 changes: 17 additions & 6 deletions src/function/matrix/subset.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export const createSubset = /* #__PURE__ */ factory(name, dependencies, ({ typed
if (typeof replacement === 'string') {
throw new Error('can\'t boradcast a string')
}
if (index._isScalar) {
if (index.isScalar()) {
return replacement
}

Expand Down Expand Up @@ -160,9 +160,14 @@ function _getSubstring (str, index) {
const range = index.dimension(0)

let substr = ''
range.forEach(function (v) {
function callback (v) {
substr += str.charAt(v)
})
}
if (Number.isInteger(range)) {
callback(range)
} else {
range.forEach(callback)
}

return substr
}
Expand Down Expand Up @@ -196,7 +201,7 @@ function _setSubstring (str, index, replacement, defaultValue) {
}

const range = index.dimension(0)
const len = range.size()[0]
const len = Number.isInteger(range) ? 1 : range.size()[0]

if (len !== replacement.length) {
throw new DimensionError(range.size()[0], replacement.length)
Expand All @@ -213,9 +218,15 @@ function _setSubstring (str, index, replacement, defaultValue) {
chars[i] = str.charAt(i)
}

range.forEach(function (v, i) {
function callback (v, i) {
chars[v] = replacement.charAt(i[0])
})
}

if (Number.isInteger(range)) {
callback(range, [0])
} else {
range.forEach(callback)
}

// initialize undefined characters with a space
if (chars.length > strLen) {
Expand Down
77 changes: 46 additions & 31 deletions src/type/matrix/DenseMatrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ export const createDenseMatrixClass = /* #__PURE__ */ factory(name, dependencies
}

// retrieve submatrix
const returnMatrix = new DenseMatrix([])
const returnMatrix = new DenseMatrix()
const submatrix = _getSubmatrix(matrix._data, index)
returnMatrix._size = submatrix.size
returnMatrix._datatype = matrix._datatype
Expand All @@ -259,21 +259,31 @@ export const createDenseMatrixClass = /* #__PURE__ */ factory(name, dependencies
function _getSubmatrix (data, index) {
const maxDepth = index.size().length - 1
const size = Array(maxDepth)
return { data: getSubmatrixRecursive(data), size }
return { data: getSubmatrixRecursive(data), size: size.filter(x => x !== null) }

function getSubmatrixRecursive (data, depth = 0) {
const ranges = index.dimension(depth)
size[depth] = ranges.size()[0]
function _mapIndex (range, callback) {
// applies a callback for when the index is a Number or a Matrix
if (isNumber(range)) return callback(range)
else return range.map(callback).valueOf()
}

if (isNumber(ranges)) {
size[depth] = null
} else {
size[depth] = ranges.size()[0]
}
if (depth < maxDepth) {
return ranges.map(rangeIndex => {
return _mapIndex(ranges, rangeIndex => {
validateIndex(rangeIndex, data.length)
return getSubmatrixRecursive(data[rangeIndex], depth + 1)
}).valueOf()
})
} else {
return ranges.map(rangeIndex => {
return _mapIndex(ranges, rangeIndex => {
validateIndex(rangeIndex, data.length)
return data[rangeIndex]
}).valueOf()
})
}
}
}
Expand All @@ -300,48 +310,48 @@ export const createDenseMatrixClass = /* #__PURE__ */ factory(name, dependencies
const isScalar = index.isScalar()

// calculate the size of the submatrix, and convert it into an Array if needed
let sSize
let submatrixSize
if (isMatrix(submatrix)) {
sSize = submatrix.size()
submatrixSize = submatrix.size()
submatrix = submatrix.valueOf()
} else {
sSize = arraySize(submatrix)
submatrixSize = arraySize(submatrix)
}

if (isScalar) {
// set a scalar

// check whether submatrix is a scalar
if (sSize.length !== 0) {
if (submatrixSize.length !== 0) {
throw new TypeError('Scalar expected')
}
matrix.set(index.min(), submatrix, defaultValue)
} else {
// set a submatrix

// broadcast submatrix
if (!deepStrictEqual(sSize, iSize)) {
try {
if (sSize.length === 0) {
submatrix = broadcastTo([submatrix], iSize)
} else {
if (!deepStrictEqual(submatrixSize, iSize)) {
if (submatrixSize.length === 0) {
submatrix = broadcastTo([submatrix], iSize)
} else {
try {
submatrix = broadcastTo(submatrix, iSize)
} catch (error) {
}
sSize = arraySize(submatrix)
} catch {
}
submatrixSize = arraySize(submatrix)
}

// validate dimensions
if (iSize.length < matrix._size.length) {
throw new DimensionError(iSize.length, matrix._size.length, '<')
}

if (sSize.length < iSize.length) {
if (submatrixSize.length < iSize.length) {
// calculate number of missing outer dimensions
let i = 0
let outer = 0
while (iSize[i] === 1 && sSize[i] === 1) {
while (iSize[i] === 1 && submatrixSize[i] === 1) {
i++
}
while (iSize[i] === 1) {
Expand All @@ -350,12 +360,12 @@ export const createDenseMatrixClass = /* #__PURE__ */ factory(name, dependencies
}

// unsqueeze both outer and inner dimensions
submatrix = unsqueeze(submatrix, iSize.length, outer, sSize)
submatrix = unsqueeze(submatrix, iSize.length, outer, submatrixSize)
}

// check whether the size of the submatrix matches the index size
if (!deepStrictEqual(iSize, sSize)) {
throw new DimensionError(iSize, sSize, '>')
if (!deepStrictEqual(iSize, submatrixSize)) {
throw new DimensionError(iSize, submatrixSize, '>')
}

// enlarge matrix when needed
Expand Down Expand Up @@ -386,16 +396,21 @@ export const createDenseMatrixClass = /* #__PURE__ */ factory(name, dependencies

function setSubmatrixRecursive (data, submatrix, depth = 0) {
const range = index.dimension(depth)
const recursiveCallback = (rangeIndex, i) => {
validateIndex(rangeIndex, data.length)
setSubmatrixRecursive(data[rangeIndex], submatrix[i[0]], depth + 1)
}
const finalCallback = (rangeIndex, i) => {
validateIndex(rangeIndex, data.length)
data[rangeIndex] = submatrix[i[0]]
}

if (depth < maxDepth) {
range.forEach((rangeIndex, i) => {
validateIndex(rangeIndex, data.length)
setSubmatrixRecursive(data[rangeIndex], submatrix[i[0]], depth + 1)
})
if (isNumber(range)) recursiveCallback(range, [0])
else range.forEach(recursiveCallback)
} else {
range.forEach((rangeIndex, i) => {
validateIndex(rangeIndex, data.length)
data[rangeIndex] = submatrix[i[0]]
})
if (isNumber(range)) finalCallback(range, [0])
else range.forEach(finalCallback)
}
}
}
Expand Down
42 changes: 20 additions & 22 deletions src/type/matrix/MatrixIndex.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isArray, isMatrix, isRange } from '../../utils/is.js'
import { isArray, isMatrix, isRange, isNumber, isString } from '../../utils/is.js'
import { clone } from '../../utils/object.js'
import { isInteger } from '../../utils/number.js'
import { factory } from '../../utils/factory.js'
Expand Down Expand Up @@ -29,7 +29,7 @@ export const createIndexClass = /* #__PURE__ */ factory(name, dependencies, ({ I
* @Constructor Index
* @param {...*} ranges
*/
function Index (ranges) {
function Index (...ranges) {
if (!(this instanceof Index)) {
throw new SyntaxError('Constructor must be called with the new operator')
}
Expand All @@ -38,8 +38,8 @@ export const createIndexClass = /* #__PURE__ */ factory(name, dependencies, ({ I
this._sourceSize = []
this._isScalar = true

for (let i = 0, ii = arguments.length; i < ii; i++) {
const arg = arguments[i]
for (let i = 0, ii = ranges.length; i < ii; i++) {
const arg = ranges[i]
const argIsArray = isArray(arg)
const argIsMatrix = isMatrix(arg)
const argType = typeof arg
Expand All @@ -50,6 +50,7 @@ export const createIndexClass = /* #__PURE__ */ factory(name, dependencies, ({ I
} else if (argIsArray || argIsMatrix) {
// create matrix
let m
this._isScalar = false

if (getMatrixDataType(arg) === 'boolean') {
if (argIsArray) m = _createImmutableMatrix(_booleansArrayToNumbersForIndex(arg).valueOf())
Expand All @@ -60,16 +61,10 @@ export const createIndexClass = /* #__PURE__ */ factory(name, dependencies, ({ I
}

this._dimensions.push(m)
// size
const size = m.size()
// scalar
if (size.length !== 1 || size[0] !== 1 || sourceSize !== null) {
this._isScalar = false
}
} else if (argType === 'number') {
this._dimensions.push(_createImmutableMatrix([arg]))
this._dimensions.push(arg)
} else if (argType === 'bigint') {
this._dimensions.push(_createImmutableMatrix([Number(arg)]))
this._dimensions.push(Number(arg))
} else if (argType === 'string') {
// object property (arguments.count should be 1)
this._dimensions.push(arg)
Expand All @@ -90,12 +85,15 @@ export const createIndexClass = /* #__PURE__ */ factory(name, dependencies, ({ I
function _createImmutableMatrix (arg) {
// loop array elements
for (let i = 0, l = arg.length; i < l; i++) {
if (typeof arg[i] !== 'number' || !isInteger(arg[i])) {
if (!isNumber(arg[i]) || !isInteger(arg[i])) {
throw new TypeError('Index parameters must be positive integer numbers')
}
}
// create matrix
return new ImmutableDenseMatrix(arg)
const matrix = new ImmutableDenseMatrix()
matrix._data = arg
matrix._size = [arg.length]
return matrix
}

/**
Expand Down Expand Up @@ -134,7 +132,7 @@ export const createIndexClass = /* #__PURE__ */ factory(name, dependencies, ({ I

for (let i = 0, ii = this._dimensions.length; i < ii; i++) {
const d = this._dimensions[i]
size[i] = (typeof d === 'string') ? 1 : d.size()[0]
size[i] = (isString(d) || isNumber(d)) ? 1 : d.size()[0]
}

return size
Expand All @@ -150,7 +148,7 @@ export const createIndexClass = /* #__PURE__ */ factory(name, dependencies, ({ I

for (let i = 0, ii = this._dimensions.length; i < ii; i++) {
const range = this._dimensions[i]
values[i] = (typeof range === 'string') ? range : range.max()
values[i] = (isString(range) || isNumber(range)) ? range : range.max()
}

return values
Expand All @@ -166,7 +164,7 @@ export const createIndexClass = /* #__PURE__ */ factory(name, dependencies, ({ I

for (let i = 0, ii = this._dimensions.length; i < ii; i++) {
const range = this._dimensions[i]
values[i] = (typeof range === 'string') ? range : range.min()
values[i] = (isString(range) || isNumber(range)) ? range : range.min()
}

return values
Expand All @@ -192,19 +190,19 @@ export const createIndexClass = /* #__PURE__ */ factory(name, dependencies, ({ I
* @returns {Range | null} range
*/
Index.prototype.dimension = function (dim) {
if (typeof dim !== 'number') {
if (!isNumber(dim)) {
return null
}

return this._dimensions[dim] || null
return this._dimensions[dim] ?? null
}

/**
* Test whether this index contains an object property
* @returns {boolean} Returns true if the index is an object property
*/
Index.prototype.isObjectProperty = function () {
return this._dimensions.length === 1 && typeof this._dimensions[0] === 'string'
return this._dimensions.length === 1 && isString(this._dimensions[0])
}

/**
Expand Down Expand Up @@ -238,7 +236,7 @@ export const createIndexClass = /* #__PURE__ */ factory(name, dependencies, ({ I
const array = []
for (let i = 0, ii = this._dimensions.length; i < ii; i++) {
const dimension = this._dimensions[i]
array.push((typeof dimension === 'string') ? dimension : dimension.toArray())
array.push(isString(dimension) || isNumber(dimension) ? dimension : dimension.toArray())
}
return array
}
Expand All @@ -261,7 +259,7 @@ export const createIndexClass = /* #__PURE__ */ factory(name, dependencies, ({ I

for (let i = 0, ii = this._dimensions.length; i < ii; i++) {
const dimension = this._dimensions[i]
if (typeof dimension === 'string') {
if (isString(dimension)) {
strings.push(JSON.stringify(dimension))
} else {
strings.push(dimension.toString())
Expand Down
Loading