{"version":3,"file":"ml-pls.esm.min.js","sources":["../node_modules/ml-matrix/matrix.js","../node_modules/ml-matrix/matrix.mjs","../lib/util/utils.js","../lib/PLS.js","../lib/KOPLS.js","../node_modules/is-any-array/lib/index.js","../node_modules/ml-confusion-matrix/lib-esm/index.js","../node_modules/ml-combinations/lib/index.js","../node_modules/ml-array-sum/node_modules/is-any-array/lib-esm/index.js","../node_modules/ml-array-sum/lib-es6/index.js","../node_modules/ml-roc-multiclass/lib-esm/getAuc.js","../node_modules/ml-array-mean/lib-es6/index.js","../node_modules/ml-roc-multiclass/lib-esm/getBinaryClassifiers.js","../node_modules/ml-roc-multiclass/lib-esm/utilities/getThresholds.js","../node_modules/ml-roc-multiclass/lib-esm/utilities/getClasses.js","../node_modules/ml-roc-multiclass/lib-esm/utilities/getSelectedResults.js","../node_modules/ml-roc-multiclass/lib-esm/getRocCurve.js","../node_modules/ml-roc-multiclass/lib-esm/utilities/getClassesPairs.js","../lib/oplsNipals.js","../lib/util/getSafeStandardDeviations.js","../lib/util/tss.js","../lib/OPLS.js","../node_modules/ml-cross-validation/src/getFolds.js"],"sourcesContent":["'use strict';\n\nObject.defineProperty(exports, '__esModule', { value: true });\n\n// eslint-disable-next-line @typescript-eslint/unbound-method\nconst toString = Object.prototype.toString;\n/**\n * Checks if an object is an instance of an Array (array or typed array, except those that contain bigint values).\n * @param value - Object to check.\n * @returns True if the object is an array or a typed array.\n */\nfunction isAnyArray(value) {\n    const tag = toString.call(value);\n    return tag.endsWith('Array]') && !tag.includes('Big');\n}\n\n/**\n * Computes the maximum of the given values.\n *\n * @param input\n * @param options\n */\nfunction max(input, options = {}) {\n    if (!isAnyArray(input)) {\n        throw new TypeError('input must be an array');\n    }\n    if (input.length === 0) {\n        throw new TypeError('input must not be empty');\n    }\n    const { fromIndex = 0, toIndex = input.length } = options;\n    if (fromIndex < 0 ||\n        fromIndex >= input.length ||\n        !Number.isInteger(fromIndex)) {\n        throw new Error('fromIndex must be a positive integer smaller than length');\n    }\n    if (toIndex <= fromIndex ||\n        toIndex > input.length ||\n        !Number.isInteger(toIndex)) {\n        throw new Error('toIndex must be an integer greater than fromIndex and at most equal to length');\n    }\n    let maxValue = input[fromIndex];\n    for (let i = fromIndex + 1; i < toIndex; i++) {\n        if (input[i] > maxValue)\n            maxValue = input[i];\n    }\n    return maxValue;\n}\n\n/**\n * Computes the minimum of the given values.\n */\nfunction min(input, options = {}) {\n    if (!isAnyArray(input)) {\n        throw new TypeError('input must be an array');\n    }\n    if (input.length === 0) {\n        throw new TypeError('input must not be empty');\n    }\n    const { fromIndex = 0, toIndex = input.length } = options;\n    if (fromIndex < 0 ||\n        fromIndex >= input.length ||\n        !Number.isInteger(fromIndex)) {\n        throw new Error('fromIndex must be a positive integer smaller than length');\n    }\n    if (toIndex <= fromIndex ||\n        toIndex > input.length ||\n        !Number.isInteger(toIndex)) {\n        throw new Error('toIndex must be an integer greater than fromIndex and at most equal to length');\n    }\n    let minValue = input[fromIndex];\n    for (let i = fromIndex + 1; i < toIndex; i++) {\n        if (input[i] < minValue)\n            minValue = input[i];\n    }\n    return minValue;\n}\n\n/**\n * Rescale an array into a range.\n */\nfunction rescale(input, options = {}) {\n    if (!isAnyArray(input)) {\n        throw new TypeError('input must be an array');\n    }\n    else if (input.length === 0) {\n        throw new TypeError('input must not be empty');\n    }\n    let output;\n    if (options.output !== undefined) {\n        if (!isAnyArray(options.output)) {\n            throw new TypeError('output option must be an array if specified');\n        }\n        output = options.output;\n    }\n    else {\n        output = new Array(input.length);\n    }\n    const currentMin = min(input);\n    const currentMax = max(input);\n    if (currentMin === currentMax) {\n        throw new RangeError('minimum and maximum input values are equal. Cannot rescale a constant array');\n    }\n    const { min: minValue = options.autoMinMax ? currentMin : 0, max: maxValue = options.autoMinMax ? currentMax : 1, } = options;\n    if (minValue >= maxValue) {\n        throw new RangeError('min option must be smaller than max option');\n    }\n    const factor = (maxValue - minValue) / (currentMax - currentMin);\n    for (let i = 0; i < input.length; i++) {\n        output[i] = (input[i] - currentMin) * factor + minValue;\n    }\n    return output;\n}\n\nconst indent = ' '.repeat(2);\nconst indentData = ' '.repeat(4);\n\n/**\n * @this {Matrix}\n * @returns {string}\n */\nfunction inspectMatrix() {\n  return inspectMatrixWithOptions(this);\n}\n\nfunction inspectMatrixWithOptions(matrix, options = {}) {\n  const {\n    maxRows = 15,\n    maxColumns = 10,\n    maxNumSize = 8,\n    padMinus = 'auto',\n  } = options;\n  return `${matrix.constructor.name} {\n${indent}[\n${indentData}${inspectData(matrix, maxRows, maxColumns, maxNumSize, padMinus)}\n${indent}]\n${indent}rows: ${matrix.rows}\n${indent}columns: ${matrix.columns}\n}`;\n}\n\nfunction inspectData(matrix, maxRows, maxColumns, maxNumSize, padMinus) {\n  const { rows, columns } = matrix;\n  const maxI = Math.min(rows, maxRows);\n  const maxJ = Math.min(columns, maxColumns);\n  const result = [];\n\n  if (padMinus === 'auto') {\n    padMinus = false;\n    loop: for (let i = 0; i < maxI; i++) {\n      for (let j = 0; j < maxJ; j++) {\n        if (matrix.get(i, j) < 0) {\n          padMinus = true;\n          break loop;\n        }\n      }\n    }\n  }\n\n  for (let i = 0; i < maxI; i++) {\n    let line = [];\n    for (let j = 0; j < maxJ; j++) {\n      line.push(formatNumber(matrix.get(i, j), maxNumSize, padMinus));\n    }\n    result.push(`${line.join(' ')}`);\n  }\n  if (maxJ !== columns) {\n    result[result.length - 1] += ` ... ${columns - maxColumns} more columns`;\n  }\n  if (maxI !== rows) {\n    result.push(`... ${rows - maxRows} more rows`);\n  }\n  return result.join(`\\n${indentData}`);\n}\n\nfunction formatNumber(num, maxNumSize, padMinus) {\n  return (\n    num >= 0 && padMinus\n      ? ` ${formatNumber2(num, maxNumSize - 1)}`\n      : formatNumber2(num, maxNumSize)\n  ).padEnd(maxNumSize);\n}\n\nfunction formatNumber2(num, len) {\n  // small.length numbers should be as is\n  let str = num.toString();\n  if (str.length <= len) return str;\n\n  // (7)'0.00123' is better then (7)'1.23e-2'\n  // (8)'0.000123' is worse then (7)'1.23e-3',\n  let fix = num.toFixed(len);\n  if (fix.length > len) {\n    fix = num.toFixed(Math.max(0, len - (fix.length - len)));\n  }\n  if (\n    fix.length <= len &&\n    !fix.startsWith('0.000') &&\n    !fix.startsWith('-0.000')\n  ) {\n    return fix;\n  }\n\n  // well, if it's still too long the user should've used longer numbers\n  let exp = num.toExponential(len);\n  if (exp.length > len) {\n    exp = num.toExponential(Math.max(0, len - (exp.length - len)));\n  }\n  return exp.slice(0);\n}\n\nfunction installMathOperations(AbstractMatrix, Matrix) {\n  AbstractMatrix.prototype.add = function add(value) {\n    if (typeof value === 'number') return this.addS(value);\n    return this.addM(value);\n  };\n\n  AbstractMatrix.prototype.addS = function addS(value) {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) + value);\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.prototype.addM = function addM(matrix) {\n    matrix = Matrix.checkMatrix(matrix);\n    if (this.rows !== matrix.rows ||\n      this.columns !== matrix.columns) {\n      throw new RangeError('Matrices dimensions must be equal');\n    }\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) + matrix.get(i, j));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.add = function add(matrix, value) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.add(value);\n  };\n\n  AbstractMatrix.prototype.sub = function sub(value) {\n    if (typeof value === 'number') return this.subS(value);\n    return this.subM(value);\n  };\n\n  AbstractMatrix.prototype.subS = function subS(value) {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) - value);\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.prototype.subM = function subM(matrix) {\n    matrix = Matrix.checkMatrix(matrix);\n    if (this.rows !== matrix.rows ||\n      this.columns !== matrix.columns) {\n      throw new RangeError('Matrices dimensions must be equal');\n    }\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) - matrix.get(i, j));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.sub = function sub(matrix, value) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.sub(value);\n  };\n  AbstractMatrix.prototype.subtract = AbstractMatrix.prototype.sub;\n  AbstractMatrix.prototype.subtractS = AbstractMatrix.prototype.subS;\n  AbstractMatrix.prototype.subtractM = AbstractMatrix.prototype.subM;\n  AbstractMatrix.subtract = AbstractMatrix.sub;\n\n  AbstractMatrix.prototype.mul = function mul(value) {\n    if (typeof value === 'number') return this.mulS(value);\n    return this.mulM(value);\n  };\n\n  AbstractMatrix.prototype.mulS = function mulS(value) {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) * value);\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.prototype.mulM = function mulM(matrix) {\n    matrix = Matrix.checkMatrix(matrix);\n    if (this.rows !== matrix.rows ||\n      this.columns !== matrix.columns) {\n      throw new RangeError('Matrices dimensions must be equal');\n    }\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) * matrix.get(i, j));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.mul = function mul(matrix, value) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.mul(value);\n  };\n  AbstractMatrix.prototype.multiply = AbstractMatrix.prototype.mul;\n  AbstractMatrix.prototype.multiplyS = AbstractMatrix.prototype.mulS;\n  AbstractMatrix.prototype.multiplyM = AbstractMatrix.prototype.mulM;\n  AbstractMatrix.multiply = AbstractMatrix.mul;\n\n  AbstractMatrix.prototype.div = function div(value) {\n    if (typeof value === 'number') return this.divS(value);\n    return this.divM(value);\n  };\n\n  AbstractMatrix.prototype.divS = function divS(value) {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) / value);\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.prototype.divM = function divM(matrix) {\n    matrix = Matrix.checkMatrix(matrix);\n    if (this.rows !== matrix.rows ||\n      this.columns !== matrix.columns) {\n      throw new RangeError('Matrices dimensions must be equal');\n    }\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) / matrix.get(i, j));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.div = function div(matrix, value) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.div(value);\n  };\n  AbstractMatrix.prototype.divide = AbstractMatrix.prototype.div;\n  AbstractMatrix.prototype.divideS = AbstractMatrix.prototype.divS;\n  AbstractMatrix.prototype.divideM = AbstractMatrix.prototype.divM;\n  AbstractMatrix.divide = AbstractMatrix.div;\n\n  AbstractMatrix.prototype.mod = function mod(value) {\n    if (typeof value === 'number') return this.modS(value);\n    return this.modM(value);\n  };\n\n  AbstractMatrix.prototype.modS = function modS(value) {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) % value);\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.prototype.modM = function modM(matrix) {\n    matrix = Matrix.checkMatrix(matrix);\n    if (this.rows !== matrix.rows ||\n      this.columns !== matrix.columns) {\n      throw new RangeError('Matrices dimensions must be equal');\n    }\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) % matrix.get(i, j));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.mod = function mod(matrix, value) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.mod(value);\n  };\n  AbstractMatrix.prototype.modulus = AbstractMatrix.prototype.mod;\n  AbstractMatrix.prototype.modulusS = AbstractMatrix.prototype.modS;\n  AbstractMatrix.prototype.modulusM = AbstractMatrix.prototype.modM;\n  AbstractMatrix.modulus = AbstractMatrix.mod;\n\n  AbstractMatrix.prototype.and = function and(value) {\n    if (typeof value === 'number') return this.andS(value);\n    return this.andM(value);\n  };\n\n  AbstractMatrix.prototype.andS = function andS(value) {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) & value);\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.prototype.andM = function andM(matrix) {\n    matrix = Matrix.checkMatrix(matrix);\n    if (this.rows !== matrix.rows ||\n      this.columns !== matrix.columns) {\n      throw new RangeError('Matrices dimensions must be equal');\n    }\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) & matrix.get(i, j));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.and = function and(matrix, value) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.and(value);\n  };\n\n  AbstractMatrix.prototype.or = function or(value) {\n    if (typeof value === 'number') return this.orS(value);\n    return this.orM(value);\n  };\n\n  AbstractMatrix.prototype.orS = function orS(value) {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) | value);\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.prototype.orM = function orM(matrix) {\n    matrix = Matrix.checkMatrix(matrix);\n    if (this.rows !== matrix.rows ||\n      this.columns !== matrix.columns) {\n      throw new RangeError('Matrices dimensions must be equal');\n    }\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) | matrix.get(i, j));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.or = function or(matrix, value) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.or(value);\n  };\n\n  AbstractMatrix.prototype.xor = function xor(value) {\n    if (typeof value === 'number') return this.xorS(value);\n    return this.xorM(value);\n  };\n\n  AbstractMatrix.prototype.xorS = function xorS(value) {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) ^ value);\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.prototype.xorM = function xorM(matrix) {\n    matrix = Matrix.checkMatrix(matrix);\n    if (this.rows !== matrix.rows ||\n      this.columns !== matrix.columns) {\n      throw new RangeError('Matrices dimensions must be equal');\n    }\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) ^ matrix.get(i, j));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.xor = function xor(matrix, value) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.xor(value);\n  };\n\n  AbstractMatrix.prototype.leftShift = function leftShift(value) {\n    if (typeof value === 'number') return this.leftShiftS(value);\n    return this.leftShiftM(value);\n  };\n\n  AbstractMatrix.prototype.leftShiftS = function leftShiftS(value) {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) << value);\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.prototype.leftShiftM = function leftShiftM(matrix) {\n    matrix = Matrix.checkMatrix(matrix);\n    if (this.rows !== matrix.rows ||\n      this.columns !== matrix.columns) {\n      throw new RangeError('Matrices dimensions must be equal');\n    }\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) << matrix.get(i, j));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.leftShift = function leftShift(matrix, value) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.leftShift(value);\n  };\n\n  AbstractMatrix.prototype.signPropagatingRightShift = function signPropagatingRightShift(value) {\n    if (typeof value === 'number') return this.signPropagatingRightShiftS(value);\n    return this.signPropagatingRightShiftM(value);\n  };\n\n  AbstractMatrix.prototype.signPropagatingRightShiftS = function signPropagatingRightShiftS(value) {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) >> value);\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.prototype.signPropagatingRightShiftM = function signPropagatingRightShiftM(matrix) {\n    matrix = Matrix.checkMatrix(matrix);\n    if (this.rows !== matrix.rows ||\n      this.columns !== matrix.columns) {\n      throw new RangeError('Matrices dimensions must be equal');\n    }\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) >> matrix.get(i, j));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.signPropagatingRightShift = function signPropagatingRightShift(matrix, value) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.signPropagatingRightShift(value);\n  };\n\n  AbstractMatrix.prototype.rightShift = function rightShift(value) {\n    if (typeof value === 'number') return this.rightShiftS(value);\n    return this.rightShiftM(value);\n  };\n\n  AbstractMatrix.prototype.rightShiftS = function rightShiftS(value) {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) >>> value);\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.prototype.rightShiftM = function rightShiftM(matrix) {\n    matrix = Matrix.checkMatrix(matrix);\n    if (this.rows !== matrix.rows ||\n      this.columns !== matrix.columns) {\n      throw new RangeError('Matrices dimensions must be equal');\n    }\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) >>> matrix.get(i, j));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.rightShift = function rightShift(matrix, value) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.rightShift(value);\n  };\n  AbstractMatrix.prototype.zeroFillRightShift = AbstractMatrix.prototype.rightShift;\n  AbstractMatrix.prototype.zeroFillRightShiftS = AbstractMatrix.prototype.rightShiftS;\n  AbstractMatrix.prototype.zeroFillRightShiftM = AbstractMatrix.prototype.rightShiftM;\n  AbstractMatrix.zeroFillRightShift = AbstractMatrix.rightShift;\n\n  AbstractMatrix.prototype.not = function not() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, ~(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.not = function not(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.not();\n  };\n\n  AbstractMatrix.prototype.abs = function abs() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.abs(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.abs = function abs(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.abs();\n  };\n\n  AbstractMatrix.prototype.acos = function acos() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.acos(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.acos = function acos(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.acos();\n  };\n\n  AbstractMatrix.prototype.acosh = function acosh() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.acosh(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.acosh = function acosh(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.acosh();\n  };\n\n  AbstractMatrix.prototype.asin = function asin() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.asin(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.asin = function asin(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.asin();\n  };\n\n  AbstractMatrix.prototype.asinh = function asinh() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.asinh(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.asinh = function asinh(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.asinh();\n  };\n\n  AbstractMatrix.prototype.atan = function atan() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.atan(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.atan = function atan(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.atan();\n  };\n\n  AbstractMatrix.prototype.atanh = function atanh() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.atanh(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.atanh = function atanh(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.atanh();\n  };\n\n  AbstractMatrix.prototype.cbrt = function cbrt() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.cbrt(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.cbrt = function cbrt(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.cbrt();\n  };\n\n  AbstractMatrix.prototype.ceil = function ceil() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.ceil(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.ceil = function ceil(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.ceil();\n  };\n\n  AbstractMatrix.prototype.clz32 = function clz32() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.clz32(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.clz32 = function clz32(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.clz32();\n  };\n\n  AbstractMatrix.prototype.cos = function cos() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.cos(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.cos = function cos(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.cos();\n  };\n\n  AbstractMatrix.prototype.cosh = function cosh() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.cosh(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.cosh = function cosh(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.cosh();\n  };\n\n  AbstractMatrix.prototype.exp = function exp() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.exp(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.exp = function exp(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.exp();\n  };\n\n  AbstractMatrix.prototype.expm1 = function expm1() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.expm1(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.expm1 = function expm1(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.expm1();\n  };\n\n  AbstractMatrix.prototype.floor = function floor() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.floor(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.floor = function floor(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.floor();\n  };\n\n  AbstractMatrix.prototype.fround = function fround() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.fround(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.fround = function fround(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.fround();\n  };\n\n  AbstractMatrix.prototype.log = function log() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.log(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.log = function log(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.log();\n  };\n\n  AbstractMatrix.prototype.log1p = function log1p() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.log1p(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.log1p = function log1p(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.log1p();\n  };\n\n  AbstractMatrix.prototype.log10 = function log10() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.log10(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.log10 = function log10(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.log10();\n  };\n\n  AbstractMatrix.prototype.log2 = function log2() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.log2(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.log2 = function log2(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.log2();\n  };\n\n  AbstractMatrix.prototype.round = function round() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.round(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.round = function round(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.round();\n  };\n\n  AbstractMatrix.prototype.sign = function sign() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.sign(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.sign = function sign(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.sign();\n  };\n\n  AbstractMatrix.prototype.sin = function sin() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.sin(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.sin = function sin(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.sin();\n  };\n\n  AbstractMatrix.prototype.sinh = function sinh() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.sinh(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.sinh = function sinh(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.sinh();\n  };\n\n  AbstractMatrix.prototype.sqrt = function sqrt() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.sqrt(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.sqrt = function sqrt(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.sqrt();\n  };\n\n  AbstractMatrix.prototype.tan = function tan() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.tan(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.tan = function tan(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.tan();\n  };\n\n  AbstractMatrix.prototype.tanh = function tanh() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.tanh(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.tanh = function tanh(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.tanh();\n  };\n\n  AbstractMatrix.prototype.trunc = function trunc() {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, Math.trunc(this.get(i, j)));\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.trunc = function trunc(matrix) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.trunc();\n  };\n\n  AbstractMatrix.pow = function pow(matrix, arg0) {\n    const newMatrix = new Matrix(matrix);\n    return newMatrix.pow(arg0);\n  };\n\n  AbstractMatrix.prototype.pow = function pow(value) {\n    if (typeof value === 'number') return this.powS(value);\n    return this.powM(value);\n  };\n\n  AbstractMatrix.prototype.powS = function powS(value) {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) ** value);\n      }\n    }\n    return this;\n  };\n\n  AbstractMatrix.prototype.powM = function powM(matrix) {\n    matrix = Matrix.checkMatrix(matrix);\n    if (this.rows !== matrix.rows ||\n      this.columns !== matrix.columns) {\n      throw new RangeError('Matrices dimensions must be equal');\n    }\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) ** matrix.get(i, j));\n      }\n    }\n    return this;\n  };\n}\n\n/**\n * @private\n * Check that a row index is not out of bounds\n * @param {Matrix} matrix\n * @param {number} index\n * @param {boolean} [outer]\n */\nfunction checkRowIndex(matrix, index, outer) {\n  let max = outer ? matrix.rows : matrix.rows - 1;\n  if (index < 0 || index > max) {\n    throw new RangeError('Row index out of range');\n  }\n}\n\n/**\n * @private\n * Check that a column index is not out of bounds\n * @param {Matrix} matrix\n * @param {number} index\n * @param {boolean} [outer]\n */\nfunction checkColumnIndex(matrix, index, outer) {\n  let max = outer ? matrix.columns : matrix.columns - 1;\n  if (index < 0 || index > max) {\n    throw new RangeError('Column index out of range');\n  }\n}\n\n/**\n * @private\n * Check that the provided vector is an array with the right length\n * @param {Matrix} matrix\n * @param {Array|Matrix} vector\n * @return {Array}\n * @throws {RangeError}\n */\nfunction checkRowVector(matrix, vector) {\n  if (vector.to1DArray) {\n    vector = vector.to1DArray();\n  }\n  if (vector.length !== matrix.columns) {\n    throw new RangeError(\n      'vector size must be the same as the number of columns',\n    );\n  }\n  return vector;\n}\n\n/**\n * @private\n * Check that the provided vector is an array with the right length\n * @param {Matrix} matrix\n * @param {Array|Matrix} vector\n * @return {Array}\n * @throws {RangeError}\n */\nfunction checkColumnVector(matrix, vector) {\n  if (vector.to1DArray) {\n    vector = vector.to1DArray();\n  }\n  if (vector.length !== matrix.rows) {\n    throw new RangeError('vector size must be the same as the number of rows');\n  }\n  return vector;\n}\n\nfunction checkRowIndices(matrix, rowIndices) {\n  if (!isAnyArray(rowIndices)) {\n    throw new TypeError('row indices must be an array');\n  }\n\n  for (let i = 0; i < rowIndices.length; i++) {\n    if (rowIndices[i] < 0 || rowIndices[i] >= matrix.rows) {\n      throw new RangeError('row indices are out of range');\n    }\n  }\n}\n\nfunction checkColumnIndices(matrix, columnIndices) {\n  if (!isAnyArray(columnIndices)) {\n    throw new TypeError('column indices must be an array');\n  }\n\n  for (let i = 0; i < columnIndices.length; i++) {\n    if (columnIndices[i] < 0 || columnIndices[i] >= matrix.columns) {\n      throw new RangeError('column indices are out of range');\n    }\n  }\n}\n\nfunction checkRange(matrix, startRow, endRow, startColumn, endColumn) {\n  if (arguments.length !== 5) {\n    throw new RangeError('expected 4 arguments');\n  }\n  checkNumber('startRow', startRow);\n  checkNumber('endRow', endRow);\n  checkNumber('startColumn', startColumn);\n  checkNumber('endColumn', endColumn);\n  if (\n    startRow > endRow ||\n    startColumn > endColumn ||\n    startRow < 0 ||\n    startRow >= matrix.rows ||\n    endRow < 0 ||\n    endRow >= matrix.rows ||\n    startColumn < 0 ||\n    startColumn >= matrix.columns ||\n    endColumn < 0 ||\n    endColumn >= matrix.columns\n  ) {\n    throw new RangeError('Submatrix indices are out of range');\n  }\n}\n\nfunction newArray(length, value = 0) {\n  let array = [];\n  for (let i = 0; i < length; i++) {\n    array.push(value);\n  }\n  return array;\n}\n\nfunction checkNumber(name, value) {\n  if (typeof value !== 'number') {\n    throw new TypeError(`${name} must be a number`);\n  }\n}\n\nfunction checkNonEmpty(matrix) {\n  if (matrix.isEmpty()) {\n    throw new Error('Empty matrix has no elements to index');\n  }\n}\n\nfunction sumByRow(matrix) {\n  let sum = newArray(matrix.rows);\n  for (let i = 0; i < matrix.rows; ++i) {\n    for (let j = 0; j < matrix.columns; ++j) {\n      sum[i] += matrix.get(i, j);\n    }\n  }\n  return sum;\n}\n\nfunction sumByColumn(matrix) {\n  let sum = newArray(matrix.columns);\n  for (let i = 0; i < matrix.rows; ++i) {\n    for (let j = 0; j < matrix.columns; ++j) {\n      sum[j] += matrix.get(i, j);\n    }\n  }\n  return sum;\n}\n\nfunction sumAll(matrix) {\n  let v = 0;\n  for (let i = 0; i < matrix.rows; i++) {\n    for (let j = 0; j < matrix.columns; j++) {\n      v += matrix.get(i, j);\n    }\n  }\n  return v;\n}\n\nfunction productByRow(matrix) {\n  let sum = newArray(matrix.rows, 1);\n  for (let i = 0; i < matrix.rows; ++i) {\n    for (let j = 0; j < matrix.columns; ++j) {\n      sum[i] *= matrix.get(i, j);\n    }\n  }\n  return sum;\n}\n\nfunction productByColumn(matrix) {\n  let sum = newArray(matrix.columns, 1);\n  for (let i = 0; i < matrix.rows; ++i) {\n    for (let j = 0; j < matrix.columns; ++j) {\n      sum[j] *= matrix.get(i, j);\n    }\n  }\n  return sum;\n}\n\nfunction productAll(matrix) {\n  let v = 1;\n  for (let i = 0; i < matrix.rows; i++) {\n    for (let j = 0; j < matrix.columns; j++) {\n      v *= matrix.get(i, j);\n    }\n  }\n  return v;\n}\n\nfunction varianceByRow(matrix, unbiased, mean) {\n  const rows = matrix.rows;\n  const cols = matrix.columns;\n  const variance = [];\n\n  for (let i = 0; i < rows; i++) {\n    let sum1 = 0;\n    let sum2 = 0;\n    let x = 0;\n    for (let j = 0; j < cols; j++) {\n      x = matrix.get(i, j) - mean[i];\n      sum1 += x;\n      sum2 += x * x;\n    }\n    if (unbiased) {\n      variance.push((sum2 - (sum1 * sum1) / cols) / (cols - 1));\n    } else {\n      variance.push((sum2 - (sum1 * sum1) / cols) / cols);\n    }\n  }\n  return variance;\n}\n\nfunction varianceByColumn(matrix, unbiased, mean) {\n  const rows = matrix.rows;\n  const cols = matrix.columns;\n  const variance = [];\n\n  for (let j = 0; j < cols; j++) {\n    let sum1 = 0;\n    let sum2 = 0;\n    let x = 0;\n    for (let i = 0; i < rows; i++) {\n      x = matrix.get(i, j) - mean[j];\n      sum1 += x;\n      sum2 += x * x;\n    }\n    if (unbiased) {\n      variance.push((sum2 - (sum1 * sum1) / rows) / (rows - 1));\n    } else {\n      variance.push((sum2 - (sum1 * sum1) / rows) / rows);\n    }\n  }\n  return variance;\n}\n\nfunction varianceAll(matrix, unbiased, mean) {\n  const rows = matrix.rows;\n  const cols = matrix.columns;\n  const size = rows * cols;\n\n  let sum1 = 0;\n  let sum2 = 0;\n  let x = 0;\n  for (let i = 0; i < rows; i++) {\n    for (let j = 0; j < cols; j++) {\n      x = matrix.get(i, j) - mean;\n      sum1 += x;\n      sum2 += x * x;\n    }\n  }\n  if (unbiased) {\n    return (sum2 - (sum1 * sum1) / size) / (size - 1);\n  } else {\n    return (sum2 - (sum1 * sum1) / size) / size;\n  }\n}\n\nfunction centerByRow(matrix, mean) {\n  for (let i = 0; i < matrix.rows; i++) {\n    for (let j = 0; j < matrix.columns; j++) {\n      matrix.set(i, j, matrix.get(i, j) - mean[i]);\n    }\n  }\n}\n\nfunction centerByColumn(matrix, mean) {\n  for (let i = 0; i < matrix.rows; i++) {\n    for (let j = 0; j < matrix.columns; j++) {\n      matrix.set(i, j, matrix.get(i, j) - mean[j]);\n    }\n  }\n}\n\nfunction centerAll(matrix, mean) {\n  for (let i = 0; i < matrix.rows; i++) {\n    for (let j = 0; j < matrix.columns; j++) {\n      matrix.set(i, j, matrix.get(i, j) - mean);\n    }\n  }\n}\n\nfunction getScaleByRow(matrix) {\n  const scale = [];\n  for (let i = 0; i < matrix.rows; i++) {\n    let sum = 0;\n    for (let j = 0; j < matrix.columns; j++) {\n      sum += matrix.get(i, j) ** 2 / (matrix.columns - 1);\n    }\n    scale.push(Math.sqrt(sum));\n  }\n  return scale;\n}\n\nfunction scaleByRow(matrix, scale) {\n  for (let i = 0; i < matrix.rows; i++) {\n    for (let j = 0; j < matrix.columns; j++) {\n      matrix.set(i, j, matrix.get(i, j) / scale[i]);\n    }\n  }\n}\n\nfunction getScaleByColumn(matrix) {\n  const scale = [];\n  for (let j = 0; j < matrix.columns; j++) {\n    let sum = 0;\n    for (let i = 0; i < matrix.rows; i++) {\n      sum += matrix.get(i, j) ** 2 / (matrix.rows - 1);\n    }\n    scale.push(Math.sqrt(sum));\n  }\n  return scale;\n}\n\nfunction scaleByColumn(matrix, scale) {\n  for (let i = 0; i < matrix.rows; i++) {\n    for (let j = 0; j < matrix.columns; j++) {\n      matrix.set(i, j, matrix.get(i, j) / scale[j]);\n    }\n  }\n}\n\nfunction getScaleAll(matrix) {\n  const divider = matrix.size - 1;\n  let sum = 0;\n  for (let j = 0; j < matrix.columns; j++) {\n    for (let i = 0; i < matrix.rows; i++) {\n      sum += matrix.get(i, j) ** 2 / divider;\n    }\n  }\n  return Math.sqrt(sum);\n}\n\nfunction scaleAll(matrix, scale) {\n  for (let i = 0; i < matrix.rows; i++) {\n    for (let j = 0; j < matrix.columns; j++) {\n      matrix.set(i, j, matrix.get(i, j) / scale);\n    }\n  }\n}\n\nclass AbstractMatrix {\n  static from1DArray(newRows, newColumns, newData) {\n    let length = newRows * newColumns;\n    if (length !== newData.length) {\n      throw new RangeError('data length does not match given dimensions');\n    }\n    let newMatrix = new Matrix(newRows, newColumns);\n    for (let row = 0; row < newRows; row++) {\n      for (let column = 0; column < newColumns; column++) {\n        newMatrix.set(row, column, newData[row * newColumns + column]);\n      }\n    }\n    return newMatrix;\n  }\n\n  static rowVector(newData) {\n    let vector = new Matrix(1, newData.length);\n    for (let i = 0; i < newData.length; i++) {\n      vector.set(0, i, newData[i]);\n    }\n    return vector;\n  }\n\n  static columnVector(newData) {\n    let vector = new Matrix(newData.length, 1);\n    for (let i = 0; i < newData.length; i++) {\n      vector.set(i, 0, newData[i]);\n    }\n    return vector;\n  }\n\n  static zeros(rows, columns) {\n    return new Matrix(rows, columns);\n  }\n\n  static ones(rows, columns) {\n    return new Matrix(rows, columns).fill(1);\n  }\n\n  static rand(rows, columns, options = {}) {\n    if (typeof options !== 'object') {\n      throw new TypeError('options must be an object');\n    }\n    const { random = Math.random } = options;\n    let matrix = new Matrix(rows, columns);\n    for (let i = 0; i < rows; i++) {\n      for (let j = 0; j < columns; j++) {\n        matrix.set(i, j, random());\n      }\n    }\n    return matrix;\n  }\n\n  static randInt(rows, columns, options = {}) {\n    if (typeof options !== 'object') {\n      throw new TypeError('options must be an object');\n    }\n    const { min = 0, max = 1000, random = Math.random } = options;\n    if (!Number.isInteger(min)) throw new TypeError('min must be an integer');\n    if (!Number.isInteger(max)) throw new TypeError('max must be an integer');\n    if (min >= max) throw new RangeError('min must be smaller than max');\n    let interval = max - min;\n    let matrix = new Matrix(rows, columns);\n    for (let i = 0; i < rows; i++) {\n      for (let j = 0; j < columns; j++) {\n        let value = min + Math.round(random() * interval);\n        matrix.set(i, j, value);\n      }\n    }\n    return matrix;\n  }\n\n  static eye(rows, columns, value) {\n    if (columns === undefined) columns = rows;\n    if (value === undefined) value = 1;\n    let min = Math.min(rows, columns);\n    let matrix = this.zeros(rows, columns);\n    for (let i = 0; i < min; i++) {\n      matrix.set(i, i, value);\n    }\n    return matrix;\n  }\n\n  static diag(data, rows, columns) {\n    let l = data.length;\n    if (rows === undefined) rows = l;\n    if (columns === undefined) columns = rows;\n    let min = Math.min(l, rows, columns);\n    let matrix = this.zeros(rows, columns);\n    for (let i = 0; i < min; i++) {\n      matrix.set(i, i, data[i]);\n    }\n    return matrix;\n  }\n\n  static min(matrix1, matrix2) {\n    matrix1 = this.checkMatrix(matrix1);\n    matrix2 = this.checkMatrix(matrix2);\n    let rows = matrix1.rows;\n    let columns = matrix1.columns;\n    let result = new Matrix(rows, columns);\n    for (let i = 0; i < rows; i++) {\n      for (let j = 0; j < columns; j++) {\n        result.set(i, j, Math.min(matrix1.get(i, j), matrix2.get(i, j)));\n      }\n    }\n    return result;\n  }\n\n  static max(matrix1, matrix2) {\n    matrix1 = this.checkMatrix(matrix1);\n    matrix2 = this.checkMatrix(matrix2);\n    let rows = matrix1.rows;\n    let columns = matrix1.columns;\n    let result = new this(rows, columns);\n    for (let i = 0; i < rows; i++) {\n      for (let j = 0; j < columns; j++) {\n        result.set(i, j, Math.max(matrix1.get(i, j), matrix2.get(i, j)));\n      }\n    }\n    return result;\n  }\n\n  static checkMatrix(value) {\n    return AbstractMatrix.isMatrix(value) ? value : new Matrix(value);\n  }\n\n  static isMatrix(value) {\n    return value != null && value.klass === 'Matrix';\n  }\n\n  get size() {\n    return this.rows * this.columns;\n  }\n\n  apply(callback) {\n    if (typeof callback !== 'function') {\n      throw new TypeError('callback must be a function');\n    }\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        callback.call(this, i, j);\n      }\n    }\n    return this;\n  }\n\n  to1DArray() {\n    let array = [];\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        array.push(this.get(i, j));\n      }\n    }\n    return array;\n  }\n\n  to2DArray() {\n    let copy = [];\n    for (let i = 0; i < this.rows; i++) {\n      copy.push([]);\n      for (let j = 0; j < this.columns; j++) {\n        copy[i].push(this.get(i, j));\n      }\n    }\n    return copy;\n  }\n\n  toJSON() {\n    return this.to2DArray();\n  }\n\n  isRowVector() {\n    return this.rows === 1;\n  }\n\n  isColumnVector() {\n    return this.columns === 1;\n  }\n\n  isVector() {\n    return this.rows === 1 || this.columns === 1;\n  }\n\n  isSquare() {\n    return this.rows === this.columns;\n  }\n\n  isEmpty() {\n    return this.rows === 0 || this.columns === 0;\n  }\n\n  isSymmetric() {\n    if (this.isSquare()) {\n      for (let i = 0; i < this.rows; i++) {\n        for (let j = 0; j <= i; j++) {\n          if (this.get(i, j) !== this.get(j, i)) {\n            return false;\n          }\n        }\n      }\n      return true;\n    }\n    return false;\n  }\n\n  isDistance() {\n    if (!this.isSymmetric()) return false;\n\n    for (let i = 0; i < this.rows; i++) {\n      if (this.get(i, i) !== 0) return false;\n    }\n\n    return true;\n  }\n\n  isEchelonForm() {\n    let i = 0;\n    let j = 0;\n    let previousColumn = -1;\n    let isEchelonForm = true;\n    let checked = false;\n    while (i < this.rows && isEchelonForm) {\n      j = 0;\n      checked = false;\n      while (j < this.columns && checked === false) {\n        if (this.get(i, j) === 0) {\n          j++;\n        } else if (this.get(i, j) === 1 && j > previousColumn) {\n          checked = true;\n          previousColumn = j;\n        } else {\n          isEchelonForm = false;\n          checked = true;\n        }\n      }\n      i++;\n    }\n    return isEchelonForm;\n  }\n\n  isReducedEchelonForm() {\n    let i = 0;\n    let j = 0;\n    let previousColumn = -1;\n    let isReducedEchelonForm = true;\n    let checked = false;\n    while (i < this.rows && isReducedEchelonForm) {\n      j = 0;\n      checked = false;\n      while (j < this.columns && checked === false) {\n        if (this.get(i, j) === 0) {\n          j++;\n        } else if (this.get(i, j) === 1 && j > previousColumn) {\n          checked = true;\n          previousColumn = j;\n        } else {\n          isReducedEchelonForm = false;\n          checked = true;\n        }\n      }\n      for (let k = j + 1; k < this.rows; k++) {\n        if (this.get(i, k) !== 0) {\n          isReducedEchelonForm = false;\n        }\n      }\n      i++;\n    }\n    return isReducedEchelonForm;\n  }\n\n  echelonForm() {\n    let result = this.clone();\n    let h = 0;\n    let k = 0;\n    while (h < result.rows && k < result.columns) {\n      let iMax = h;\n      for (let i = h; i < result.rows; i++) {\n        if (result.get(i, k) > result.get(iMax, k)) {\n          iMax = i;\n        }\n      }\n      if (result.get(iMax, k) === 0) {\n        k++;\n      } else {\n        result.swapRows(h, iMax);\n        let tmp = result.get(h, k);\n        for (let j = k; j < result.columns; j++) {\n          result.set(h, j, result.get(h, j) / tmp);\n        }\n        for (let i = h + 1; i < result.rows; i++) {\n          let factor = result.get(i, k) / result.get(h, k);\n          result.set(i, k, 0);\n          for (let j = k + 1; j < result.columns; j++) {\n            result.set(i, j, result.get(i, j) - result.get(h, j) * factor);\n          }\n        }\n        h++;\n        k++;\n      }\n    }\n    return result;\n  }\n\n  reducedEchelonForm() {\n    let result = this.echelonForm();\n    let m = result.columns;\n    let n = result.rows;\n    let h = n - 1;\n    while (h >= 0) {\n      if (result.maxRow(h) === 0) {\n        h--;\n      } else {\n        let p = 0;\n        let pivot = false;\n        while (p < n && pivot === false) {\n          if (result.get(h, p) === 1) {\n            pivot = true;\n          } else {\n            p++;\n          }\n        }\n        for (let i = 0; i < h; i++) {\n          let factor = result.get(i, p);\n          for (let j = p; j < m; j++) {\n            let tmp = result.get(i, j) - factor * result.get(h, j);\n            result.set(i, j, tmp);\n          }\n        }\n        h--;\n      }\n    }\n    return result;\n  }\n\n  set() {\n    throw new Error('set method is unimplemented');\n  }\n\n  get() {\n    throw new Error('get method is unimplemented');\n  }\n\n  repeat(options = {}) {\n    if (typeof options !== 'object') {\n      throw new TypeError('options must be an object');\n    }\n    const { rows = 1, columns = 1 } = options;\n    if (!Number.isInteger(rows) || rows <= 0) {\n      throw new TypeError('rows must be a positive integer');\n    }\n    if (!Number.isInteger(columns) || columns <= 0) {\n      throw new TypeError('columns must be a positive integer');\n    }\n    let matrix = new Matrix(this.rows * rows, this.columns * columns);\n    for (let i = 0; i < rows; i++) {\n      for (let j = 0; j < columns; j++) {\n        matrix.setSubMatrix(this, this.rows * i, this.columns * j);\n      }\n    }\n    return matrix;\n  }\n\n  fill(value) {\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, value);\n      }\n    }\n    return this;\n  }\n\n  neg() {\n    return this.mulS(-1);\n  }\n\n  getRow(index) {\n    checkRowIndex(this, index);\n    let row = [];\n    for (let i = 0; i < this.columns; i++) {\n      row.push(this.get(index, i));\n    }\n    return row;\n  }\n\n  getRowVector(index) {\n    return Matrix.rowVector(this.getRow(index));\n  }\n\n  setRow(index, array) {\n    checkRowIndex(this, index);\n    array = checkRowVector(this, array);\n    for (let i = 0; i < this.columns; i++) {\n      this.set(index, i, array[i]);\n    }\n    return this;\n  }\n\n  swapRows(row1, row2) {\n    checkRowIndex(this, row1);\n    checkRowIndex(this, row2);\n    for (let i = 0; i < this.columns; i++) {\n      let temp = this.get(row1, i);\n      this.set(row1, i, this.get(row2, i));\n      this.set(row2, i, temp);\n    }\n    return this;\n  }\n\n  getColumn(index) {\n    checkColumnIndex(this, index);\n    let column = [];\n    for (let i = 0; i < this.rows; i++) {\n      column.push(this.get(i, index));\n    }\n    return column;\n  }\n\n  getColumnVector(index) {\n    return Matrix.columnVector(this.getColumn(index));\n  }\n\n  setColumn(index, array) {\n    checkColumnIndex(this, index);\n    array = checkColumnVector(this, array);\n    for (let i = 0; i < this.rows; i++) {\n      this.set(i, index, array[i]);\n    }\n    return this;\n  }\n\n  swapColumns(column1, column2) {\n    checkColumnIndex(this, column1);\n    checkColumnIndex(this, column2);\n    for (let i = 0; i < this.rows; i++) {\n      let temp = this.get(i, column1);\n      this.set(i, column1, this.get(i, column2));\n      this.set(i, column2, temp);\n    }\n    return this;\n  }\n\n  addRowVector(vector) {\n    vector = checkRowVector(this, vector);\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) + vector[j]);\n      }\n    }\n    return this;\n  }\n\n  subRowVector(vector) {\n    vector = checkRowVector(this, vector);\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) - vector[j]);\n      }\n    }\n    return this;\n  }\n\n  mulRowVector(vector) {\n    vector = checkRowVector(this, vector);\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) * vector[j]);\n      }\n    }\n    return this;\n  }\n\n  divRowVector(vector) {\n    vector = checkRowVector(this, vector);\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) / vector[j]);\n      }\n    }\n    return this;\n  }\n\n  addColumnVector(vector) {\n    vector = checkColumnVector(this, vector);\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) + vector[i]);\n      }\n    }\n    return this;\n  }\n\n  subColumnVector(vector) {\n    vector = checkColumnVector(this, vector);\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) - vector[i]);\n      }\n    }\n    return this;\n  }\n\n  mulColumnVector(vector) {\n    vector = checkColumnVector(this, vector);\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) * vector[i]);\n      }\n    }\n    return this;\n  }\n\n  divColumnVector(vector) {\n    vector = checkColumnVector(this, vector);\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        this.set(i, j, this.get(i, j) / vector[i]);\n      }\n    }\n    return this;\n  }\n\n  mulRow(index, value) {\n    checkRowIndex(this, index);\n    for (let i = 0; i < this.columns; i++) {\n      this.set(index, i, this.get(index, i) * value);\n    }\n    return this;\n  }\n\n  mulColumn(index, value) {\n    checkColumnIndex(this, index);\n    for (let i = 0; i < this.rows; i++) {\n      this.set(i, index, this.get(i, index) * value);\n    }\n    return this;\n  }\n\n  max(by) {\n    if (this.isEmpty()) {\n      return NaN;\n    }\n    switch (by) {\n      case 'row': {\n        const max = new Array(this.rows).fill(Number.NEGATIVE_INFINITY);\n        for (let row = 0; row < this.rows; row++) {\n          for (let column = 0; column < this.columns; column++) {\n            if (this.get(row, column) > max[row]) {\n              max[row] = this.get(row, column);\n            }\n          }\n        }\n        return max;\n      }\n      case 'column': {\n        const max = new Array(this.columns).fill(Number.NEGATIVE_INFINITY);\n        for (let row = 0; row < this.rows; row++) {\n          for (let column = 0; column < this.columns; column++) {\n            if (this.get(row, column) > max[column]) {\n              max[column] = this.get(row, column);\n            }\n          }\n        }\n        return max;\n      }\n      case undefined: {\n        let max = this.get(0, 0);\n        for (let row = 0; row < this.rows; row++) {\n          for (let column = 0; column < this.columns; column++) {\n            if (this.get(row, column) > max) {\n              max = this.get(row, column);\n            }\n          }\n        }\n        return max;\n      }\n      default:\n        throw new Error(`invalid option: ${by}`);\n    }\n  }\n\n  maxIndex() {\n    checkNonEmpty(this);\n    let v = this.get(0, 0);\n    let idx = [0, 0];\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        if (this.get(i, j) > v) {\n          v = this.get(i, j);\n          idx[0] = i;\n          idx[1] = j;\n        }\n      }\n    }\n    return idx;\n  }\n\n  min(by) {\n    if (this.isEmpty()) {\n      return NaN;\n    }\n\n    switch (by) {\n      case 'row': {\n        const min = new Array(this.rows).fill(Number.POSITIVE_INFINITY);\n        for (let row = 0; row < this.rows; row++) {\n          for (let column = 0; column < this.columns; column++) {\n            if (this.get(row, column) < min[row]) {\n              min[row] = this.get(row, column);\n            }\n          }\n        }\n        return min;\n      }\n      case 'column': {\n        const min = new Array(this.columns).fill(Number.POSITIVE_INFINITY);\n        for (let row = 0; row < this.rows; row++) {\n          for (let column = 0; column < this.columns; column++) {\n            if (this.get(row, column) < min[column]) {\n              min[column] = this.get(row, column);\n            }\n          }\n        }\n        return min;\n      }\n      case undefined: {\n        let min = this.get(0, 0);\n        for (let row = 0; row < this.rows; row++) {\n          for (let column = 0; column < this.columns; column++) {\n            if (this.get(row, column) < min) {\n              min = this.get(row, column);\n            }\n          }\n        }\n        return min;\n      }\n      default:\n        throw new Error(`invalid option: ${by}`);\n    }\n  }\n\n  minIndex() {\n    checkNonEmpty(this);\n    let v = this.get(0, 0);\n    let idx = [0, 0];\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        if (this.get(i, j) < v) {\n          v = this.get(i, j);\n          idx[0] = i;\n          idx[1] = j;\n        }\n      }\n    }\n    return idx;\n  }\n\n  maxRow(row) {\n    checkRowIndex(this, row);\n    if (this.isEmpty()) {\n      return NaN;\n    }\n    let v = this.get(row, 0);\n    for (let i = 1; i < this.columns; i++) {\n      if (this.get(row, i) > v) {\n        v = this.get(row, i);\n      }\n    }\n    return v;\n  }\n\n  maxRowIndex(row) {\n    checkRowIndex(this, row);\n    checkNonEmpty(this);\n    let v = this.get(row, 0);\n    let idx = [row, 0];\n    for (let i = 1; i < this.columns; i++) {\n      if (this.get(row, i) > v) {\n        v = this.get(row, i);\n        idx[1] = i;\n      }\n    }\n    return idx;\n  }\n\n  minRow(row) {\n    checkRowIndex(this, row);\n    if (this.isEmpty()) {\n      return NaN;\n    }\n    let v = this.get(row, 0);\n    for (let i = 1; i < this.columns; i++) {\n      if (this.get(row, i) < v) {\n        v = this.get(row, i);\n      }\n    }\n    return v;\n  }\n\n  minRowIndex(row) {\n    checkRowIndex(this, row);\n    checkNonEmpty(this);\n    let v = this.get(row, 0);\n    let idx = [row, 0];\n    for (let i = 1; i < this.columns; i++) {\n      if (this.get(row, i) < v) {\n        v = this.get(row, i);\n        idx[1] = i;\n      }\n    }\n    return idx;\n  }\n\n  maxColumn(column) {\n    checkColumnIndex(this, column);\n    if (this.isEmpty()) {\n      return NaN;\n    }\n    let v = this.get(0, column);\n    for (let i = 1; i < this.rows; i++) {\n      if (this.get(i, column) > v) {\n        v = this.get(i, column);\n      }\n    }\n    return v;\n  }\n\n  maxColumnIndex(column) {\n    checkColumnIndex(this, column);\n    checkNonEmpty(this);\n    let v = this.get(0, column);\n    let idx = [0, column];\n    for (let i = 1; i < this.rows; i++) {\n      if (this.get(i, column) > v) {\n        v = this.get(i, column);\n        idx[0] = i;\n      }\n    }\n    return idx;\n  }\n\n  minColumn(column) {\n    checkColumnIndex(this, column);\n    if (this.isEmpty()) {\n      return NaN;\n    }\n    let v = this.get(0, column);\n    for (let i = 1; i < this.rows; i++) {\n      if (this.get(i, column) < v) {\n        v = this.get(i, column);\n      }\n    }\n    return v;\n  }\n\n  minColumnIndex(column) {\n    checkColumnIndex(this, column);\n    checkNonEmpty(this);\n    let v = this.get(0, column);\n    let idx = [0, column];\n    for (let i = 1; i < this.rows; i++) {\n      if (this.get(i, column) < v) {\n        v = this.get(i, column);\n        idx[0] = i;\n      }\n    }\n    return idx;\n  }\n\n  diag() {\n    let min = Math.min(this.rows, this.columns);\n    let diag = [];\n    for (let i = 0; i < min; i++) {\n      diag.push(this.get(i, i));\n    }\n    return diag;\n  }\n\n  norm(type = 'frobenius') {\n    switch (type) {\n      case 'max':\n        return this.max();\n      case 'frobenius':\n        return Math.sqrt(this.dot(this));\n      default:\n        throw new RangeError(`unknown norm type: ${type}`);\n    }\n  }\n\n  cumulativeSum() {\n    let sum = 0;\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        sum += this.get(i, j);\n        this.set(i, j, sum);\n      }\n    }\n    return this;\n  }\n\n  dot(vector2) {\n    if (AbstractMatrix.isMatrix(vector2)) vector2 = vector2.to1DArray();\n    let vector1 = this.to1DArray();\n    if (vector1.length !== vector2.length) {\n      throw new RangeError('vectors do not have the same size');\n    }\n    let dot = 0;\n    for (let i = 0; i < vector1.length; i++) {\n      dot += vector1[i] * vector2[i];\n    }\n    return dot;\n  }\n\n  mmul(other) {\n    other = Matrix.checkMatrix(other);\n\n    let m = this.rows;\n    let n = this.columns;\n    let p = other.columns;\n\n    let result = new Matrix(m, p);\n\n    let Bcolj = new Float64Array(n);\n    for (let j = 0; j < p; j++) {\n      for (let k = 0; k < n; k++) {\n        Bcolj[k] = other.get(k, j);\n      }\n\n      for (let i = 0; i < m; i++) {\n        let s = 0;\n        for (let k = 0; k < n; k++) {\n          s += this.get(i, k) * Bcolj[k];\n        }\n\n        result.set(i, j, s);\n      }\n    }\n    return result;\n  }\n\n  mpow(scalar) {\n    if (!this.isSquare()) {\n      throw new RangeError('Matrix must be square');\n    }\n    if (!Number.isInteger(scalar) || scalar < 0) {\n      throw new RangeError('Exponent must be a non-negative integer');\n    }\n    // Russian Peasant exponentiation, i.e. exponentiation by squaring\n    let result = Matrix.eye(this.rows);\n    let bb = this;\n    // Note: Don't bit shift. In JS, that would truncate at 32 bits\n    for (let e = scalar; e >= 1; e /= 2) {\n      if ((e & 1) !== 0) {\n        result = result.mmul(bb);\n      }\n      bb = bb.mmul(bb);\n    }\n    return result;\n  }\n\n  strassen2x2(other) {\n    other = Matrix.checkMatrix(other);\n    let result = new Matrix(2, 2);\n    const a11 = this.get(0, 0);\n    const b11 = other.get(0, 0);\n    const a12 = this.get(0, 1);\n    const b12 = other.get(0, 1);\n    const a21 = this.get(1, 0);\n    const b21 = other.get(1, 0);\n    const a22 = this.get(1, 1);\n    const b22 = other.get(1, 1);\n\n    // Compute intermediate values.\n    const m1 = (a11 + a22) * (b11 + b22);\n    const m2 = (a21 + a22) * b11;\n    const m3 = a11 * (b12 - b22);\n    const m4 = a22 * (b21 - b11);\n    const m5 = (a11 + a12) * b22;\n    const m6 = (a21 - a11) * (b11 + b12);\n    const m7 = (a12 - a22) * (b21 + b22);\n\n    // Combine intermediate values into the output.\n    const c00 = m1 + m4 - m5 + m7;\n    const c01 = m3 + m5;\n    const c10 = m2 + m4;\n    const c11 = m1 - m2 + m3 + m6;\n\n    result.set(0, 0, c00);\n    result.set(0, 1, c01);\n    result.set(1, 0, c10);\n    result.set(1, 1, c11);\n    return result;\n  }\n\n  strassen3x3(other) {\n    other = Matrix.checkMatrix(other);\n    let result = new Matrix(3, 3);\n\n    const a00 = this.get(0, 0);\n    const a01 = this.get(0, 1);\n    const a02 = this.get(0, 2);\n    const a10 = this.get(1, 0);\n    const a11 = this.get(1, 1);\n    const a12 = this.get(1, 2);\n    const a20 = this.get(2, 0);\n    const a21 = this.get(2, 1);\n    const a22 = this.get(2, 2);\n\n    const b00 = other.get(0, 0);\n    const b01 = other.get(0, 1);\n    const b02 = other.get(0, 2);\n    const b10 = other.get(1, 0);\n    const b11 = other.get(1, 1);\n    const b12 = other.get(1, 2);\n    const b20 = other.get(2, 0);\n    const b21 = other.get(2, 1);\n    const b22 = other.get(2, 2);\n\n    const m1 = (a00 + a01 + a02 - a10 - a11 - a21 - a22) * b11;\n    const m2 = (a00 - a10) * (-b01 + b11);\n    const m3 = a11 * (-b00 + b01 + b10 - b11 - b12 - b20 + b22);\n    const m4 = (-a00 + a10 + a11) * (b00 - b01 + b11);\n    const m5 = (a10 + a11) * (-b00 + b01);\n    const m6 = a00 * b00;\n    const m7 = (-a00 + a20 + a21) * (b00 - b02 + b12);\n    const m8 = (-a00 + a20) * (b02 - b12);\n    const m9 = (a20 + a21) * (-b00 + b02);\n    const m10 = (a00 + a01 + a02 - a11 - a12 - a20 - a21) * b12;\n    const m11 = a21 * (-b00 + b02 + b10 - b11 - b12 - b20 + b21);\n    const m12 = (-a02 + a21 + a22) * (b11 + b20 - b21);\n    const m13 = (a02 - a22) * (b11 - b21);\n    const m14 = a02 * b20;\n    const m15 = (a21 + a22) * (-b20 + b21);\n    const m16 = (-a02 + a11 + a12) * (b12 + b20 - b22);\n    const m17 = (a02 - a12) * (b12 - b22);\n    const m18 = (a11 + a12) * (-b20 + b22);\n    const m19 = a01 * b10;\n    const m20 = a12 * b21;\n    const m21 = a10 * b02;\n    const m22 = a20 * b01;\n    const m23 = a22 * b22;\n\n    const c00 = m6 + m14 + m19;\n    const c01 = m1 + m4 + m5 + m6 + m12 + m14 + m15;\n    const c02 = m6 + m7 + m9 + m10 + m14 + m16 + m18;\n    const c10 = m2 + m3 + m4 + m6 + m14 + m16 + m17;\n    const c11 = m2 + m4 + m5 + m6 + m20;\n    const c12 = m14 + m16 + m17 + m18 + m21;\n    const c20 = m6 + m7 + m8 + m11 + m12 + m13 + m14;\n    const c21 = m12 + m13 + m14 + m15 + m22;\n    const c22 = m6 + m7 + m8 + m9 + m23;\n\n    result.set(0, 0, c00);\n    result.set(0, 1, c01);\n    result.set(0, 2, c02);\n    result.set(1, 0, c10);\n    result.set(1, 1, c11);\n    result.set(1, 2, c12);\n    result.set(2, 0, c20);\n    result.set(2, 1, c21);\n    result.set(2, 2, c22);\n    return result;\n  }\n\n  mmulStrassen(y) {\n    y = Matrix.checkMatrix(y);\n    let x = this.clone();\n    let r1 = x.rows;\n    let c1 = x.columns;\n    let r2 = y.rows;\n    let c2 = y.columns;\n    if (c1 !== r2) {\n      // eslint-disable-next-line no-console\n      console.warn(\n        `Multiplying ${r1} x ${c1} and ${r2} x ${c2} matrix: dimensions do not match.`,\n      );\n    }\n\n    // Put a matrix into the top left of a matrix of zeros.\n    // `rows` and `cols` are the dimensions of the output matrix.\n    function embed(mat, rows, cols) {\n      let r = mat.rows;\n      let c = mat.columns;\n      if (r === rows && c === cols) {\n        return mat;\n      } else {\n        let resultat = AbstractMatrix.zeros(rows, cols);\n        resultat = resultat.setSubMatrix(mat, 0, 0);\n        return resultat;\n      }\n    }\n\n    // Make sure both matrices are the same size.\n    // This is exclusively for simplicity:\n    // this algorithm can be implemented with matrices of different sizes.\n\n    let r = Math.max(r1, r2);\n    let c = Math.max(c1, c2);\n    x = embed(x, r, c);\n    y = embed(y, r, c);\n\n    // Our recursive multiplication function.\n    function blockMult(a, b, rows, cols) {\n      // For small matrices, resort to naive multiplication.\n      if (rows <= 512 || cols <= 512) {\n        return a.mmul(b); // a is equivalent to this\n      }\n\n      // Apply dynamic padding.\n      if (rows % 2 === 1 && cols % 2 === 1) {\n        a = embed(a, rows + 1, cols + 1);\n        b = embed(b, rows + 1, cols + 1);\n      } else if (rows % 2 === 1) {\n        a = embed(a, rows + 1, cols);\n        b = embed(b, rows + 1, cols);\n      } else if (cols % 2 === 1) {\n        a = embed(a, rows, cols + 1);\n        b = embed(b, rows, cols + 1);\n      }\n\n      let halfRows = parseInt(a.rows / 2, 10);\n      let halfCols = parseInt(a.columns / 2, 10);\n      // Subdivide input matrices.\n      let a11 = a.subMatrix(0, halfRows - 1, 0, halfCols - 1);\n      let b11 = b.subMatrix(0, halfRows - 1, 0, halfCols - 1);\n\n      let a12 = a.subMatrix(0, halfRows - 1, halfCols, a.columns - 1);\n      let b12 = b.subMatrix(0, halfRows - 1, halfCols, b.columns - 1);\n\n      let a21 = a.subMatrix(halfRows, a.rows - 1, 0, halfCols - 1);\n      let b21 = b.subMatrix(halfRows, b.rows - 1, 0, halfCols - 1);\n\n      let a22 = a.subMatrix(halfRows, a.rows - 1, halfCols, a.columns - 1);\n      let b22 = b.subMatrix(halfRows, b.rows - 1, halfCols, b.columns - 1);\n\n      // Compute intermediate values.\n      let m1 = blockMult(\n        AbstractMatrix.add(a11, a22),\n        AbstractMatrix.add(b11, b22),\n        halfRows,\n        halfCols,\n      );\n      let m2 = blockMult(AbstractMatrix.add(a21, a22), b11, halfRows, halfCols);\n      let m3 = blockMult(a11, AbstractMatrix.sub(b12, b22), halfRows, halfCols);\n      let m4 = blockMult(a22, AbstractMatrix.sub(b21, b11), halfRows, halfCols);\n      let m5 = blockMult(AbstractMatrix.add(a11, a12), b22, halfRows, halfCols);\n      let m6 = blockMult(\n        AbstractMatrix.sub(a21, a11),\n        AbstractMatrix.add(b11, b12),\n        halfRows,\n        halfCols,\n      );\n      let m7 = blockMult(\n        AbstractMatrix.sub(a12, a22),\n        AbstractMatrix.add(b21, b22),\n        halfRows,\n        halfCols,\n      );\n\n      // Combine intermediate values into the output.\n      let c11 = AbstractMatrix.add(m1, m4);\n      c11.sub(m5);\n      c11.add(m7);\n      let c12 = AbstractMatrix.add(m3, m5);\n      let c21 = AbstractMatrix.add(m2, m4);\n      let c22 = AbstractMatrix.sub(m1, m2);\n      c22.add(m3);\n      c22.add(m6);\n\n      // Crop output to the desired size (undo dynamic padding).\n      let result = AbstractMatrix.zeros(2 * c11.rows, 2 * c11.columns);\n      result = result.setSubMatrix(c11, 0, 0);\n      result = result.setSubMatrix(c12, c11.rows, 0);\n      result = result.setSubMatrix(c21, 0, c11.columns);\n      result = result.setSubMatrix(c22, c11.rows, c11.columns);\n      return result.subMatrix(0, rows - 1, 0, cols - 1);\n    }\n\n    return blockMult(x, y, r, c);\n  }\n\n  scaleRows(options = {}) {\n    if (typeof options !== 'object') {\n      throw new TypeError('options must be an object');\n    }\n    const { min = 0, max = 1 } = options;\n    if (!Number.isFinite(min)) throw new TypeError('min must be a number');\n    if (!Number.isFinite(max)) throw new TypeError('max must be a number');\n    if (min >= max) throw new RangeError('min must be smaller than max');\n    let newMatrix = new Matrix(this.rows, this.columns);\n    for (let i = 0; i < this.rows; i++) {\n      const row = this.getRow(i);\n      if (row.length > 0) {\n        rescale(row, { min, max, output: row });\n      }\n      newMatrix.setRow(i, row);\n    }\n    return newMatrix;\n  }\n\n  scaleColumns(options = {}) {\n    if (typeof options !== 'object') {\n      throw new TypeError('options must be an object');\n    }\n    const { min = 0, max = 1 } = options;\n    if (!Number.isFinite(min)) throw new TypeError('min must be a number');\n    if (!Number.isFinite(max)) throw new TypeError('max must be a number');\n    if (min >= max) throw new RangeError('min must be smaller than max');\n    let newMatrix = new Matrix(this.rows, this.columns);\n    for (let i = 0; i < this.columns; i++) {\n      const column = this.getColumn(i);\n      if (column.length) {\n        rescale(column, {\n          min,\n          max,\n          output: column,\n        });\n      }\n      newMatrix.setColumn(i, column);\n    }\n    return newMatrix;\n  }\n\n  flipRows() {\n    const middle = Math.ceil(this.columns / 2);\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < middle; j++) {\n        let first = this.get(i, j);\n        let last = this.get(i, this.columns - 1 - j);\n        this.set(i, j, last);\n        this.set(i, this.columns - 1 - j, first);\n      }\n    }\n    return this;\n  }\n\n  flipColumns() {\n    const middle = Math.ceil(this.rows / 2);\n    for (let j = 0; j < this.columns; j++) {\n      for (let i = 0; i < middle; i++) {\n        let first = this.get(i, j);\n        let last = this.get(this.rows - 1 - i, j);\n        this.set(i, j, last);\n        this.set(this.rows - 1 - i, j, first);\n      }\n    }\n    return this;\n  }\n\n  kroneckerProduct(other) {\n    other = Matrix.checkMatrix(other);\n\n    let m = this.rows;\n    let n = this.columns;\n    let p = other.rows;\n    let q = other.columns;\n\n    let result = new Matrix(m * p, n * q);\n    for (let i = 0; i < m; i++) {\n      for (let j = 0; j < n; j++) {\n        for (let k = 0; k < p; k++) {\n          for (let l = 0; l < q; l++) {\n            result.set(p * i + k, q * j + l, this.get(i, j) * other.get(k, l));\n          }\n        }\n      }\n    }\n    return result;\n  }\n\n  kroneckerSum(other) {\n    other = Matrix.checkMatrix(other);\n    if (!this.isSquare() || !other.isSquare()) {\n      throw new Error('Kronecker Sum needs two Square Matrices');\n    }\n    let m = this.rows;\n    let n = other.rows;\n    let AxI = this.kroneckerProduct(Matrix.eye(n, n));\n    let IxB = Matrix.eye(m, m).kroneckerProduct(other);\n    return AxI.add(IxB);\n  }\n\n  transpose() {\n    let result = new Matrix(this.columns, this.rows);\n    for (let i = 0; i < this.rows; i++) {\n      for (let j = 0; j < this.columns; j++) {\n        result.set(j, i, this.get(i, j));\n      }\n    }\n    return result;\n  }\n\n  sortRows(compareFunction = compareNumbers) {\n    for (let i = 0; i < this.rows; i++) {\n      this.setRow(i, this.getRow(i).sort(compareFunction));\n    }\n    return this;\n  }\n\n  sortColumns(compareFunction = compareNumbers) {\n    for (let i = 0; i < this.columns; i++) {\n      this.setColumn(i, this.getColumn(i).sort(compareFunction));\n    }\n    return this;\n  }\n\n  subMatrix(startRow, endRow, startColumn, endColumn) {\n    checkRange(this, startRow, endRow, startColumn, endColumn);\n    let newMatrix = new Matrix(\n      endRow - startRow + 1,\n      endColumn - startColumn + 1,\n    );\n    for (let i = startRow; i <= endRow; i++) {\n      for (let j = startColumn; j <= endColumn; j++) {\n        newMatrix.set(i - startRow, j - startColumn, this.get(i, j));\n      }\n    }\n    return newMatrix;\n  }\n\n  subMatrixRow(indices, startColumn, endColumn) {\n    if (startColumn === undefined) startColumn = 0;\n    if (endColumn === undefined) endColumn = this.columns - 1;\n    if (\n      startColumn > endColumn ||\n      startColumn < 0 ||\n      startColumn >= this.columns ||\n      endColumn < 0 ||\n      endColumn >= this.columns\n    ) {\n      throw new RangeError('Argument out of range');\n    }\n\n    let newMatrix = new Matrix(indices.length, endColumn - startColumn + 1);\n    for (let i = 0; i < indices.length; i++) {\n      for (let j = startColumn; j <= endColumn; j++) {\n        if (indices[i] < 0 || indices[i] >= this.rows) {\n          throw new RangeError(`Row index out of range: ${indices[i]}`);\n        }\n        newMatrix.set(i, j - startColumn, this.get(indices[i], j));\n      }\n    }\n    return newMatrix;\n  }\n\n  subMatrixColumn(indices, startRow, endRow) {\n    if (startRow === undefined) startRow = 0;\n    if (endRow === undefined) endRow = this.rows - 1;\n    if (\n      startRow > endRow ||\n      startRow < 0 ||\n      startRow >= this.rows ||\n      endRow < 0 ||\n      endRow >= this.rows\n    ) {\n      throw new RangeError('Argument out of range');\n    }\n\n    let newMatrix = new Matrix(endRow - startRow + 1, indices.length);\n    for (let i = 0; i < indices.length; i++) {\n      for (let j = startRow; j <= endRow; j++) {\n        if (indices[i] < 0 || indices[i] >= this.columns) {\n          throw new RangeError(`Column index out of range: ${indices[i]}`);\n        }\n        newMatrix.set(j - startRow, i, this.get(j, indices[i]));\n      }\n    }\n    return newMatrix;\n  }\n\n  setSubMatrix(matrix, startRow, startColumn) {\n    matrix = Matrix.checkMatrix(matrix);\n    if (matrix.isEmpty()) {\n      return this;\n    }\n    let endRow = startRow + matrix.rows - 1;\n    let endColumn = startColumn + matrix.columns - 1;\n    checkRange(this, startRow, endRow, startColumn, endColumn);\n    for (let i = 0; i < matrix.rows; i++) {\n      for (let j = 0; j < matrix.columns; j++) {\n        this.set(startRow + i, startColumn + j, matrix.get(i, j));\n      }\n    }\n    return this;\n  }\n\n  selection(rowIndices, columnIndices) {\n    checkRowIndices(this, rowIndices);\n    checkColumnIndices(this, columnIndices);\n    let newMatrix = new Matrix(rowIndices.length, columnIndices.length);\n    for (let i = 0; i < rowIndices.length; i++) {\n      let rowIndex = rowIndices[i];\n      for (let j = 0; j < columnIndices.length; j++) {\n        let columnIndex = columnIndices[j];\n        newMatrix.set(i, j, this.get(rowIndex, columnIndex));\n      }\n    }\n    return newMatrix;\n  }\n\n  trace() {\n    let min = Math.min(this.rows, this.columns);\n    let trace = 0;\n    for (let i = 0; i < min; i++) {\n      trace += this.get(i, i);\n    }\n    return trace;\n  }\n\n  clone() {\n    return this.constructor.copy(this, new Matrix(this.rows, this.columns));\n  }\n\n  /**\n   * @template {AbstractMatrix} M\n   * @param {AbstractMatrix} from\n   * @param {M} to\n   * @return {M}\n   */\n  static copy(from, to) {\n    for (const [row, column, value] of from.entries()) {\n      to.set(row, column, value);\n    }\n\n    return to;\n  }\n\n  sum(by) {\n    switch (by) {\n      case 'row':\n        return sumByRow(this);\n      case 'column':\n        return sumByColumn(this);\n      case undefined:\n        return sumAll(this);\n      default:\n        throw new Error(`invalid option: ${by}`);\n    }\n  }\n\n  product(by) {\n    switch (by) {\n      case 'row':\n        return productByRow(this);\n      case 'column':\n        return productByColumn(this);\n      case undefined:\n        return productAll(this);\n      default:\n        throw new Error(`invalid option: ${by}`);\n    }\n  }\n\n  mean(by) {\n    const sum = this.sum(by);\n    switch (by) {\n      case 'row': {\n        for (let i = 0; i < this.rows; i++) {\n          sum[i] /= this.columns;\n        }\n        return sum;\n      }\n      case 'column': {\n        for (let i = 0; i < this.columns; i++) {\n          sum[i] /= this.rows;\n        }\n        return sum;\n      }\n      case undefined:\n        return sum / this.size;\n      default:\n        throw new Error(`invalid option: ${by}`);\n    }\n  }\n\n  variance(by, options = {}) {\n    if (typeof by === 'object') {\n      options = by;\n      by = undefined;\n    }\n    if (typeof options !== 'object') {\n      throw new TypeError('options must be an object');\n    }\n    const { unbiased = true, mean = this.mean(by) } = options;\n    if (typeof unbiased !== 'boolean') {\n      throw new TypeError('unbiased must be a boolean');\n    }\n    switch (by) {\n      case 'row': {\n        if (!isAnyArray(mean)) {\n          throw new TypeError('mean must be an array');\n        }\n        return varianceByRow(this, unbiased, mean);\n      }\n      case 'column': {\n        if (!isAnyArray(mean)) {\n          throw new TypeError('mean must be an array');\n        }\n        return varianceByColumn(this, unbiased, mean);\n      }\n      case undefined: {\n        if (typeof mean !== 'number') {\n          throw new TypeError('mean must be a number');\n        }\n        return varianceAll(this, unbiased, mean);\n      }\n      default:\n        throw new Error(`invalid option: ${by}`);\n    }\n  }\n\n  standardDeviation(by, options) {\n    if (typeof by === 'object') {\n      options = by;\n      by = undefined;\n    }\n    const variance = this.variance(by, options);\n    if (by === undefined) {\n      return Math.sqrt(variance);\n    } else {\n      for (let i = 0; i < variance.length; i++) {\n        variance[i] = Math.sqrt(variance[i]);\n      }\n      return variance;\n    }\n  }\n\n  center(by, options = {}) {\n    if (typeof by === 'object') {\n      options = by;\n      by = undefined;\n    }\n    if (typeof options !== 'object') {\n      throw new TypeError('options must be an object');\n    }\n    const { center = this.mean(by) } = options;\n    switch (by) {\n      case 'row': {\n        if (!isAnyArray(center)) {\n          throw new TypeError('center must be an array');\n        }\n        centerByRow(this, center);\n        return this;\n      }\n      case 'column': {\n        if (!isAnyArray(center)) {\n          throw new TypeError('center must be an array');\n        }\n        centerByColumn(this, center);\n        return this;\n      }\n      case undefined: {\n        if (typeof center !== 'number') {\n          throw new TypeError('center must be a number');\n        }\n        centerAll(this, center);\n        return this;\n      }\n      default:\n        throw new Error(`invalid option: ${by}`);\n    }\n  }\n\n  scale(by, options = {}) {\n    if (typeof by === 'object') {\n      options = by;\n      by = undefined;\n    }\n    if (typeof options !== 'object') {\n      throw new TypeError('options must be an object');\n    }\n    let scale = options.scale;\n    switch (by) {\n      case 'row': {\n        if (scale === undefined) {\n          scale = getScaleByRow(this);\n        } else if (!isAnyArray(scale)) {\n          throw new TypeError('scale must be an array');\n        }\n        scaleByRow(this, scale);\n        return this;\n      }\n      case 'column': {\n        if (scale === undefined) {\n          scale = getScaleByColumn(this);\n        } else if (!isAnyArray(scale)) {\n          throw new TypeError('scale must be an array');\n        }\n        scaleByColumn(this, scale);\n        return this;\n      }\n      case undefined: {\n        if (scale === undefined) {\n          scale = getScaleAll(this);\n        } else if (typeof scale !== 'number') {\n          throw new TypeError('scale must be a number');\n        }\n        scaleAll(this, scale);\n        return this;\n      }\n      default:\n        throw new Error(`invalid option: ${by}`);\n    }\n  }\n\n  toString(options) {\n    return inspectMatrixWithOptions(this, options);\n  }\n\n  [Symbol.iterator]() {\n    return this.entries();\n  }\n\n  /**\n   * iterator from left to right, from top to bottom\n   * yield [row, column, value]\n   * @returns {Generator<[number, number, number], void, void>}\n   */\n  *entries() {\n    for (let row = 0; row < this.rows; row++) {\n      for (let col = 0; col < this.columns; col++) {\n        yield [row, col, this.get(row, col)];\n      }\n    }\n  }\n\n  /**\n   * iterator from left to right, from top to bottom\n   * yield value\n   * @returns {Generator<number, void, void>}\n   */\n  *values() {\n    for (let row = 0; row < this.rows; row++) {\n      for (let col = 0; col < this.columns; col++) {\n        yield this.get(row, col);\n      }\n    }\n  }\n}\n\nAbstractMatrix.prototype.klass = 'Matrix';\nif (typeof Symbol !== 'undefined') {\n  AbstractMatrix.prototype[Symbol.for('nodejs.util.inspect.custom')] =\n    inspectMatrix;\n}\n\nfunction compareNumbers(a, b) {\n  return a - b;\n}\n\nfunction isArrayOfNumbers(array) {\n  return array.every((element) => {\n    return typeof element === 'number';\n  });\n}\n\n// Synonyms\nAbstractMatrix.random = AbstractMatrix.rand;\nAbstractMatrix.randomInt = AbstractMatrix.randInt;\nAbstractMatrix.diagonal = AbstractMatrix.diag;\nAbstractMatrix.prototype.diagonal = AbstractMatrix.prototype.diag;\nAbstractMatrix.identity = AbstractMatrix.eye;\nAbstractMatrix.prototype.negate = AbstractMatrix.prototype.neg;\nAbstractMatrix.prototype.tensorProduct =\n  AbstractMatrix.prototype.kroneckerProduct;\n\nclass Matrix extends AbstractMatrix {\n  /**\n   * @type {Float64Array[]}\n   */\n  data;\n\n  /**\n   * Init an empty matrix\n   * @param {number} nRows\n   * @param {number} nColumns\n   */\n  #initData(nRows, nColumns) {\n    this.data = [];\n\n    if (Number.isInteger(nColumns) && nColumns >= 0) {\n      for (let i = 0; i < nRows; i++) {\n        this.data.push(new Float64Array(nColumns));\n      }\n    } else {\n      throw new TypeError('nColumns must be a positive integer');\n    }\n\n    this.rows = nRows;\n    this.columns = nColumns;\n  }\n\n  constructor(nRows, nColumns) {\n    super();\n    if (Matrix.isMatrix(nRows)) {\n      this.#initData(nRows.rows, nRows.columns);\n      Matrix.copy(nRows, this);\n    } else if (Number.isInteger(nRows) && nRows >= 0) {\n      this.#initData(nRows, nColumns);\n    } else if (isAnyArray(nRows)) {\n      // Copy the values from the 2D array\n      const arrayData = nRows;\n      nRows = arrayData.length;\n      nColumns = nRows ? arrayData[0].length : 0;\n      if (typeof nColumns !== 'number') {\n        throw new TypeError(\n          'Data must be a 2D array with at least one element',\n        );\n      }\n      this.data = [];\n\n      for (let i = 0; i < nRows; i++) {\n        if (arrayData[i].length !== nColumns) {\n          throw new RangeError('Inconsistent array dimensions');\n        }\n        if (!isArrayOfNumbers(arrayData[i])) {\n          throw new TypeError('Input data contains non-numeric values');\n        }\n        this.data.push(Float64Array.from(arrayData[i]));\n      }\n\n      this.rows = nRows;\n      this.columns = nColumns;\n    } else {\n      throw new TypeError(\n        'First argument must be a positive number or an array',\n      );\n    }\n  }\n\n  set(rowIndex, columnIndex, value) {\n    this.data[rowIndex][columnIndex] = value;\n    return this;\n  }\n\n  get(rowIndex, columnIndex) {\n    return this.data[rowIndex][columnIndex];\n  }\n\n  removeRow(index) {\n    checkRowIndex(this, index);\n    this.data.splice(index, 1);\n    this.rows -= 1;\n    return this;\n  }\n\n  addRow(index, array) {\n    if (array === undefined) {\n      array = index;\n      index = this.rows;\n    }\n    checkRowIndex(this, index, true);\n    array = Float64Array.from(checkRowVector(this, array));\n    this.data.splice(index, 0, array);\n    this.rows += 1;\n    return this;\n  }\n\n  removeColumn(index) {\n    checkColumnIndex(this, index);\n    for (let i = 0; i < this.rows; i++) {\n      const newRow = new Float64Array(this.columns - 1);\n      for (let j = 0; j < index; j++) {\n        newRow[j] = this.data[i][j];\n      }\n      for (let j = index + 1; j < this.columns; j++) {\n        newRow[j - 1] = this.data[i][j];\n      }\n      this.data[i] = newRow;\n    }\n    this.columns -= 1;\n    return this;\n  }\n\n  addColumn(index, array) {\n    if (typeof array === 'undefined') {\n      array = index;\n      index = this.columns;\n    }\n    checkColumnIndex(this, index, true);\n    array = checkColumnVector(this, array);\n    for (let i = 0; i < this.rows; i++) {\n      const newRow = new Float64Array(this.columns + 1);\n      let j = 0;\n      for (; j < index; j++) {\n        newRow[j] = this.data[i][j];\n      }\n      newRow[j++] = array[i];\n      for (; j < this.columns + 1; j++) {\n        newRow[j] = this.data[i][j - 1];\n      }\n      this.data[i] = newRow;\n    }\n    this.columns += 1;\n    return this;\n  }\n}\n\ninstallMathOperations(AbstractMatrix, Matrix);\n\n/**\n * @typedef {0 | 1 | number | boolean} Mask\n */\n\nclass SymmetricMatrix extends AbstractMatrix {\n  /** @type {Matrix} */\n  #matrix;\n\n  get size() {\n    return this.#matrix.size;\n  }\n\n  get rows() {\n    return this.#matrix.rows;\n  }\n\n  get columns() {\n    return this.#matrix.columns;\n  }\n\n  get diagonalSize() {\n    return this.rows;\n  }\n\n  /**\n   * not the same as matrix.isSymmetric()\n   * Here is to check if it's instanceof SymmetricMatrix without bundling issues\n   *\n   * @param value\n   * @returns {boolean}\n   */\n  static isSymmetricMatrix(value) {\n    return Matrix.isMatrix(value) && value.klassType === 'SymmetricMatrix';\n  }\n\n  /**\n   * @param diagonalSize\n   * @return {SymmetricMatrix}\n   */\n  static zeros(diagonalSize) {\n    return new this(diagonalSize);\n  }\n\n  /**\n   * @param diagonalSize\n   * @return {SymmetricMatrix}\n   */\n  static ones(diagonalSize) {\n    return new this(diagonalSize).fill(1);\n  }\n\n  /**\n   * @param {number | AbstractMatrix | ArrayLike<ArrayLike<number>>} diagonalSize\n   * @return {this}\n   */\n  constructor(diagonalSize) {\n    super();\n\n    if (Matrix.isMatrix(diagonalSize)) {\n      if (!diagonalSize.isSymmetric()) {\n        throw new TypeError('not symmetric data');\n      }\n\n      this.#matrix = Matrix.copy(\n        diagonalSize,\n        new Matrix(diagonalSize.rows, diagonalSize.rows),\n      );\n    } else if (Number.isInteger(diagonalSize) && diagonalSize >= 0) {\n      this.#matrix = new Matrix(diagonalSize, diagonalSize);\n    } else {\n      this.#matrix = new Matrix(diagonalSize);\n\n      if (!this.isSymmetric()) {\n        throw new TypeError('not symmetric data');\n      }\n    }\n  }\n\n  clone() {\n    const matrix = new SymmetricMatrix(this.diagonalSize);\n\n    for (const [row, col, value] of this.upperRightEntries()) {\n      matrix.set(row, col, value);\n    }\n\n    return matrix;\n  }\n\n  toMatrix() {\n    return new Matrix(this);\n  }\n\n  get(rowIndex, columnIndex) {\n    return this.#matrix.get(rowIndex, columnIndex);\n  }\n  set(rowIndex, columnIndex, value) {\n    // symmetric set\n    this.#matrix.set(rowIndex, columnIndex, value);\n    this.#matrix.set(columnIndex, rowIndex, value);\n\n    return this;\n  }\n\n  removeCross(index) {\n    // symmetric remove side\n    this.#matrix.removeRow(index);\n    this.#matrix.removeColumn(index);\n\n    return this;\n  }\n\n  addCross(index, array) {\n    if (array === undefined) {\n      array = index;\n      index = this.diagonalSize;\n    }\n\n    const row = array.slice();\n    row.splice(index, 1);\n\n    this.#matrix.addRow(index, row);\n    this.#matrix.addColumn(index, array);\n\n    return this;\n  }\n\n  /**\n   * @param {Mask[]} mask\n   */\n  applyMask(mask) {\n    if (mask.length !== this.diagonalSize) {\n      throw new RangeError('Mask size do not match with matrix size');\n    }\n\n    // prepare sides to remove from matrix from mask\n    /** @type {number[]} */\n    const sidesToRemove = [];\n    for (const [index, passthroughs] of mask.entries()) {\n      if (passthroughs) continue;\n      sidesToRemove.push(index);\n    }\n    // to remove from highest to lowest for no mutation shifting\n    sidesToRemove.reverse();\n\n    // remove sides\n    for (const sideIndex of sidesToRemove) {\n      this.removeCross(sideIndex);\n    }\n\n    return this;\n  }\n\n  /**\n   * Compact format upper-right corner of matrix\n   * iterate from left to right, from top to bottom.\n   *\n   * ```\n   *   A B C D\n   * A 1 2 3 4\n   * B 2 5 6 7\n   * C 3 6 8 9\n   * D 4 7 9 10\n   * ```\n   *\n   * will return compact 1D array `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`\n   *\n   * length is S(i=0, n=sideSize) => 10 for a 4 sideSized matrix\n   *\n   * @returns {number[]}\n   */\n  toCompact() {\n    const { diagonalSize } = this;\n\n    /** @type {number[]} */\n    const compact = new Array((diagonalSize * (diagonalSize + 1)) / 2);\n    for (let col = 0, row = 0, index = 0; index < compact.length; index++) {\n      compact[index] = this.get(row, col);\n\n      if (++col >= diagonalSize) col = ++row;\n    }\n\n    return compact;\n  }\n\n  /**\n   * @param {number[]} compact\n   * @return {SymmetricMatrix}\n   */\n  static fromCompact(compact) {\n    const compactSize = compact.length;\n    // compactSize = (sideSize * (sideSize + 1)) / 2\n    // https://mathsolver.microsoft.com/fr/solve-problem/y%20%3D%20%20x%20%60cdot%20%20%20%60frac%7B%20%20%60left(%20x%2B1%20%20%60right)%20%20%20%20%7D%7B%202%20%20%7D\n    // sideSize = (Sqrt(8 × compactSize + 1) - 1) / 2\n    const diagonalSize = (Math.sqrt(8 * compactSize + 1) - 1) / 2;\n\n    if (!Number.isInteger(diagonalSize)) {\n      throw new TypeError(\n        `This array is not a compact representation of a Symmetric Matrix, ${JSON.stringify(\n          compact,\n        )}`,\n      );\n    }\n\n    const matrix = new SymmetricMatrix(diagonalSize);\n    for (let col = 0, row = 0, index = 0; index < compactSize; index++) {\n      matrix.set(col, row, compact[index]);\n      if (++col >= diagonalSize) col = ++row;\n    }\n\n    return matrix;\n  }\n\n  /**\n   * half iterator upper-right-corner from left to right, from top to bottom\n   * yield [row, column, value]\n   *\n   * @returns {Generator<[number, number, number], void, void>}\n   */\n  *upperRightEntries() {\n    for (let row = 0, col = 0; row < this.diagonalSize; void 0) {\n      const value = this.get(row, col);\n\n      yield [row, col, value];\n\n      // at the end of row, move cursor to next row at diagonal position\n      if (++col >= this.diagonalSize) col = ++row;\n    }\n  }\n\n  /**\n   * half iterator upper-right-corner from left to right, from top to bottom\n   * yield value\n   *\n   * @returns {Generator<[number, number, number], void, void>}\n   */\n  *upperRightValues() {\n    for (let row = 0, col = 0; row < this.diagonalSize; void 0) {\n      const value = this.get(row, col);\n\n      yield value;\n\n      // at the end of row, move cursor to next row at diagonal position\n      if (++col >= this.diagonalSize) col = ++row;\n    }\n  }\n}\nSymmetricMatrix.prototype.klassType = 'SymmetricMatrix';\n\nclass DistanceMatrix extends SymmetricMatrix {\n  /**\n   * not the same as matrix.isSymmetric()\n   * Here is to check if it's instanceof SymmetricMatrix without bundling issues\n   *\n   * @param value\n   * @returns {boolean}\n   */\n  static isDistanceMatrix(value) {\n    return (\n      SymmetricMatrix.isSymmetricMatrix(value) &&\n      value.klassSubType === 'DistanceMatrix'\n    );\n  }\n\n  constructor(sideSize) {\n    super(sideSize);\n\n    if (!this.isDistance()) {\n      throw new TypeError('Provided arguments do no produce a distance matrix');\n    }\n  }\n\n  set(rowIndex, columnIndex, value) {\n    // distance matrix diagonal is 0\n    if (rowIndex === columnIndex) value = 0;\n\n    return super.set(rowIndex, columnIndex, value);\n  }\n\n  addCross(index, array) {\n    if (array === undefined) {\n      array = index;\n      index = this.diagonalSize;\n    }\n\n    // ensure distance\n    array = array.slice();\n    array[index] = 0;\n\n    return super.addCross(index, array);\n  }\n\n  toSymmetricMatrix() {\n    return new SymmetricMatrix(this);\n  }\n\n  clone() {\n    const matrix = new DistanceMatrix(this.diagonalSize);\n\n    for (const [row, col, value] of this.upperRightEntries()) {\n      if (row === col) continue;\n      matrix.set(row, col, value);\n    }\n\n    return matrix;\n  }\n\n  /**\n   * Compact format upper-right corner of matrix\n   * no diagonal (only zeros)\n   * iterable from left to right, from top to bottom.\n   *\n   * ```\n   *   A B C D\n   * A 0 1 2 3\n   * B 1 0 4 5\n   * C 2 4 0 6\n   * D 3 5 6 0\n   * ```\n   *\n   * will return compact 1D array `[1, 2, 3, 4, 5, 6]`\n   *\n   * length is S(i=0, n=sideSize-1) => 6 for a 4 side sized matrix\n   *\n   * @returns {number[]}\n   */\n  toCompact() {\n    const { diagonalSize } = this;\n    const compactLength = ((diagonalSize - 1) * diagonalSize) / 2;\n\n    /** @type {number[]} */\n    const compact = new Array(compactLength);\n    for (let col = 1, row = 0, index = 0; index < compact.length; index++) {\n      compact[index] = this.get(row, col);\n\n      if (++col >= diagonalSize) col = ++row + 1;\n    }\n\n    return compact;\n  }\n\n  /**\n   * @param {number[]} compact\n   */\n  static fromCompact(compact) {\n    const compactSize = compact.length;\n\n    if (compactSize === 0) {\n      return new this(0);\n    }\n\n    // compactSize in Natural integer range ]0;∞]\n    // compactSize = (sideSize * (sideSize - 1)) / 2\n    // sideSize = (Sqrt(8 × compactSize + 1) + 1) / 2\n    const diagonalSize = (Math.sqrt(8 * compactSize + 1) + 1) / 2;\n\n    if (!Number.isInteger(diagonalSize)) {\n      throw new TypeError(\n        `This array is not a compact representation of a DistanceMatrix, ${JSON.stringify(\n          compact,\n        )}`,\n      );\n    }\n\n    const matrix = new this(diagonalSize);\n    for (let col = 1, row = 0, index = 0; index < compactSize; index++) {\n      matrix.set(col, row, compact[index]);\n      if (++col >= diagonalSize) col = ++row + 1;\n    }\n\n    return matrix;\n  }\n}\nDistanceMatrix.prototype.klassSubType = 'DistanceMatrix';\n\nclass BaseView extends AbstractMatrix {\n  constructor(matrix, rows, columns) {\n    super();\n    this.matrix = matrix;\n    this.rows = rows;\n    this.columns = columns;\n  }\n}\n\nclass MatrixColumnView extends BaseView {\n  constructor(matrix, column) {\n    checkColumnIndex(matrix, column);\n    super(matrix, matrix.rows, 1);\n    this.column = column;\n  }\n\n  set(rowIndex, columnIndex, value) {\n    this.matrix.set(rowIndex, this.column, value);\n    return this;\n  }\n\n  get(rowIndex) {\n    return this.matrix.get(rowIndex, this.column);\n  }\n}\n\nclass MatrixColumnSelectionView extends BaseView {\n  constructor(matrix, columnIndices) {\n    checkColumnIndices(matrix, columnIndices);\n    super(matrix, matrix.rows, columnIndices.length);\n    this.columnIndices = columnIndices;\n  }\n\n  set(rowIndex, columnIndex, value) {\n    this.matrix.set(rowIndex, this.columnIndices[columnIndex], value);\n    return this;\n  }\n\n  get(rowIndex, columnIndex) {\n    return this.matrix.get(rowIndex, this.columnIndices[columnIndex]);\n  }\n}\n\nclass MatrixFlipColumnView extends BaseView {\n  constructor(matrix) {\n    super(matrix, matrix.rows, matrix.columns);\n  }\n\n  set(rowIndex, columnIndex, value) {\n    this.matrix.set(rowIndex, this.columns - columnIndex - 1, value);\n    return this;\n  }\n\n  get(rowIndex, columnIndex) {\n    return this.matrix.get(rowIndex, this.columns - columnIndex - 1);\n  }\n}\n\nclass MatrixFlipRowView extends BaseView {\n  constructor(matrix) {\n    super(matrix, matrix.rows, matrix.columns);\n  }\n\n  set(rowIndex, columnIndex, value) {\n    this.matrix.set(this.rows - rowIndex - 1, columnIndex, value);\n    return this;\n  }\n\n  get(rowIndex, columnIndex) {\n    return this.matrix.get(this.rows - rowIndex - 1, columnIndex);\n  }\n}\n\nclass MatrixRowView extends BaseView {\n  constructor(matrix, row) {\n    checkRowIndex(matrix, row);\n    super(matrix, 1, matrix.columns);\n    this.row = row;\n  }\n\n  set(rowIndex, columnIndex, value) {\n    this.matrix.set(this.row, columnIndex, value);\n    return this;\n  }\n\n  get(rowIndex, columnIndex) {\n    return this.matrix.get(this.row, columnIndex);\n  }\n}\n\nclass MatrixRowSelectionView extends BaseView {\n  constructor(matrix, rowIndices) {\n    checkRowIndices(matrix, rowIndices);\n    super(matrix, rowIndices.length, matrix.columns);\n    this.rowIndices = rowIndices;\n  }\n\n  set(rowIndex, columnIndex, value) {\n    this.matrix.set(this.rowIndices[rowIndex], columnIndex, value);\n    return this;\n  }\n\n  get(rowIndex, columnIndex) {\n    return this.matrix.get(this.rowIndices[rowIndex], columnIndex);\n  }\n}\n\nclass MatrixSelectionView extends BaseView {\n  constructor(matrix, rowIndices, columnIndices) {\n    checkRowIndices(matrix, rowIndices);\n    checkColumnIndices(matrix, columnIndices);\n    super(matrix, rowIndices.length, columnIndices.length);\n    this.rowIndices = rowIndices;\n    this.columnIndices = columnIndices;\n  }\n\n  set(rowIndex, columnIndex, value) {\n    this.matrix.set(\n      this.rowIndices[rowIndex],\n      this.columnIndices[columnIndex],\n      value,\n    );\n    return this;\n  }\n\n  get(rowIndex, columnIndex) {\n    return this.matrix.get(\n      this.rowIndices[rowIndex],\n      this.columnIndices[columnIndex],\n    );\n  }\n}\n\nclass MatrixSubView extends BaseView {\n  constructor(matrix, startRow, endRow, startColumn, endColumn) {\n    checkRange(matrix, startRow, endRow, startColumn, endColumn);\n    super(matrix, endRow - startRow + 1, endColumn - startColumn + 1);\n    this.startRow = startRow;\n    this.startColumn = startColumn;\n  }\n\n  set(rowIndex, columnIndex, value) {\n    this.matrix.set(\n      this.startRow + rowIndex,\n      this.startColumn + columnIndex,\n      value,\n    );\n    return this;\n  }\n\n  get(rowIndex, columnIndex) {\n    return this.matrix.get(\n      this.startRow + rowIndex,\n      this.startColumn + columnIndex,\n    );\n  }\n}\n\nclass MatrixTransposeView extends BaseView {\n  constructor(matrix) {\n    super(matrix, matrix.columns, matrix.rows);\n  }\n\n  set(rowIndex, columnIndex, value) {\n    this.matrix.set(columnIndex, rowIndex, value);\n    return this;\n  }\n\n  get(rowIndex, columnIndex) {\n    return this.matrix.get(columnIndex, rowIndex);\n  }\n}\n\nclass WrapperMatrix1D extends AbstractMatrix {\n  constructor(data, options = {}) {\n    const { rows = 1 } = options;\n\n    if (data.length % rows !== 0) {\n      throw new Error('the data length is not divisible by the number of rows');\n    }\n    super();\n    this.rows = rows;\n    this.columns = data.length / rows;\n    this.data = data;\n  }\n\n  set(rowIndex, columnIndex, value) {\n    let index = this._calculateIndex(rowIndex, columnIndex);\n    this.data[index] = value;\n    return this;\n  }\n\n  get(rowIndex, columnIndex) {\n    let index = this._calculateIndex(rowIndex, columnIndex);\n    return this.data[index];\n  }\n\n  _calculateIndex(row, column) {\n    return row * this.columns + column;\n  }\n}\n\nclass WrapperMatrix2D extends AbstractMatrix {\n  constructor(data) {\n    super();\n    this.data = data;\n    this.rows = data.length;\n    this.columns = data[0].length;\n  }\n\n  set(rowIndex, columnIndex, value) {\n    this.data[rowIndex][columnIndex] = value;\n    return this;\n  }\n\n  get(rowIndex, columnIndex) {\n    return this.data[rowIndex][columnIndex];\n  }\n}\n\nfunction wrap(array, options) {\n  if (isAnyArray(array)) {\n    if (array[0] && isAnyArray(array[0])) {\n      return new WrapperMatrix2D(array);\n    } else {\n      return new WrapperMatrix1D(array, options);\n    }\n  } else {\n    throw new Error('the argument is not an array');\n  }\n}\n\nclass LuDecomposition {\n  constructor(matrix) {\n    matrix = WrapperMatrix2D.checkMatrix(matrix);\n\n    let lu = matrix.clone();\n    let rows = lu.rows;\n    let columns = lu.columns;\n    let pivotVector = new Float64Array(rows);\n    let pivotSign = 1;\n    let i, j, k, p, s, t, v;\n    let LUcolj, kmax;\n\n    for (i = 0; i < rows; i++) {\n      pivotVector[i] = i;\n    }\n\n    LUcolj = new Float64Array(rows);\n\n    for (j = 0; j < columns; j++) {\n      for (i = 0; i < rows; i++) {\n        LUcolj[i] = lu.get(i, j);\n      }\n\n      for (i = 0; i < rows; i++) {\n        kmax = Math.min(i, j);\n        s = 0;\n        for (k = 0; k < kmax; k++) {\n          s += lu.get(i, k) * LUcolj[k];\n        }\n        LUcolj[i] -= s;\n        lu.set(i, j, LUcolj[i]);\n      }\n\n      p = j;\n      for (i = j + 1; i < rows; i++) {\n        if (Math.abs(LUcolj[i]) > Math.abs(LUcolj[p])) {\n          p = i;\n        }\n      }\n\n      if (p !== j) {\n        for (k = 0; k < columns; k++) {\n          t = lu.get(p, k);\n          lu.set(p, k, lu.get(j, k));\n          lu.set(j, k, t);\n        }\n\n        v = pivotVector[p];\n        pivotVector[p] = pivotVector[j];\n        pivotVector[j] = v;\n\n        pivotSign = -pivotSign;\n      }\n\n      if (j < rows && lu.get(j, j) !== 0) {\n        for (i = j + 1; i < rows; i++) {\n          lu.set(i, j, lu.get(i, j) / lu.get(j, j));\n        }\n      }\n    }\n\n    this.LU = lu;\n    this.pivotVector = pivotVector;\n    this.pivotSign = pivotSign;\n  }\n\n  isSingular() {\n    let data = this.LU;\n    let col = data.columns;\n    for (let j = 0; j < col; j++) {\n      if (data.get(j, j) === 0) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  solve(value) {\n    value = Matrix.checkMatrix(value);\n\n    let lu = this.LU;\n    let rows = lu.rows;\n\n    if (rows !== value.rows) {\n      throw new Error('Invalid matrix dimensions');\n    }\n    if (this.isSingular()) {\n      throw new Error('LU matrix is singular');\n    }\n\n    let count = value.columns;\n    let X = value.subMatrixRow(this.pivotVector, 0, count - 1);\n    let columns = lu.columns;\n    let i, j, k;\n\n    for (k = 0; k < columns; k++) {\n      for (i = k + 1; i < columns; i++) {\n        for (j = 0; j < count; j++) {\n          X.set(i, j, X.get(i, j) - X.get(k, j) * lu.get(i, k));\n        }\n      }\n    }\n    for (k = columns - 1; k >= 0; k--) {\n      for (j = 0; j < count; j++) {\n        X.set(k, j, X.get(k, j) / lu.get(k, k));\n      }\n      for (i = 0; i < k; i++) {\n        for (j = 0; j < count; j++) {\n          X.set(i, j, X.get(i, j) - X.get(k, j) * lu.get(i, k));\n        }\n      }\n    }\n    return X;\n  }\n\n  get determinant() {\n    let data = this.LU;\n    if (!data.isSquare()) {\n      throw new Error('Matrix must be square');\n    }\n    let determinant = this.pivotSign;\n    let col = data.columns;\n    for (let j = 0; j < col; j++) {\n      determinant *= data.get(j, j);\n    }\n    return determinant;\n  }\n\n  get lowerTriangularMatrix() {\n    let data = this.LU;\n    let rows = data.rows;\n    let columns = data.columns;\n    let X = new Matrix(rows, columns);\n    for (let i = 0; i < rows; i++) {\n      for (let j = 0; j < columns; j++) {\n        if (i > j) {\n          X.set(i, j, data.get(i, j));\n        } else if (i === j) {\n          X.set(i, j, 1);\n        } else {\n          X.set(i, j, 0);\n        }\n      }\n    }\n    return X;\n  }\n\n  get upperTriangularMatrix() {\n    let data = this.LU;\n    let rows = data.rows;\n    let columns = data.columns;\n    let X = new Matrix(rows, columns);\n    for (let i = 0; i < rows; i++) {\n      for (let j = 0; j < columns; j++) {\n        if (i <= j) {\n          X.set(i, j, data.get(i, j));\n        } else {\n          X.set(i, j, 0);\n        }\n      }\n    }\n    return X;\n  }\n\n  get pivotPermutationVector() {\n    return Array.from(this.pivotVector);\n  }\n}\n\nfunction hypotenuse(a, b) {\n  let r = 0;\n  if (Math.abs(a) > Math.abs(b)) {\n    r = b / a;\n    return Math.abs(a) * Math.sqrt(1 + r * r);\n  }\n  if (b !== 0) {\n    r = a / b;\n    return Math.abs(b) * Math.sqrt(1 + r * r);\n  }\n  return 0;\n}\n\nclass QrDecomposition {\n  constructor(value) {\n    value = WrapperMatrix2D.checkMatrix(value);\n\n    let qr = value.clone();\n    let m = value.rows;\n    let n = value.columns;\n    let rdiag = new Float64Array(n);\n    let i, j, k, s;\n\n    for (k = 0; k < n; k++) {\n      let nrm = 0;\n      for (i = k; i < m; i++) {\n        nrm = hypotenuse(nrm, qr.get(i, k));\n      }\n      if (nrm !== 0) {\n        if (qr.get(k, k) < 0) {\n          nrm = -nrm;\n        }\n        for (i = k; i < m; i++) {\n          qr.set(i, k, qr.get(i, k) / nrm);\n        }\n        qr.set(k, k, qr.get(k, k) + 1);\n        for (j = k + 1; j < n; j++) {\n          s = 0;\n          for (i = k; i < m; i++) {\n            s += qr.get(i, k) * qr.get(i, j);\n          }\n          s = -s / qr.get(k, k);\n          for (i = k; i < m; i++) {\n            qr.set(i, j, qr.get(i, j) + s * qr.get(i, k));\n          }\n        }\n      }\n      rdiag[k] = -nrm;\n    }\n\n    this.QR = qr;\n    this.Rdiag = rdiag;\n  }\n\n  solve(value) {\n    value = Matrix.checkMatrix(value);\n\n    let qr = this.QR;\n    let m = qr.rows;\n\n    if (value.rows !== m) {\n      throw new Error('Matrix row dimensions must agree');\n    }\n    if (!this.isFullRank()) {\n      throw new Error('Matrix is rank deficient');\n    }\n\n    let count = value.columns;\n    let X = value.clone();\n    let n = qr.columns;\n    let i, j, k, s;\n\n    for (k = 0; k < n; k++) {\n      for (j = 0; j < count; j++) {\n        s = 0;\n        for (i = k; i < m; i++) {\n          s += qr.get(i, k) * X.get(i, j);\n        }\n        s = -s / qr.get(k, k);\n        for (i = k; i < m; i++) {\n          X.set(i, j, X.get(i, j) + s * qr.get(i, k));\n        }\n      }\n    }\n    for (k = n - 1; k >= 0; k--) {\n      for (j = 0; j < count; j++) {\n        X.set(k, j, X.get(k, j) / this.Rdiag[k]);\n      }\n      for (i = 0; i < k; i++) {\n        for (j = 0; j < count; j++) {\n          X.set(i, j, X.get(i, j) - X.get(k, j) * qr.get(i, k));\n        }\n      }\n    }\n\n    return X.subMatrix(0, n - 1, 0, count - 1);\n  }\n\n  isFullRank() {\n    let columns = this.QR.columns;\n    for (let i = 0; i < columns; i++) {\n      if (this.Rdiag[i] === 0) {\n        return false;\n      }\n    }\n    return true;\n  }\n\n  get upperTriangularMatrix() {\n    let qr = this.QR;\n    let n = qr.columns;\n    let X = new Matrix(n, n);\n    let i, j;\n    for (i = 0; i < n; i++) {\n      for (j = 0; j < n; j++) {\n        if (i < j) {\n          X.set(i, j, qr.get(i, j));\n        } else if (i === j) {\n          X.set(i, j, this.Rdiag[i]);\n        } else {\n          X.set(i, j, 0);\n        }\n      }\n    }\n    return X;\n  }\n\n  get orthogonalMatrix() {\n    let qr = this.QR;\n    let rows = qr.rows;\n    let columns = qr.columns;\n    let X = new Matrix(rows, columns);\n    let i, j, k, s;\n\n    for (k = columns - 1; k >= 0; k--) {\n      for (i = 0; i < rows; i++) {\n        X.set(i, k, 0);\n      }\n      X.set(k, k, 1);\n      for (j = k; j < columns; j++) {\n        if (qr.get(k, k) !== 0) {\n          s = 0;\n          for (i = k; i < rows; i++) {\n            s += qr.get(i, k) * X.get(i, j);\n          }\n\n          s = -s / qr.get(k, k);\n\n          for (i = k; i < rows; i++) {\n            X.set(i, j, X.get(i, j) + s * qr.get(i, k));\n          }\n        }\n      }\n    }\n    return X;\n  }\n}\n\nclass SingularValueDecomposition {\n  constructor(value, options = {}) {\n    value = WrapperMatrix2D.checkMatrix(value);\n\n    if (value.isEmpty()) {\n      throw new Error('Matrix must be non-empty');\n    }\n\n    let m = value.rows;\n    let n = value.columns;\n\n    const {\n      computeLeftSingularVectors = true,\n      computeRightSingularVectors = true,\n      autoTranspose = false,\n    } = options;\n\n    let wantu = Boolean(computeLeftSingularVectors);\n    let wantv = Boolean(computeRightSingularVectors);\n\n    let swapped = false;\n    let a;\n    if (m < n) {\n      if (!autoTranspose) {\n        a = value.clone();\n        // eslint-disable-next-line no-console\n        console.warn(\n          'Computing SVD on a matrix with more columns than rows. Consider enabling autoTranspose',\n        );\n      } else {\n        a = value.transpose();\n        m = a.rows;\n        n = a.columns;\n        swapped = true;\n        let aux = wantu;\n        wantu = wantv;\n        wantv = aux;\n      }\n    } else {\n      a = value.clone();\n    }\n\n    let nu = Math.min(m, n);\n    let ni = Math.min(m + 1, n);\n    let s = new Float64Array(ni);\n    let U = new Matrix(m, nu);\n    let V = new Matrix(n, n);\n\n    let e = new Float64Array(n);\n    let work = new Float64Array(m);\n\n    let si = new Float64Array(ni);\n    for (let i = 0; i < ni; i++) si[i] = i;\n\n    let nct = Math.min(m - 1, n);\n    let nrt = Math.max(0, Math.min(n - 2, m));\n    let mrc = Math.max(nct, nrt);\n\n    for (let k = 0; k < mrc; k++) {\n      if (k < nct) {\n        s[k] = 0;\n        for (let i = k; i < m; i++) {\n          s[k] = hypotenuse(s[k], a.get(i, k));\n        }\n        if (s[k] !== 0) {\n          if (a.get(k, k) < 0) {\n            s[k] = -s[k];\n          }\n          for (let i = k; i < m; i++) {\n            a.set(i, k, a.get(i, k) / s[k]);\n          }\n          a.set(k, k, a.get(k, k) + 1);\n        }\n        s[k] = -s[k];\n      }\n\n      for (let j = k + 1; j < n; j++) {\n        if (k < nct && s[k] !== 0) {\n          let t = 0;\n          for (let i = k; i < m; i++) {\n            t += a.get(i, k) * a.get(i, j);\n          }\n          t = -t / a.get(k, k);\n          for (let i = k; i < m; i++) {\n            a.set(i, j, a.get(i, j) + t * a.get(i, k));\n          }\n        }\n        e[j] = a.get(k, j);\n      }\n\n      if (wantu && k < nct) {\n        for (let i = k; i < m; i++) {\n          U.set(i, k, a.get(i, k));\n        }\n      }\n\n      if (k < nrt) {\n        e[k] = 0;\n        for (let i = k + 1; i < n; i++) {\n          e[k] = hypotenuse(e[k], e[i]);\n        }\n        if (e[k] !== 0) {\n          if (e[k + 1] < 0) {\n            e[k] = 0 - e[k];\n          }\n          for (let i = k + 1; i < n; i++) {\n            e[i] /= e[k];\n          }\n          e[k + 1] += 1;\n        }\n        e[k] = -e[k];\n        if (k + 1 < m && e[k] !== 0) {\n          for (let i = k + 1; i < m; i++) {\n            work[i] = 0;\n          }\n          for (let i = k + 1; i < m; i++) {\n            for (let j = k + 1; j < n; j++) {\n              work[i] += e[j] * a.get(i, j);\n            }\n          }\n          for (let j = k + 1; j < n; j++) {\n            let t = -e[j] / e[k + 1];\n            for (let i = k + 1; i < m; i++) {\n              a.set(i, j, a.get(i, j) + t * work[i]);\n            }\n          }\n        }\n        if (wantv) {\n          for (let i = k + 1; i < n; i++) {\n            V.set(i, k, e[i]);\n          }\n        }\n      }\n    }\n\n    let p = Math.min(n, m + 1);\n    if (nct < n) {\n      s[nct] = a.get(nct, nct);\n    }\n    if (m < p) {\n      s[p - 1] = 0;\n    }\n    if (nrt + 1 < p) {\n      e[nrt] = a.get(nrt, p - 1);\n    }\n    e[p - 1] = 0;\n\n    if (wantu) {\n      for (let j = nct; j < nu; j++) {\n        for (let i = 0; i < m; i++) {\n          U.set(i, j, 0);\n        }\n        U.set(j, j, 1);\n      }\n      for (let k = nct - 1; k >= 0; k--) {\n        if (s[k] !== 0) {\n          for (let j = k + 1; j < nu; j++) {\n            let t = 0;\n            for (let i = k; i < m; i++) {\n              t += U.get(i, k) * U.get(i, j);\n            }\n            t = -t / U.get(k, k);\n            for (let i = k; i < m; i++) {\n              U.set(i, j, U.get(i, j) + t * U.get(i, k));\n            }\n          }\n          for (let i = k; i < m; i++) {\n            U.set(i, k, -U.get(i, k));\n          }\n          U.set(k, k, 1 + U.get(k, k));\n          for (let i = 0; i < k - 1; i++) {\n            U.set(i, k, 0);\n          }\n        } else {\n          for (let i = 0; i < m; i++) {\n            U.set(i, k, 0);\n          }\n          U.set(k, k, 1);\n        }\n      }\n    }\n\n    if (wantv) {\n      for (let k = n - 1; k >= 0; k--) {\n        if (k < nrt && e[k] !== 0) {\n          for (let j = k + 1; j < n; j++) {\n            let t = 0;\n            for (let i = k + 1; i < n; i++) {\n              t += V.get(i, k) * V.get(i, j);\n            }\n            t = -t / V.get(k + 1, k);\n            for (let i = k + 1; i < n; i++) {\n              V.set(i, j, V.get(i, j) + t * V.get(i, k));\n            }\n          }\n        }\n        for (let i = 0; i < n; i++) {\n          V.set(i, k, 0);\n        }\n        V.set(k, k, 1);\n      }\n    }\n\n    let pp = p - 1;\n    let eps = Number.EPSILON;\n    while (p > 0) {\n      let k, kase;\n      for (k = p - 2; k >= -1; k--) {\n        if (k === -1) {\n          break;\n        }\n        const alpha =\n          Number.MIN_VALUE + eps * Math.abs(s[k] + Math.abs(s[k + 1]));\n        if (Math.abs(e[k]) <= alpha || Number.isNaN(e[k])) {\n          e[k] = 0;\n          break;\n        }\n      }\n      if (k === p - 2) {\n        kase = 4;\n      } else {\n        let ks;\n        for (ks = p - 1; ks >= k; ks--) {\n          if (ks === k) {\n            break;\n          }\n          let t =\n            (ks !== p ? Math.abs(e[ks]) : 0) +\n            (ks !== k + 1 ? Math.abs(e[ks - 1]) : 0);\n          if (Math.abs(s[ks]) <= eps * t) {\n            s[ks] = 0;\n            break;\n          }\n        }\n        if (ks === k) {\n          kase = 3;\n        } else if (ks === p - 1) {\n          kase = 1;\n        } else {\n          kase = 2;\n          k = ks;\n        }\n      }\n\n      k++;\n\n      switch (kase) {\n        case 1: {\n          let f = e[p - 2];\n          e[p - 2] = 0;\n          for (let j = p - 2; j >= k; j--) {\n            let t = hypotenuse(s[j], f);\n            let cs = s[j] / t;\n            let sn = f / t;\n            s[j] = t;\n            if (j !== k) {\n              f = -sn * e[j - 1];\n              e[j - 1] = cs * e[j - 1];\n            }\n            if (wantv) {\n              for (let i = 0; i < n; i++) {\n                t = cs * V.get(i, j) + sn * V.get(i, p - 1);\n                V.set(i, p - 1, -sn * V.get(i, j) + cs * V.get(i, p - 1));\n                V.set(i, j, t);\n              }\n            }\n          }\n          break;\n        }\n        case 2: {\n          let f = e[k - 1];\n          e[k - 1] = 0;\n          for (let j = k; j < p; j++) {\n            let t = hypotenuse(s[j], f);\n            let cs = s[j] / t;\n            let sn = f / t;\n            s[j] = t;\n            f = -sn * e[j];\n            e[j] = cs * e[j];\n            if (wantu) {\n              for (let i = 0; i < m; i++) {\n                t = cs * U.get(i, j) + sn * U.get(i, k - 1);\n                U.set(i, k - 1, -sn * U.get(i, j) + cs * U.get(i, k - 1));\n                U.set(i, j, t);\n              }\n            }\n          }\n          break;\n        }\n        case 3: {\n          const scale = Math.max(\n            Math.abs(s[p - 1]),\n            Math.abs(s[p - 2]),\n            Math.abs(e[p - 2]),\n            Math.abs(s[k]),\n            Math.abs(e[k]),\n          );\n          const sp = s[p - 1] / scale;\n          const spm1 = s[p - 2] / scale;\n          const epm1 = e[p - 2] / scale;\n          const sk = s[k] / scale;\n          const ek = e[k] / scale;\n          const b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2;\n          const c = sp * epm1 * (sp * epm1);\n          let shift = 0;\n          if (b !== 0 || c !== 0) {\n            if (b < 0) {\n              shift = 0 - Math.sqrt(b * b + c);\n            } else {\n              shift = Math.sqrt(b * b + c);\n            }\n            shift = c / (b + shift);\n          }\n          let f = (sk + sp) * (sk - sp) + shift;\n          let g = sk * ek;\n          for (let j = k; j < p - 1; j++) {\n            let t = hypotenuse(f, g);\n            if (t === 0) t = Number.MIN_VALUE;\n            let cs = f / t;\n            let sn = g / t;\n            if (j !== k) {\n              e[j - 1] = t;\n            }\n            f = cs * s[j] + sn * e[j];\n            e[j] = cs * e[j] - sn * s[j];\n            g = sn * s[j + 1];\n            s[j + 1] = cs * s[j + 1];\n            if (wantv) {\n              for (let i = 0; i < n; i++) {\n                t = cs * V.get(i, j) + sn * V.get(i, j + 1);\n                V.set(i, j + 1, -sn * V.get(i, j) + cs * V.get(i, j + 1));\n                V.set(i, j, t);\n              }\n            }\n            t = hypotenuse(f, g);\n            if (t === 0) t = Number.MIN_VALUE;\n            cs = f / t;\n            sn = g / t;\n            s[j] = t;\n            f = cs * e[j] + sn * s[j + 1];\n            s[j + 1] = -sn * e[j] + cs * s[j + 1];\n            g = sn * e[j + 1];\n            e[j + 1] = cs * e[j + 1];\n            if (wantu && j < m - 1) {\n              for (let i = 0; i < m; i++) {\n                t = cs * U.get(i, j) + sn * U.get(i, j + 1);\n                U.set(i, j + 1, -sn * U.get(i, j) + cs * U.get(i, j + 1));\n                U.set(i, j, t);\n              }\n            }\n          }\n          e[p - 2] = f;\n          break;\n        }\n        case 4: {\n          if (s[k] <= 0) {\n            s[k] = s[k] < 0 ? -s[k] : 0;\n            if (wantv) {\n              for (let i = 0; i <= pp; i++) {\n                V.set(i, k, -V.get(i, k));\n              }\n            }\n          }\n          while (k < pp) {\n            if (s[k] >= s[k + 1]) {\n              break;\n            }\n            let t = s[k];\n            s[k] = s[k + 1];\n            s[k + 1] = t;\n            if (wantv && k < n - 1) {\n              for (let i = 0; i < n; i++) {\n                t = V.get(i, k + 1);\n                V.set(i, k + 1, V.get(i, k));\n                V.set(i, k, t);\n              }\n            }\n            if (wantu && k < m - 1) {\n              for (let i = 0; i < m; i++) {\n                t = U.get(i, k + 1);\n                U.set(i, k + 1, U.get(i, k));\n                U.set(i, k, t);\n              }\n            }\n            k++;\n          }\n          p--;\n          break;\n        }\n        // no default\n      }\n    }\n\n    if (swapped) {\n      let tmp = V;\n      V = U;\n      U = tmp;\n    }\n\n    this.m = m;\n    this.n = n;\n    this.s = s;\n    this.U = U;\n    this.V = V;\n  }\n\n  solve(value) {\n    let Y = value;\n    let e = this.threshold;\n    let scols = this.s.length;\n    let Ls = Matrix.zeros(scols, scols);\n\n    for (let i = 0; i < scols; i++) {\n      if (Math.abs(this.s[i]) <= e) {\n        Ls.set(i, i, 0);\n      } else {\n        Ls.set(i, i, 1 / this.s[i]);\n      }\n    }\n\n    let U = this.U;\n    let V = this.rightSingularVectors;\n\n    let VL = V.mmul(Ls);\n    let vrows = V.rows;\n    let urows = U.rows;\n    let VLU = Matrix.zeros(vrows, urows);\n\n    for (let i = 0; i < vrows; i++) {\n      for (let j = 0; j < urows; j++) {\n        let sum = 0;\n        for (let k = 0; k < scols; k++) {\n          sum += VL.get(i, k) * U.get(j, k);\n        }\n        VLU.set(i, j, sum);\n      }\n    }\n\n    return VLU.mmul(Y);\n  }\n\n  solveForDiagonal(value) {\n    return this.solve(Matrix.diag(value));\n  }\n\n  inverse() {\n    let V = this.V;\n    let e = this.threshold;\n    let vrows = V.rows;\n    let vcols = V.columns;\n    let X = new Matrix(vrows, this.s.length);\n\n    for (let i = 0; i < vrows; i++) {\n      for (let j = 0; j < vcols; j++) {\n        if (Math.abs(this.s[j]) > e) {\n          X.set(i, j, V.get(i, j) / this.s[j]);\n        }\n      }\n    }\n\n    let U = this.U;\n\n    let urows = U.rows;\n    let ucols = U.columns;\n    let Y = new Matrix(vrows, urows);\n\n    for (let i = 0; i < vrows; i++) {\n      for (let j = 0; j < urows; j++) {\n        let sum = 0;\n        for (let k = 0; k < ucols; k++) {\n          sum += X.get(i, k) * U.get(j, k);\n        }\n        Y.set(i, j, sum);\n      }\n    }\n\n    return Y;\n  }\n\n  get condition() {\n    return this.s[0] / this.s[Math.min(this.m, this.n) - 1];\n  }\n\n  get norm2() {\n    return this.s[0];\n  }\n\n  get rank() {\n    let tol = Math.max(this.m, this.n) * this.s[0] * Number.EPSILON;\n    let r = 0;\n    let s = this.s;\n    for (let i = 0, ii = s.length; i < ii; i++) {\n      if (s[i] > tol) {\n        r++;\n      }\n    }\n    return r;\n  }\n\n  get diagonal() {\n    return Array.from(this.s);\n  }\n\n  get threshold() {\n    return (Number.EPSILON / 2) * Math.max(this.m, this.n) * this.s[0];\n  }\n\n  get leftSingularVectors() {\n    return this.U;\n  }\n\n  get rightSingularVectors() {\n    return this.V;\n  }\n\n  get diagonalMatrix() {\n    return Matrix.diag(this.s);\n  }\n}\n\nfunction inverse(matrix, useSVD = false) {\n  matrix = WrapperMatrix2D.checkMatrix(matrix);\n  if (useSVD) {\n    return new SingularValueDecomposition(matrix).inverse();\n  } else {\n    return solve(matrix, Matrix.eye(matrix.rows));\n  }\n}\n\nfunction solve(leftHandSide, rightHandSide, useSVD = false) {\n  leftHandSide = WrapperMatrix2D.checkMatrix(leftHandSide);\n  rightHandSide = WrapperMatrix2D.checkMatrix(rightHandSide);\n  if (useSVD) {\n    return new SingularValueDecomposition(leftHandSide).solve(rightHandSide);\n  } else {\n    return leftHandSide.isSquare()\n      ? new LuDecomposition(leftHandSide).solve(rightHandSide)\n      : new QrDecomposition(leftHandSide).solve(rightHandSide);\n  }\n}\n\nfunction determinant(matrix) {\n  matrix = Matrix.checkMatrix(matrix);\n  if (matrix.isSquare()) {\n    if (matrix.columns === 0) {\n      return 1;\n    }\n\n    let a, b, c, d;\n    if (matrix.columns === 2) {\n      // 2 x 2 matrix\n      a = matrix.get(0, 0);\n      b = matrix.get(0, 1);\n      c = matrix.get(1, 0);\n      d = matrix.get(1, 1);\n\n      return a * d - b * c;\n    } else if (matrix.columns === 3) {\n      // 3 x 3 matrix\n      let subMatrix0, subMatrix1, subMatrix2;\n      subMatrix0 = new MatrixSelectionView(matrix, [1, 2], [1, 2]);\n      subMatrix1 = new MatrixSelectionView(matrix, [1, 2], [0, 2]);\n      subMatrix2 = new MatrixSelectionView(matrix, [1, 2], [0, 1]);\n      a = matrix.get(0, 0);\n      b = matrix.get(0, 1);\n      c = matrix.get(0, 2);\n\n      return (\n        a * determinant(subMatrix0) -\n        b * determinant(subMatrix1) +\n        c * determinant(subMatrix2)\n      );\n    } else {\n      // general purpose determinant using the LU decomposition\n      return new LuDecomposition(matrix).determinant;\n    }\n  } else {\n    throw Error('determinant can only be calculated for a square matrix');\n  }\n}\n\nfunction xrange(n, exception) {\n  let range = [];\n  for (let i = 0; i < n; i++) {\n    if (i !== exception) {\n      range.push(i);\n    }\n  }\n  return range;\n}\n\nfunction dependenciesOneRow(\n  error,\n  matrix,\n  index,\n  thresholdValue = 10e-10,\n  thresholdError = 10e-10,\n) {\n  if (error > thresholdError) {\n    return new Array(matrix.rows + 1).fill(0);\n  } else {\n    let returnArray = matrix.addRow(index, [0]);\n    for (let i = 0; i < returnArray.rows; i++) {\n      if (Math.abs(returnArray.get(i, 0)) < thresholdValue) {\n        returnArray.set(i, 0, 0);\n      }\n    }\n    return returnArray.to1DArray();\n  }\n}\n\nfunction linearDependencies(matrix, options = {}) {\n  const { thresholdValue = 10e-10, thresholdError = 10e-10 } = options;\n  matrix = Matrix.checkMatrix(matrix);\n\n  let n = matrix.rows;\n  let results = new Matrix(n, n);\n\n  for (let i = 0; i < n; i++) {\n    let b = Matrix.columnVector(matrix.getRow(i));\n    let Abis = matrix.subMatrixRow(xrange(n, i)).transpose();\n    let svd = new SingularValueDecomposition(Abis);\n    let x = svd.solve(b);\n    let error = Matrix.sub(b, Abis.mmul(x)).abs().max();\n    results.setRow(\n      i,\n      dependenciesOneRow(error, x, i, thresholdValue, thresholdError),\n    );\n  }\n  return results;\n}\n\nfunction pseudoInverse(matrix, threshold = Number.EPSILON) {\n  matrix = Matrix.checkMatrix(matrix);\n  if (matrix.isEmpty()) {\n    // with a zero dimension, the pseudo-inverse is the transpose, since all 0xn and nx0 matrices are singular\n    // (0xn)*(nx0)*(0xn) = 0xn\n    // (nx0)*(0xn)*(nx0) = nx0\n    return matrix.transpose();\n  }\n  let svdSolution = new SingularValueDecomposition(matrix, { autoTranspose: true });\n\n  let U = svdSolution.leftSingularVectors;\n  let V = svdSolution.rightSingularVectors;\n  let s = svdSolution.diagonal;\n\n  for (let i = 0; i < s.length; i++) {\n    if (Math.abs(s[i]) > threshold) {\n      s[i] = 1.0 / s[i];\n    } else {\n      s[i] = 0.0;\n    }\n  }\n\n  return V.mmul(Matrix.diag(s).mmul(U.transpose()));\n}\n\nfunction covariance(xMatrix, yMatrix = xMatrix, options = {}) {\n  xMatrix = new Matrix(xMatrix);\n  let yIsSame = false;\n  if (\n    typeof yMatrix === 'object' &&\n    !Matrix.isMatrix(yMatrix) &&\n    !isAnyArray(yMatrix)\n  ) {\n    options = yMatrix;\n    yMatrix = xMatrix;\n    yIsSame = true;\n  } else {\n    yMatrix = new Matrix(yMatrix);\n  }\n  if (xMatrix.rows !== yMatrix.rows) {\n    throw new TypeError('Both matrices must have the same number of rows');\n  }\n  const { center = true } = options;\n  if (center) {\n    xMatrix = xMatrix.center('column');\n    if (!yIsSame) {\n      yMatrix = yMatrix.center('column');\n    }\n  }\n  const cov = xMatrix.transpose().mmul(yMatrix);\n  for (let i = 0; i < cov.rows; i++) {\n    for (let j = 0; j < cov.columns; j++) {\n      cov.set(i, j, cov.get(i, j) * (1 / (xMatrix.rows - 1)));\n    }\n  }\n  return cov;\n}\n\nfunction correlation(xMatrix, yMatrix = xMatrix, options = {}) {\n  xMatrix = new Matrix(xMatrix);\n  let yIsSame = false;\n  if (\n    typeof yMatrix === 'object' &&\n    !Matrix.isMatrix(yMatrix) &&\n    !isAnyArray(yMatrix)\n  ) {\n    options = yMatrix;\n    yMatrix = xMatrix;\n    yIsSame = true;\n  } else {\n    yMatrix = new Matrix(yMatrix);\n  }\n  if (xMatrix.rows !== yMatrix.rows) {\n    throw new TypeError('Both matrices must have the same number of rows');\n  }\n\n  const { center = true, scale = true } = options;\n  if (center) {\n    xMatrix.center('column');\n    if (!yIsSame) {\n      yMatrix.center('column');\n    }\n  }\n  if (scale) {\n    xMatrix.scale('column');\n    if (!yIsSame) {\n      yMatrix.scale('column');\n    }\n  }\n\n  const sdx = xMatrix.standardDeviation('column', { unbiased: true });\n  const sdy = yIsSame\n    ? sdx\n    : yMatrix.standardDeviation('column', { unbiased: true });\n\n  const corr = xMatrix.transpose().mmul(yMatrix);\n  for (let i = 0; i < corr.rows; i++) {\n    for (let j = 0; j < corr.columns; j++) {\n      corr.set(\n        i,\n        j,\n        corr.get(i, j) * (1 / (sdx[i] * sdy[j])) * (1 / (xMatrix.rows - 1)),\n      );\n    }\n  }\n  return corr;\n}\n\nclass EigenvalueDecomposition {\n  constructor(matrix, options = {}) {\n    const { assumeSymmetric = false } = options;\n\n    matrix = WrapperMatrix2D.checkMatrix(matrix);\n    if (!matrix.isSquare()) {\n      throw new Error('Matrix is not a square matrix');\n    }\n\n    if (matrix.isEmpty()) {\n      throw new Error('Matrix must be non-empty');\n    }\n\n    let n = matrix.columns;\n    let V = new Matrix(n, n);\n    let d = new Float64Array(n);\n    let e = new Float64Array(n);\n    let value = matrix;\n    let i, j;\n\n    let isSymmetric = false;\n    if (assumeSymmetric) {\n      isSymmetric = true;\n    } else {\n      isSymmetric = matrix.isSymmetric();\n    }\n\n    if (isSymmetric) {\n      for (i = 0; i < n; i++) {\n        for (j = 0; j < n; j++) {\n          V.set(i, j, value.get(i, j));\n        }\n      }\n      tred2(n, e, d, V);\n      tql2(n, e, d, V);\n    } else {\n      let H = new Matrix(n, n);\n      let ort = new Float64Array(n);\n      for (j = 0; j < n; j++) {\n        for (i = 0; i < n; i++) {\n          H.set(i, j, value.get(i, j));\n        }\n      }\n      orthes(n, H, ort, V);\n      hqr2(n, e, d, V, H);\n    }\n\n    this.n = n;\n    this.e = e;\n    this.d = d;\n    this.V = V;\n  }\n\n  get realEigenvalues() {\n    return Array.from(this.d);\n  }\n\n  get imaginaryEigenvalues() {\n    return Array.from(this.e);\n  }\n\n  get eigenvectorMatrix() {\n    return this.V;\n  }\n\n  get diagonalMatrix() {\n    let n = this.n;\n    let e = this.e;\n    let d = this.d;\n    let X = new Matrix(n, n);\n    let i, j;\n    for (i = 0; i < n; i++) {\n      for (j = 0; j < n; j++) {\n        X.set(i, j, 0);\n      }\n      X.set(i, i, d[i]);\n      if (e[i] > 0) {\n        X.set(i, i + 1, e[i]);\n      } else if (e[i] < 0) {\n        X.set(i, i - 1, e[i]);\n      }\n    }\n    return X;\n  }\n}\n\nfunction tred2(n, e, d, V) {\n  let f, g, h, i, j, k, hh, scale;\n\n  for (j = 0; j < n; j++) {\n    d[j] = V.get(n - 1, j);\n  }\n\n  for (i = n - 1; i > 0; i--) {\n    scale = 0;\n    h = 0;\n    for (k = 0; k < i; k++) {\n      scale = scale + Math.abs(d[k]);\n    }\n\n    if (scale === 0) {\n      e[i] = d[i - 1];\n      for (j = 0; j < i; j++) {\n        d[j] = V.get(i - 1, j);\n        V.set(i, j, 0);\n        V.set(j, i, 0);\n      }\n    } else {\n      for (k = 0; k < i; k++) {\n        d[k] /= scale;\n        h += d[k] * d[k];\n      }\n\n      f = d[i - 1];\n      g = Math.sqrt(h);\n      if (f > 0) {\n        g = -g;\n      }\n\n      e[i] = scale * g;\n      h = h - f * g;\n      d[i - 1] = f - g;\n      for (j = 0; j < i; j++) {\n        e[j] = 0;\n      }\n\n      for (j = 0; j < i; j++) {\n        f = d[j];\n        V.set(j, i, f);\n        g = e[j] + V.get(j, j) * f;\n        for (k = j + 1; k <= i - 1; k++) {\n          g += V.get(k, j) * d[k];\n          e[k] += V.get(k, j) * f;\n        }\n        e[j] = g;\n      }\n\n      f = 0;\n      for (j = 0; j < i; j++) {\n        e[j] /= h;\n        f += e[j] * d[j];\n      }\n\n      hh = f / (h + h);\n      for (j = 0; j < i; j++) {\n        e[j] -= hh * d[j];\n      }\n\n      for (j = 0; j < i; j++) {\n        f = d[j];\n        g = e[j];\n        for (k = j; k <= i - 1; k++) {\n          V.set(k, j, V.get(k, j) - (f * e[k] + g * d[k]));\n        }\n        d[j] = V.get(i - 1, j);\n        V.set(i, j, 0);\n      }\n    }\n    d[i] = h;\n  }\n\n  for (i = 0; i < n - 1; i++) {\n    V.set(n - 1, i, V.get(i, i));\n    V.set(i, i, 1);\n    h = d[i + 1];\n    if (h !== 0) {\n      for (k = 0; k <= i; k++) {\n        d[k] = V.get(k, i + 1) / h;\n      }\n\n      for (j = 0; j <= i; j++) {\n        g = 0;\n        for (k = 0; k <= i; k++) {\n          g += V.get(k, i + 1) * V.get(k, j);\n        }\n        for (k = 0; k <= i; k++) {\n          V.set(k, j, V.get(k, j) - g * d[k]);\n        }\n      }\n    }\n\n    for (k = 0; k <= i; k++) {\n      V.set(k, i + 1, 0);\n    }\n  }\n\n  for (j = 0; j < n; j++) {\n    d[j] = V.get(n - 1, j);\n    V.set(n - 1, j, 0);\n  }\n\n  V.set(n - 1, n - 1, 1);\n  e[0] = 0;\n}\n\nfunction tql2(n, e, d, V) {\n  let g, h, i, j, k, l, m, p, r, dl1, c, c2, c3, el1, s, s2;\n\n  for (i = 1; i < n; i++) {\n    e[i - 1] = e[i];\n  }\n\n  e[n - 1] = 0;\n\n  let f = 0;\n  let tst1 = 0;\n  let eps = Number.EPSILON;\n\n  for (l = 0; l < n; l++) {\n    tst1 = Math.max(tst1, Math.abs(d[l]) + Math.abs(e[l]));\n    m = l;\n    while (m < n) {\n      if (Math.abs(e[m]) <= eps * tst1) {\n        break;\n      }\n      m++;\n    }\n\n    if (m > l) {\n      do {\n\n        g = d[l];\n        p = (d[l + 1] - g) / (2 * e[l]);\n        r = hypotenuse(p, 1);\n        if (p < 0) {\n          r = -r;\n        }\n\n        d[l] = e[l] / (p + r);\n        d[l + 1] = e[l] * (p + r);\n        dl1 = d[l + 1];\n        h = g - d[l];\n        for (i = l + 2; i < n; i++) {\n          d[i] -= h;\n        }\n\n        f = f + h;\n\n        p = d[m];\n        c = 1;\n        c2 = c;\n        c3 = c;\n        el1 = e[l + 1];\n        s = 0;\n        s2 = 0;\n        for (i = m - 1; i >= l; i--) {\n          c3 = c2;\n          c2 = c;\n          s2 = s;\n          g = c * e[i];\n          h = c * p;\n          r = hypotenuse(p, e[i]);\n          e[i + 1] = s * r;\n          s = e[i] / r;\n          c = p / r;\n          p = c * d[i] - s * g;\n          d[i + 1] = h + s * (c * g + s * d[i]);\n\n          for (k = 0; k < n; k++) {\n            h = V.get(k, i + 1);\n            V.set(k, i + 1, s * V.get(k, i) + c * h);\n            V.set(k, i, c * V.get(k, i) - s * h);\n          }\n        }\n\n        p = (-s * s2 * c3 * el1 * e[l]) / dl1;\n        e[l] = s * p;\n        d[l] = c * p;\n      } while (Math.abs(e[l]) > eps * tst1);\n    }\n    d[l] = d[l] + f;\n    e[l] = 0;\n  }\n\n  for (i = 0; i < n - 1; i++) {\n    k = i;\n    p = d[i];\n    for (j = i + 1; j < n; j++) {\n      if (d[j] < p) {\n        k = j;\n        p = d[j];\n      }\n    }\n\n    if (k !== i) {\n      d[k] = d[i];\n      d[i] = p;\n      for (j = 0; j < n; j++) {\n        p = V.get(j, i);\n        V.set(j, i, V.get(j, k));\n        V.set(j, k, p);\n      }\n    }\n  }\n}\n\nfunction orthes(n, H, ort, V) {\n  let low = 0;\n  let high = n - 1;\n  let f, g, h, i, j, m;\n  let scale;\n\n  for (m = low + 1; m <= high - 1; m++) {\n    scale = 0;\n    for (i = m; i <= high; i++) {\n      scale = scale + Math.abs(H.get(i, m - 1));\n    }\n\n    if (scale !== 0) {\n      h = 0;\n      for (i = high; i >= m; i--) {\n        ort[i] = H.get(i, m - 1) / scale;\n        h += ort[i] * ort[i];\n      }\n\n      g = Math.sqrt(h);\n      if (ort[m] > 0) {\n        g = -g;\n      }\n\n      h = h - ort[m] * g;\n      ort[m] = ort[m] - g;\n\n      for (j = m; j < n; j++) {\n        f = 0;\n        for (i = high; i >= m; i--) {\n          f += ort[i] * H.get(i, j);\n        }\n\n        f = f / h;\n        for (i = m; i <= high; i++) {\n          H.set(i, j, H.get(i, j) - f * ort[i]);\n        }\n      }\n\n      for (i = 0; i <= high; i++) {\n        f = 0;\n        for (j = high; j >= m; j--) {\n          f += ort[j] * H.get(i, j);\n        }\n\n        f = f / h;\n        for (j = m; j <= high; j++) {\n          H.set(i, j, H.get(i, j) - f * ort[j]);\n        }\n      }\n\n      ort[m] = scale * ort[m];\n      H.set(m, m - 1, scale * g);\n    }\n  }\n\n  for (i = 0; i < n; i++) {\n    for (j = 0; j < n; j++) {\n      V.set(i, j, i === j ? 1 : 0);\n    }\n  }\n\n  for (m = high - 1; m >= low + 1; m--) {\n    if (H.get(m, m - 1) !== 0) {\n      for (i = m + 1; i <= high; i++) {\n        ort[i] = H.get(i, m - 1);\n      }\n\n      for (j = m; j <= high; j++) {\n        g = 0;\n        for (i = m; i <= high; i++) {\n          g += ort[i] * V.get(i, j);\n        }\n\n        g = g / ort[m] / H.get(m, m - 1);\n        for (i = m; i <= high; i++) {\n          V.set(i, j, V.get(i, j) + g * ort[i]);\n        }\n      }\n    }\n  }\n}\n\nfunction hqr2(nn, e, d, V, H) {\n  let n = nn - 1;\n  let low = 0;\n  let high = nn - 1;\n  let eps = Number.EPSILON;\n  let exshift = 0;\n  let norm = 0;\n  let p = 0;\n  let q = 0;\n  let r = 0;\n  let s = 0;\n  let z = 0;\n  let iter = 0;\n  let i, j, k, l, m, t, w, x, y;\n  let ra, sa, vr, vi;\n  let notlast, cdivres;\n\n  for (i = 0; i < nn; i++) {\n    if (i < low || i > high) {\n      d[i] = H.get(i, i);\n      e[i] = 0;\n    }\n\n    for (j = Math.max(i - 1, 0); j < nn; j++) {\n      norm = norm + Math.abs(H.get(i, j));\n    }\n  }\n\n  while (n >= low) {\n    l = n;\n    while (l > low) {\n      s = Math.abs(H.get(l - 1, l - 1)) + Math.abs(H.get(l, l));\n      if (s === 0) {\n        s = norm;\n      }\n      if (Math.abs(H.get(l, l - 1)) < eps * s) {\n        break;\n      }\n      l--;\n    }\n\n    if (l === n) {\n      H.set(n, n, H.get(n, n) + exshift);\n      d[n] = H.get(n, n);\n      e[n] = 0;\n      n--;\n      iter = 0;\n    } else if (l === n - 1) {\n      w = H.get(n, n - 1) * H.get(n - 1, n);\n      p = (H.get(n - 1, n - 1) - H.get(n, n)) / 2;\n      q = p * p + w;\n      z = Math.sqrt(Math.abs(q));\n      H.set(n, n, H.get(n, n) + exshift);\n      H.set(n - 1, n - 1, H.get(n - 1, n - 1) + exshift);\n      x = H.get(n, n);\n\n      if (q >= 0) {\n        z = p >= 0 ? p + z : p - z;\n        d[n - 1] = x + z;\n        d[n] = d[n - 1];\n        if (z !== 0) {\n          d[n] = x - w / z;\n        }\n        e[n - 1] = 0;\n        e[n] = 0;\n        x = H.get(n, n - 1);\n        s = Math.abs(x) + Math.abs(z);\n        p = x / s;\n        q = z / s;\n        r = Math.sqrt(p * p + q * q);\n        p = p / r;\n        q = q / r;\n\n        for (j = n - 1; j < nn; j++) {\n          z = H.get(n - 1, j);\n          H.set(n - 1, j, q * z + p * H.get(n, j));\n          H.set(n, j, q * H.get(n, j) - p * z);\n        }\n\n        for (i = 0; i <= n; i++) {\n          z = H.get(i, n - 1);\n          H.set(i, n - 1, q * z + p * H.get(i, n));\n          H.set(i, n, q * H.get(i, n) - p * z);\n        }\n\n        for (i = low; i <= high; i++) {\n          z = V.get(i, n - 1);\n          V.set(i, n - 1, q * z + p * V.get(i, n));\n          V.set(i, n, q * V.get(i, n) - p * z);\n        }\n      } else {\n        d[n - 1] = x + p;\n        d[n] = x + p;\n        e[n - 1] = z;\n        e[n] = -z;\n      }\n\n      n = n - 2;\n      iter = 0;\n    } else {\n      x = H.get(n, n);\n      y = 0;\n      w = 0;\n      if (l < n) {\n        y = H.get(n - 1, n - 1);\n        w = H.get(n, n - 1) * H.get(n - 1, n);\n      }\n\n      if (iter === 10) {\n        exshift += x;\n        for (i = low; i <= n; i++) {\n          H.set(i, i, H.get(i, i) - x);\n        }\n        s = Math.abs(H.get(n, n - 1)) + Math.abs(H.get(n - 1, n - 2));\n        // eslint-disable-next-line no-multi-assign\n        x = y = 0.75 * s;\n        w = -0.4375 * s * s;\n      }\n\n      if (iter === 30) {\n        s = (y - x) / 2;\n        s = s * s + w;\n        if (s > 0) {\n          s = Math.sqrt(s);\n          if (y < x) {\n            s = -s;\n          }\n          s = x - w / ((y - x) / 2 + s);\n          for (i = low; i <= n; i++) {\n            H.set(i, i, H.get(i, i) - s);\n          }\n          exshift += s;\n          // eslint-disable-next-line no-multi-assign\n          x = y = w = 0.964;\n        }\n      }\n\n      iter = iter + 1;\n\n      m = n - 2;\n      while (m >= l) {\n        z = H.get(m, m);\n        r = x - z;\n        s = y - z;\n        p = (r * s - w) / H.get(m + 1, m) + H.get(m, m + 1);\n        q = H.get(m + 1, m + 1) - z - r - s;\n        r = H.get(m + 2, m + 1);\n        s = Math.abs(p) + Math.abs(q) + Math.abs(r);\n        p = p / s;\n        q = q / s;\n        r = r / s;\n        if (m === l) {\n          break;\n        }\n        if (\n          Math.abs(H.get(m, m - 1)) * (Math.abs(q) + Math.abs(r)) <\n          eps *\n            (Math.abs(p) *\n              (Math.abs(H.get(m - 1, m - 1)) +\n                Math.abs(z) +\n                Math.abs(H.get(m + 1, m + 1))))\n        ) {\n          break;\n        }\n        m--;\n      }\n\n      for (i = m + 2; i <= n; i++) {\n        H.set(i, i - 2, 0);\n        if (i > m + 2) {\n          H.set(i, i - 3, 0);\n        }\n      }\n\n      for (k = m; k <= n - 1; k++) {\n        notlast = k !== n - 1;\n        if (k !== m) {\n          p = H.get(k, k - 1);\n          q = H.get(k + 1, k - 1);\n          r = notlast ? H.get(k + 2, k - 1) : 0;\n          x = Math.abs(p) + Math.abs(q) + Math.abs(r);\n          if (x !== 0) {\n            p = p / x;\n            q = q / x;\n            r = r / x;\n          }\n        }\n\n        if (x === 0) {\n          break;\n        }\n\n        s = Math.sqrt(p * p + q * q + r * r);\n        if (p < 0) {\n          s = -s;\n        }\n\n        if (s !== 0) {\n          if (k !== m) {\n            H.set(k, k - 1, -s * x);\n          } else if (l !== m) {\n            H.set(k, k - 1, -H.get(k, k - 1));\n          }\n\n          p = p + s;\n          x = p / s;\n          y = q / s;\n          z = r / s;\n          q = q / p;\n          r = r / p;\n\n          for (j = k; j < nn; j++) {\n            p = H.get(k, j) + q * H.get(k + 1, j);\n            if (notlast) {\n              p = p + r * H.get(k + 2, j);\n              H.set(k + 2, j, H.get(k + 2, j) - p * z);\n            }\n\n            H.set(k, j, H.get(k, j) - p * x);\n            H.set(k + 1, j, H.get(k + 1, j) - p * y);\n          }\n\n          for (i = 0; i <= Math.min(n, k + 3); i++) {\n            p = x * H.get(i, k) + y * H.get(i, k + 1);\n            if (notlast) {\n              p = p + z * H.get(i, k + 2);\n              H.set(i, k + 2, H.get(i, k + 2) - p * r);\n            }\n\n            H.set(i, k, H.get(i, k) - p);\n            H.set(i, k + 1, H.get(i, k + 1) - p * q);\n          }\n\n          for (i = low; i <= high; i++) {\n            p = x * V.get(i, k) + y * V.get(i, k + 1);\n            if (notlast) {\n              p = p + z * V.get(i, k + 2);\n              V.set(i, k + 2, V.get(i, k + 2) - p * r);\n            }\n\n            V.set(i, k, V.get(i, k) - p);\n            V.set(i, k + 1, V.get(i, k + 1) - p * q);\n          }\n        }\n      }\n    }\n  }\n\n  if (norm === 0) {\n    return;\n  }\n\n  for (n = nn - 1; n >= 0; n--) {\n    p = d[n];\n    q = e[n];\n\n    if (q === 0) {\n      l = n;\n      H.set(n, n, 1);\n      for (i = n - 1; i >= 0; i--) {\n        w = H.get(i, i) - p;\n        r = 0;\n        for (j = l; j <= n; j++) {\n          r = r + H.get(i, j) * H.get(j, n);\n        }\n\n        if (e[i] < 0) {\n          z = w;\n          s = r;\n        } else {\n          l = i;\n          if (e[i] === 0) {\n            H.set(i, n, w !== 0 ? -r / w : -r / (eps * norm));\n          } else {\n            x = H.get(i, i + 1);\n            y = H.get(i + 1, i);\n            q = (d[i] - p) * (d[i] - p) + e[i] * e[i];\n            t = (x * s - z * r) / q;\n            H.set(i, n, t);\n            H.set(\n              i + 1,\n              n,\n              Math.abs(x) > Math.abs(z) ? (-r - w * t) / x : (-s - y * t) / z,\n            );\n          }\n\n          t = Math.abs(H.get(i, n));\n          if (eps * t * t > 1) {\n            for (j = i; j <= n; j++) {\n              H.set(j, n, H.get(j, n) / t);\n            }\n          }\n        }\n      }\n    } else if (q < 0) {\n      l = n - 1;\n\n      if (Math.abs(H.get(n, n - 1)) > Math.abs(H.get(n - 1, n))) {\n        H.set(n - 1, n - 1, q / H.get(n, n - 1));\n        H.set(n - 1, n, -(H.get(n, n) - p) / H.get(n, n - 1));\n      } else {\n        cdivres = cdiv(0, -H.get(n - 1, n), H.get(n - 1, n - 1) - p, q);\n        H.set(n - 1, n - 1, cdivres[0]);\n        H.set(n - 1, n, cdivres[1]);\n      }\n\n      H.set(n, n - 1, 0);\n      H.set(n, n, 1);\n      for (i = n - 2; i >= 0; i--) {\n        ra = 0;\n        sa = 0;\n        for (j = l; j <= n; j++) {\n          ra = ra + H.get(i, j) * H.get(j, n - 1);\n          sa = sa + H.get(i, j) * H.get(j, n);\n        }\n\n        w = H.get(i, i) - p;\n\n        if (e[i] < 0) {\n          z = w;\n          r = ra;\n          s = sa;\n        } else {\n          l = i;\n          if (e[i] === 0) {\n            cdivres = cdiv(-ra, -sa, w, q);\n            H.set(i, n - 1, cdivres[0]);\n            H.set(i, n, cdivres[1]);\n          } else {\n            x = H.get(i, i + 1);\n            y = H.get(i + 1, i);\n            vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;\n            vi = (d[i] - p) * 2 * q;\n            if (vr === 0 && vi === 0) {\n              vr =\n                eps *\n                norm *\n                (Math.abs(w) +\n                  Math.abs(q) +\n                  Math.abs(x) +\n                  Math.abs(y) +\n                  Math.abs(z));\n            }\n            cdivres = cdiv(\n              x * r - z * ra + q * sa,\n              x * s - z * sa - q * ra,\n              vr,\n              vi,\n            );\n            H.set(i, n - 1, cdivres[0]);\n            H.set(i, n, cdivres[1]);\n            if (Math.abs(x) > Math.abs(z) + Math.abs(q)) {\n              H.set(\n                i + 1,\n                n - 1,\n                (-ra - w * H.get(i, n - 1) + q * H.get(i, n)) / x,\n              );\n              H.set(\n                i + 1,\n                n,\n                (-sa - w * H.get(i, n) - q * H.get(i, n - 1)) / x,\n              );\n            } else {\n              cdivres = cdiv(\n                -r - y * H.get(i, n - 1),\n                -s - y * H.get(i, n),\n                z,\n                q,\n              );\n              H.set(i + 1, n - 1, cdivres[0]);\n              H.set(i + 1, n, cdivres[1]);\n            }\n          }\n\n          t = Math.max(Math.abs(H.get(i, n - 1)), Math.abs(H.get(i, n)));\n          if (eps * t * t > 1) {\n            for (j = i; j <= n; j++) {\n              H.set(j, n - 1, H.get(j, n - 1) / t);\n              H.set(j, n, H.get(j, n) / t);\n            }\n          }\n        }\n      }\n    }\n  }\n\n  for (i = 0; i < nn; i++) {\n    if (i < low || i > high) {\n      for (j = i; j < nn; j++) {\n        V.set(i, j, H.get(i, j));\n      }\n    }\n  }\n\n  for (j = nn - 1; j >= low; j--) {\n    for (i = low; i <= high; i++) {\n      z = 0;\n      for (k = low; k <= Math.min(j, high); k++) {\n        z = z + V.get(i, k) * H.get(k, j);\n      }\n      V.set(i, j, z);\n    }\n  }\n}\n\nfunction cdiv(xr, xi, yr, yi) {\n  let r, d;\n  if (Math.abs(yr) > Math.abs(yi)) {\n    r = yi / yr;\n    d = yr + r * yi;\n    return [(xr + r * xi) / d, (xi - r * xr) / d];\n  } else {\n    r = yr / yi;\n    d = yi + r * yr;\n    return [(r * xr + xi) / d, (r * xi - xr) / d];\n  }\n}\n\nclass CholeskyDecomposition {\n  constructor(value) {\n    value = WrapperMatrix2D.checkMatrix(value);\n    if (!value.isSymmetric()) {\n      throw new Error('Matrix is not symmetric');\n    }\n\n    let a = value;\n    let dimension = a.rows;\n    let l = new Matrix(dimension, dimension);\n    let positiveDefinite = true;\n    let i, j, k;\n\n    for (j = 0; j < dimension; j++) {\n      let d = 0;\n      for (k = 0; k < j; k++) {\n        let s = 0;\n        for (i = 0; i < k; i++) {\n          s += l.get(k, i) * l.get(j, i);\n        }\n        s = (a.get(j, k) - s) / l.get(k, k);\n        l.set(j, k, s);\n        d = d + s * s;\n      }\n\n      d = a.get(j, j) - d;\n\n      positiveDefinite &&= d > 0;\n      l.set(j, j, Math.sqrt(Math.max(d, 0)));\n      for (k = j + 1; k < dimension; k++) {\n        l.set(j, k, 0);\n      }\n    }\n\n    this.L = l;\n    this.positiveDefinite = positiveDefinite;\n  }\n\n  isPositiveDefinite() {\n    return this.positiveDefinite;\n  }\n\n  solve(value) {\n    value = WrapperMatrix2D.checkMatrix(value);\n\n    let l = this.L;\n    let dimension = l.rows;\n\n    if (value.rows !== dimension) {\n      throw new Error('Matrix dimensions do not match');\n    }\n    if (this.isPositiveDefinite() === false) {\n      throw new Error('Matrix is not positive definite');\n    }\n\n    let count = value.columns;\n    let B = value.clone();\n    let i, j, k;\n\n    for (k = 0; k < dimension; k++) {\n      for (j = 0; j < count; j++) {\n        for (i = 0; i < k; i++) {\n          B.set(k, j, B.get(k, j) - B.get(i, j) * l.get(k, i));\n        }\n        B.set(k, j, B.get(k, j) / l.get(k, k));\n      }\n    }\n\n    for (k = dimension - 1; k >= 0; k--) {\n      for (j = 0; j < count; j++) {\n        for (i = k + 1; i < dimension; i++) {\n          B.set(k, j, B.get(k, j) - B.get(i, j) * l.get(i, k));\n        }\n        B.set(k, j, B.get(k, j) / l.get(k, k));\n      }\n    }\n\n    return B;\n  }\n\n  get lowerTriangularMatrix() {\n    return this.L;\n  }\n}\n\nclass nipals {\n  constructor(X, options = {}) {\n    X = WrapperMatrix2D.checkMatrix(X);\n    let { Y } = options;\n    const {\n      scaleScores = false,\n      maxIterations = 1000,\n      terminationCriteria = 1e-10,\n    } = options;\n\n    let u;\n    if (Y) {\n      if (isAnyArray(Y) && typeof Y[0] === 'number') {\n        Y = Matrix.columnVector(Y);\n      } else {\n        Y = WrapperMatrix2D.checkMatrix(Y);\n      }\n      if (Y.rows !== X.rows) {\n        throw new Error('Y should have the same number of rows as X');\n      }\n      u = Y.getColumnVector(0);\n    } else {\n      u = X.getColumnVector(0);\n    }\n\n    let diff = 1;\n    let t, q, w, tOld;\n\n    for (\n      let counter = 0;\n      counter < maxIterations && diff > terminationCriteria;\n      counter++\n    ) {\n      w = X.transpose().mmul(u).div(u.transpose().mmul(u).get(0, 0));\n      w = w.div(w.norm());\n\n      t = X.mmul(w).div(w.transpose().mmul(w).get(0, 0));\n\n      if (counter > 0) {\n        diff = t.clone().sub(tOld).pow(2).sum();\n      }\n      tOld = t.clone();\n\n      if (Y) {\n        q = Y.transpose().mmul(t).div(t.transpose().mmul(t).get(0, 0));\n        q = q.div(q.norm());\n\n        u = Y.mmul(q).div(q.transpose().mmul(q).get(0, 0));\n      } else {\n        u = t;\n      }\n    }\n\n    if (Y) {\n      let p = X.transpose().mmul(t).div(t.transpose().mmul(t).get(0, 0));\n      p = p.div(p.norm());\n      let xResidual = X.clone().sub(t.clone().mmul(p.transpose()));\n      let residual = u.transpose().mmul(t).div(t.transpose().mmul(t).get(0, 0));\n      let yResidual = Y.clone().sub(\n        t.clone().mulS(residual.get(0, 0)).mmul(q.transpose()),\n      );\n\n      this.t = t;\n      this.p = p.transpose();\n      this.w = w.transpose();\n      this.q = q;\n      this.u = u;\n      this.s = t.transpose().mmul(t);\n      this.xResidual = xResidual;\n      this.yResidual = yResidual;\n      this.betas = residual;\n    } else {\n      this.w = w.transpose();\n      this.s = t.transpose().mmul(t).sqrt();\n      if (scaleScores) {\n        this.t = t.clone().div(this.s.get(0, 0));\n      } else {\n        this.t = t;\n      }\n      this.xResidual = X.sub(t.mmul(w.transpose()));\n    }\n  }\n}\n\nexports.AbstractMatrix = AbstractMatrix;\nexports.CHO = CholeskyDecomposition;\nexports.CholeskyDecomposition = CholeskyDecomposition;\nexports.DistanceMatrix = DistanceMatrix;\nexports.EVD = EigenvalueDecomposition;\nexports.EigenvalueDecomposition = EigenvalueDecomposition;\nexports.LU = LuDecomposition;\nexports.LuDecomposition = LuDecomposition;\nexports.Matrix = Matrix;\nexports.MatrixColumnSelectionView = MatrixColumnSelectionView;\nexports.MatrixColumnView = MatrixColumnView;\nexports.MatrixFlipColumnView = MatrixFlipColumnView;\nexports.MatrixFlipRowView = MatrixFlipRowView;\nexports.MatrixRowSelectionView = MatrixRowSelectionView;\nexports.MatrixRowView = MatrixRowView;\nexports.MatrixSelectionView = MatrixSelectionView;\nexports.MatrixSubView = MatrixSubView;\nexports.MatrixTransposeView = MatrixTransposeView;\nexports.NIPALS = nipals;\nexports.Nipals = nipals;\nexports.QR = QrDecomposition;\nexports.QrDecomposition = QrDecomposition;\nexports.SVD = SingularValueDecomposition;\nexports.SingularValueDecomposition = SingularValueDecomposition;\nexports.SymmetricMatrix = SymmetricMatrix;\nexports.WrapperMatrix1D = WrapperMatrix1D;\nexports.WrapperMatrix2D = WrapperMatrix2D;\nexports.correlation = correlation;\nexports.covariance = covariance;\nexports.default = Matrix;\nexports.determinant = determinant;\nexports.inverse = inverse;\nexports.linearDependencies = linearDependencies;\nexports.pseudoInverse = pseudoInverse;\nexports.solve = solve;\nexports.wrap = wrap;\n//# sourceMappingURL=matrix.js.map\n","import * as matrix from './matrix.js';\n\nexport const AbstractMatrix = matrix.AbstractMatrix;\nexport const CHO = matrix.CHO;\nexport const CholeskyDecomposition = matrix.CholeskyDecomposition;\nexport const DistanceMatrix = matrix.DistanceMatrix;\nexport const EVD = matrix.EVD;\nexport const EigenvalueDecomposition = matrix.EigenvalueDecomposition;\nexport const LU = matrix.LU;\nexport const LuDecomposition = matrix.LuDecomposition;\nexport const Matrix = matrix.Matrix;\nexport const MatrixColumnSelectionView = matrix.MatrixColumnSelectionView;\nexport const MatrixColumnView = matrix.MatrixColumnView;\nexport const MatrixFlipColumnView = matrix.MatrixFlipColumnView;\nexport const MatrixFlipRowView = matrix.MatrixFlipRowView;\nexport const MatrixRowSelectionView = matrix.MatrixRowSelectionView;\nexport const MatrixRowView = matrix.MatrixRowView;\nexport const MatrixSelectionView = matrix.MatrixSelectionView;\nexport const MatrixSubView = matrix.MatrixSubView;\nexport const MatrixTransposeView = matrix.MatrixTransposeView;\nexport const NIPALS = matrix.NIPALS;\nexport const Nipals = matrix.Nipals;\nexport const QR = matrix.QR;\nexport const QrDecomposition = matrix.QrDecomposition;\nexport const SVD = matrix.SVD;\nexport const SingularValueDecomposition = matrix.SingularValueDecomposition;\nexport const SymmetricMatrix = matrix.SymmetricMatrix;\nexport const WrapperMatrix1D = matrix.WrapperMatrix1D;\nexport const WrapperMatrix2D = matrix.WrapperMatrix2D;\nexport const correlation = matrix.correlation;\nexport const covariance = matrix.covariance;\nexport default matrix.default.Matrix ? matrix.default.Matrix : matrix.Matrix;\nexport const determinant = matrix.determinant;\nexport const inverse = matrix.inverse;\nexport const linearDependencies = matrix.linearDependencies;\nexport const pseudoInverse = matrix.pseudoInverse;\nexport const solve = matrix.solve;\nexport const wrap = matrix.wrap;\n","import { Matrix } from 'ml-matrix';\n/**\n * Given a vector, returns its norm.\n * @private\n * @param {Matrix} X - the vector.\n * @returns {number} norm of the vector.\n */\nexport function norm(X) {\n    return Math.sqrt(X.clone().apply(pow2array).sum());\n}\n/**\n * Powers by 2 each element of a Matrix or a Vector, used in the apply method of\n * the Matrix object.\n * @private\n * @param {number} i - index i.\n * @param {number} j - index j.\n */\nexport function pow2array(i, j) {\n    // eslint-disable-next-line no-invalid-this -- `this` is the Matrix bound by apply()\n    this.set(i, j, this.get(i, j) ** 2);\n}\n/**\n * Normalizes the dataset and returns the means and standard deviation of each\n * feature.\n * @private\n * @param {Matrix} dataset - the dataset to normalize.\n * @returns {object} dataset normalized, means and standard deviations.\n */\nexport function featureNormalize(dataset) {\n    let means = dataset.mean('column');\n    let std = dataset.standardDeviation('column', {\n        mean: means,\n        unbiased: true,\n    });\n    let result = Matrix.checkMatrix(dataset).subRowVector(means);\n    return { result: result.divRowVector(std), means, std };\n}\n/**\n * Initializes an array of matrices.\n * @private\n * @param {Array} array - the array to initialize.\n * @param {boolean} isMatrix - whether the array holds 2D matrices.\n * @returns {Array} array with the matrices initialized.\n */\nexport function initializeMatrices(array, isMatrix) {\n    if (isMatrix) {\n        for (let i = 0; i < array.length; ++i) {\n            for (let j = 0; j < array[i].length; ++j) {\n                let elem = array[i][j];\n                array[i][j] = elem !== null ? new Matrix(array[i][j]) : undefined;\n            }\n        }\n    }\n    else {\n        for (let i = 0; i < array.length; ++i) {\n            array[i] = new Matrix(array[i]);\n        }\n    }\n    return array;\n}\n//# sourceMappingURL=utils.js.map","import { Matrix } from 'ml-matrix';\nimport * as Utils from './util/utils.js';\n/**\n * @class PLS\n */\nexport class PLS {\n    /**\n     * Constructor for Partial Least Squares (PLS)\n     * @param {object} options - constructor options.\n     * @param {number} [options.latentVectors] - Number of latent vector to get (if the algorithm doesn't find a good model below the tolerance)\n     * @param {number} [options.tolerance=1e-5] - tolerance used to stop the algorithm.\n     * @param {boolean} [options.scale=true] - rescale dataset using mean.\n     * @param {object} model - for load purposes.\n     */\n    constructor(options, model) {\n        if (options === true) {\n            this.meanX = model.meanX;\n            this.stdDevX = model.stdDevX;\n            this.meanY = model.meanY;\n            this.stdDevY = model.stdDevY;\n            this.PBQ = Matrix.checkMatrix(model.PBQ);\n            this.R2X = model.R2X;\n            this.scale = model.scale;\n            this.scaleMethod = model.scaleMethod;\n            this.tolerance = model.tolerance;\n        }\n        else {\n            let { tolerance = 1e-5, scale = true, latentVectors } = options;\n            this.tolerance = tolerance;\n            this.scale = scale;\n            this.latentVectors = latentVectors;\n        }\n    }\n    /**\n     * Fits the model with the given data and predictions, in this function is calculated the\n     * following outputs:\n     *\n     * T - Score matrix of X\n     * P - Loading matrix of X\n     * U - Score matrix of Y\n     * Q - Loading matrix of Y\n     * B - Matrix of regression coefficient\n     * W - Weight matrix of X\n     * @param {Matrix|Array} trainingSet - matrix of features.\n     * @param {Matrix|Array} trainingValues - matrix of predictions.\n     */\n    train(trainingSet, trainingValues) {\n        trainingSet = Matrix.checkMatrix(trainingSet);\n        trainingValues = Matrix.checkMatrix(trainingValues);\n        if (trainingSet.length !== trainingValues.length) {\n            throw new RangeError('The number of X rows must be equal to the number of Y rows');\n        }\n        this.meanX = trainingSet.mean('column');\n        this.stdDevX = trainingSet.standardDeviation('column', {\n            mean: this.meanX,\n            unbiased: true,\n        });\n        this.meanY = trainingValues.mean('column');\n        this.stdDevY = trainingValues.standardDeviation('column', {\n            mean: this.meanY,\n            unbiased: true,\n        });\n        if (this.scale) {\n            trainingSet = trainingSet\n                .clone()\n                .subRowVector(this.meanX)\n                .divRowVector(this.stdDevX);\n            trainingValues = trainingValues\n                .clone()\n                .subRowVector(this.meanY)\n                .divRowVector(this.stdDevY);\n        }\n        if (this.latentVectors === undefined) {\n            this.latentVectors = Math.min(trainingSet.rows - 1, trainingSet.columns);\n        }\n        let rx = trainingSet.rows;\n        let cx = trainingSet.columns;\n        let ry = trainingValues.rows;\n        let cy = trainingValues.columns;\n        let ssqXcal = trainingSet.clone().mul(trainingSet).sum(); // for the r²\n        let sumOfSquaresY = trainingValues.clone().mul(trainingValues).sum();\n        let tolerance = this.tolerance;\n        let n = this.latentVectors;\n        let T = Matrix.zeros(rx, n);\n        let P = Matrix.zeros(cx, n);\n        let U = Matrix.zeros(ry, n);\n        let Q = Matrix.zeros(cy, n);\n        let B = Matrix.zeros(n, n);\n        let W = P.clone();\n        let k = 0;\n        let t;\n        let w;\n        let q;\n        let p;\n        while (Utils.norm(trainingValues) > tolerance && k < n) {\n            let transposeX = trainingSet.transpose();\n            let transposeY = trainingValues.transpose();\n            let tIndex = maxSumColIndex(trainingSet.clone().mul(trainingSet));\n            let uIndex = maxSumColIndex(trainingValues.clone().mul(trainingValues));\n            let t1 = trainingSet.getColumnVector(tIndex);\n            let u = trainingValues.getColumnVector(uIndex);\n            t = Matrix.zeros(rx, 1);\n            while (Utils.norm(t1.clone().sub(t)) > tolerance) {\n                w = transposeX.mmul(u);\n                w.div(Utils.norm(w));\n                t = t1;\n                t1 = trainingSet.mmul(w);\n                q = transposeY.mmul(t1);\n                q.div(Utils.norm(q));\n                u = trainingValues.mmul(q);\n            }\n            t = t1;\n            let num = transposeX.mmul(t);\n            let den = t.transpose().mmul(t).get(0, 0);\n            p = num.div(den);\n            let pnorm = Utils.norm(p);\n            p.div(pnorm);\n            t.mul(pnorm);\n            w.mul(pnorm);\n            num = u.transpose().mmul(t);\n            den = t.transpose().mmul(t).get(0, 0);\n            let b = num.div(den).get(0, 0);\n            trainingSet.sub(t.mmul(p.transpose()));\n            trainingValues.sub(t.clone().mul(b).mmul(q.transpose()));\n            T.setColumn(k, t);\n            P.setColumn(k, p);\n            U.setColumn(k, u);\n            Q.setColumn(k, q);\n            W.setColumn(k, w);\n            B.set(k, k, b);\n            k++;\n        }\n        k--;\n        T = T.subMatrix(0, T.rows - 1, 0, k);\n        P = P.subMatrix(0, P.rows - 1, 0, k);\n        U = U.subMatrix(0, U.rows - 1, 0, k);\n        Q = Q.subMatrix(0, Q.rows - 1, 0, k);\n        W = W.subMatrix(0, W.rows - 1, 0, k);\n        B = B.subMatrix(0, k, 0, k);\n        this.ssqYcal = sumOfSquaresY;\n        this.E = trainingSet;\n        this.F = trainingValues;\n        this.T = T;\n        this.P = P;\n        this.U = U;\n        this.Q = Q;\n        this.W = W;\n        this.B = B;\n        this.PBQ = P.mmul(B).mmul(Q.transpose());\n        this.R2X = t\n            .transpose()\n            .mmul(t)\n            .mmul(p.transpose().mmul(p))\n            .div(ssqXcal)\n            .get(0, 0);\n    }\n    /**\n     * Predicts the behavior of the given dataset.\n     * @param {Matrix|Array} dataset - data to be predicted.\n     * @returns {Matrix} - predictions of each element of the dataset.\n     */\n    predict(dataset) {\n        let X = Matrix.checkMatrix(dataset);\n        if (this.scale) {\n            X = X.subRowVector(this.meanX).divRowVector(this.stdDevX);\n        }\n        let Y = X.mmul(this.PBQ);\n        Y = Y.mulRowVector(this.stdDevY).addRowVector(this.meanY);\n        return Y;\n    }\n    /**\n     * Returns the explained variance on training of the PLS model\n     * @returns {number} the explained variance.\n     */\n    getExplainedVariance() {\n        return this.R2X;\n    }\n    /**\n     * Export the current model to JSON.\n     * @returns {object} - Current model.\n     */\n    toJSON() {\n        return {\n            name: 'PLS',\n            R2X: this.R2X,\n            meanX: this.meanX,\n            stdDevX: this.stdDevX,\n            meanY: this.meanY,\n            stdDevY: this.stdDevY,\n            PBQ: this.PBQ,\n            tolerance: this.tolerance,\n            scale: this.scale,\n        };\n    }\n    /**\n     * Load a PLS model from a JSON Object\n     * @param {object} model - the serialized model to load.\n     * @returns {PLS} - PLS object from the given model\n     */\n    static load(model) {\n        if (model.name !== 'PLS') {\n            throw new RangeError(`Invalid model: ${model.name}`);\n        }\n        return new PLS(true, model);\n    }\n}\n/**\n * Returns the index where the sum of each column vector is maximum.\n * @private\n * @param {Matrix} data - the matrix to scan.\n * @returns {number} index of the maximum.\n */\nfunction maxSumColIndex(data) {\n    return Matrix.rowVector(data.sum('column')).maxIndex()[0];\n}\n//# sourceMappingURL=PLS.js.map","import { Matrix, SingularValueDecomposition, inverse } from 'ml-matrix';\nimport { initializeMatrices } from './util/utils.js';\n/**\n * @class KOPLS\n */\nexport class KOPLS {\n    /**\n     * Constructor for Kernel-based Orthogonal Projections to Latent Structures (K-OPLS)\n     * @param {object} options - constructor options.\n     * @param {number} [options.predictiveComponents] - Number of predictive components to use.\n     * @param {number} [options.orthogonalComponents] - Number of Y-Orthogonal components.\n     * @param {object} [options.kernel] - Kernel object to apply, see [ml-kernel](https://github.com/mljs/kernel).\n     * @param {object} model - for load purposes.\n     */\n    constructor(options, model) {\n        if (options === true) {\n            this.trainingSet = new Matrix(model.trainingSet);\n            this.YLoadingMat = new Matrix(model.YLoadingMat);\n            this.SigmaPow = new Matrix(model.SigmaPow);\n            this.YScoreMat = new Matrix(model.YScoreMat);\n            this.predScoreMat = initializeMatrices(model.predScoreMat, false);\n            this.YOrthLoadingVec = initializeMatrices(model.YOrthLoadingVec, false);\n            this.YOrthEigen = model.YOrthEigen;\n            this.YOrthScoreMat = initializeMatrices(model.YOrthScoreMat, false);\n            this.toNorm = initializeMatrices(model.toNorm, false);\n            this.TURegressionCoeff = initializeMatrices(model.TURegressionCoeff, false);\n            this.kernelX = initializeMatrices(model.kernelX, true);\n            this.kernel = model.kernel;\n            this.orthogonalComp = model.orthogonalComp;\n            this.predictiveComp = model.predictiveComp;\n        }\n        else {\n            if (options.predictiveComponents === undefined) {\n                throw new RangeError('no predictive components found!');\n            }\n            if (options.orthogonalComponents === undefined) {\n                throw new RangeError('no orthogonal components found!');\n            }\n            if (options.kernel === undefined) {\n                throw new RangeError('no kernel found!');\n            }\n            this.orthogonalComp = options.orthogonalComponents;\n            this.predictiveComp = options.predictiveComponents;\n            this.kernel = options.kernel;\n        }\n    }\n    /**\n     * Train the K-OPLS model with the given training set and labels.\n     * @param {Matrix|Array} trainingSet - matrix of features.\n     * @param {Matrix|Array} trainingValues - matrix of labels.\n     */\n    train(trainingSet, trainingValues) {\n        trainingSet = Matrix.checkMatrix(trainingSet);\n        trainingValues = Matrix.checkMatrix(trainingValues);\n        // to save and compute kernel with the prediction dataset.\n        this.trainingSet = trainingSet.clone();\n        let kernelX = this.kernel.compute(trainingSet);\n        let Identity = Matrix.eye(kernelX.rows, kernelX.rows, 1);\n        let temp = kernelX;\n        kernelX = new Array(this.orthogonalComp + 1);\n        for (let i = 0; i < this.orthogonalComp + 1; i++) {\n            kernelX[i] = new Array(this.orthogonalComp + 1);\n        }\n        kernelX[0][0] = temp;\n        let result = new SingularValueDecomposition(trainingValues.transpose().mmul(kernelX[0][0]).mmul(trainingValues), {\n            computeLeftSingularVectors: true,\n            computeRightSingularVectors: false,\n        });\n        let YLoadingMat = result.leftSingularVectors;\n        let Sigma = result.diagonalMatrix;\n        YLoadingMat = YLoadingMat.subMatrix(0, YLoadingMat.rows - 1, 0, this.predictiveComp - 1);\n        Sigma = Sigma.subMatrix(0, this.predictiveComp - 1, 0, this.predictiveComp - 1);\n        let YScoreMat = trainingValues.mmul(YLoadingMat);\n        let predScoreMat = new Array(this.orthogonalComp + 1);\n        let TURegressionCoeff = new Array(this.orthogonalComp + 1);\n        let YOrthScoreMat = new Array(this.orthogonalComp);\n        let YOrthLoadingVec = new Array(this.orthogonalComp);\n        let YOrthEigen = new Array(this.orthogonalComp);\n        let YOrthScoreNorm = new Array(this.orthogonalComp);\n        let SigmaPow = Matrix.pow(Sigma, -0.5);\n        // to avoid errors, check infinity\n        SigmaPow.apply(removeInfinity);\n        for (let i = 0; i < this.orthogonalComp; ++i) {\n            predScoreMat[i] = kernelX[0][i]\n                .transpose()\n                .mmul(YScoreMat)\n                .mmul(SigmaPow);\n            let TpiPrime = predScoreMat[i].transpose();\n            TURegressionCoeff[i] = inverse(TpiPrime.mmul(predScoreMat[i]))\n                .mmul(TpiPrime)\n                .mmul(YScoreMat);\n            result = new SingularValueDecomposition(TpiPrime.mmul(Matrix.sub(kernelX[i][i], predScoreMat[i].mmul(TpiPrime))).mmul(predScoreMat[i]), {\n                computeLeftSingularVectors: true,\n                computeRightSingularVectors: false,\n            });\n            let CoTemp = result.leftSingularVectors;\n            let SoTemp = result.diagonalMatrix;\n            YOrthLoadingVec[i] = CoTemp.subMatrix(0, CoTemp.rows - 1, 0, 0);\n            YOrthEigen[i] = SoTemp.get(0, 0);\n            YOrthScoreMat[i] = Matrix.sub(kernelX[i][i], predScoreMat[i].mmul(TpiPrime))\n                .mmul(predScoreMat[i])\n                .mmul(YOrthLoadingVec[i])\n                .mul(YOrthEigen[i] ** -0.5);\n            let toiPrime = YOrthScoreMat[i].transpose();\n            YOrthScoreNorm[i] = Matrix.sqrt(toiPrime.mmul(YOrthScoreMat[i]));\n            YOrthScoreMat[i] = YOrthScoreMat[i].divRowVector(YOrthScoreNorm[i]);\n            let ITo = Matrix.sub(Identity, YOrthScoreMat[i].mmul(YOrthScoreMat[i].transpose()));\n            kernelX[0][i + 1] = kernelX[0][i].mmul(ITo);\n            kernelX[i + 1][i + 1] = ITo.mmul(kernelX[i][i]).mmul(ITo);\n        }\n        let lastScoreMat = kernelX[0][this.orthogonalComp]\n            .transpose()\n            .mmul(YScoreMat)\n            .mmul(SigmaPow);\n        predScoreMat[this.orthogonalComp] = lastScoreMat.clone();\n        let lastTpPrime = lastScoreMat.transpose();\n        TURegressionCoeff[this.orthogonalComp] = inverse(lastTpPrime.mmul(lastScoreMat))\n            .mmul(lastTpPrime)\n            .mmul(YScoreMat);\n        this.YLoadingMat = YLoadingMat;\n        this.SigmaPow = SigmaPow;\n        this.YScoreMat = YScoreMat;\n        this.predScoreMat = predScoreMat;\n        this.YOrthLoadingVec = YOrthLoadingVec;\n        this.YOrthEigen = YOrthEigen;\n        this.YOrthScoreMat = YOrthScoreMat;\n        this.toNorm = YOrthScoreNorm;\n        this.TURegressionCoeff = TURegressionCoeff;\n        this.kernelX = kernelX;\n    }\n    /**\n     * Predicts the output given the matrix to predict.\n     * @param {Matrix|Array} toPredict - matrix of features to predict.\n     * @returns {{y: Matrix, predScoreMat: Array<Matrix>, predYOrthVectors: Array<Matrix>}} predictions\n     */\n    predict(toPredict) {\n        let KTestTrain = this.kernel.compute(toPredict, this.trainingSet);\n        let temp = KTestTrain;\n        KTestTrain = new Array(this.orthogonalComp + 1);\n        for (let i = 0; i < this.orthogonalComp + 1; i++) {\n            KTestTrain[i] = new Array(this.orthogonalComp + 1);\n        }\n        KTestTrain[0][0] = temp;\n        let YOrthScoreVector = new Array(this.orthogonalComp);\n        let predScoreMat = new Array(this.orthogonalComp);\n        let i;\n        for (i = 0; i < this.orthogonalComp; ++i) {\n            predScoreMat[i] = KTestTrain[i][0]\n                .mmul(this.YScoreMat)\n                .mmul(this.SigmaPow);\n            YOrthScoreVector[i] = Matrix.sub(KTestTrain[i][i], predScoreMat[i].mmul(this.predScoreMat[i].transpose()))\n                .mmul(this.predScoreMat[i])\n                .mmul(this.YOrthLoadingVec[i])\n                .mul(this.YOrthEigen[i] ** -0.5);\n            YOrthScoreVector[i] = YOrthScoreVector[i].divRowVector(this.toNorm[i]);\n            let scoreMatPrime = this.YOrthScoreMat[i].transpose();\n            KTestTrain[i + 1][0] = Matrix.sub(KTestTrain[i][0], YOrthScoreVector[i]\n                .mmul(scoreMatPrime)\n                .mmul(this.kernelX[0][i].transpose()));\n            let p1 = Matrix.sub(KTestTrain[i][0], KTestTrain[i][i].mmul(this.YOrthScoreMat[i]).mmul(scoreMatPrime));\n            let p2 = YOrthScoreVector[i].mmul(scoreMatPrime).mmul(this.kernelX[i][i]);\n            let p3 = p2.mmul(this.YOrthScoreMat[i]).mmul(scoreMatPrime);\n            KTestTrain[i + 1][i + 1] = p1.sub(p2).add(p3);\n        }\n        predScoreMat[i] = KTestTrain[i][0].mmul(this.YScoreMat).mmul(this.SigmaPow);\n        let prediction = predScoreMat[i]\n            .mmul(this.TURegressionCoeff[i])\n            .mmul(this.YLoadingMat.transpose());\n        return {\n            prediction,\n            predScoreMat,\n            predYOrthVectors: YOrthScoreVector,\n        };\n    }\n    /**\n     * Export the current model to JSON.\n     * @returns {object} - Current model.\n     */\n    toJSON() {\n        return {\n            name: 'K-OPLS',\n            YLoadingMat: this.YLoadingMat,\n            SigmaPow: this.SigmaPow,\n            YScoreMat: this.YScoreMat,\n            predScoreMat: this.predScoreMat,\n            YOrthLoadingVec: this.YOrthLoadingVec,\n            YOrthEigen: this.YOrthEigen,\n            YOrthScoreMat: this.YOrthScoreMat,\n            toNorm: this.toNorm,\n            TURegressionCoeff: this.TURegressionCoeff,\n            kernelX: this.kernelX,\n            trainingSet: this.trainingSet,\n            orthogonalComp: this.orthogonalComp,\n            predictiveComp: this.predictiveComp,\n        };\n    }\n    /**\n     * Load a K-OPLS with the given model.\n     * @param {object} model - the serialized model to load.\n     * @param {object} kernel - kernel used on the model, see [ml-kernel](https://github.com/mljs/kernel).\n     * @returns {KOPLS} the loaded K-OPLS model.\n     */\n    static load(model, kernel) {\n        if (model.name !== 'K-OPLS') {\n            throw new RangeError(`Invalid model: ${model.name}`);\n        }\n        if (!kernel) {\n            throw new RangeError('You must provide a kernel for the model!');\n        }\n        model.kernel = kernel;\n        return new KOPLS(true, model);\n    }\n}\n/**\n * Replaces infinite entries with zero. Used as a Matrix.apply() callback.\n * @param {number} i - row index.\n * @param {number} j - column index.\n */\nfunction removeInfinity(i, j) {\n    // eslint-disable-next-line no-invalid-this -- `this` is the Matrix bound by apply()\n    if (this.get(i, j) === Infinity) {\n        // eslint-disable-next-line no-invalid-this -- `this` is the Matrix bound by apply()\n        this.set(i, j, 0);\n    }\n}\n//# sourceMappingURL=KOPLS.js.map","// eslint-disable-next-line @typescript-eslint/unbound-method\nconst toString = Object.prototype.toString;\n/**\n * Checks if an object is an instance of an Array (array or typed array, except those that contain bigint values).\n * @param value - Object to check.\n * @returns True if the object is an array or a typed array.\n */\nexport function isAnyArray(value) {\n    const tag = toString.call(value);\n    return tag.endsWith('Array]') && !tag.includes('Big');\n}\n//# sourceMappingURL=index.js.map","/**\n * Constructs a confusion matrix\n * @class ConfusionMatrix\n * @example\n * const CM = new ConfusionMatrix([[13, 2], [10, 5]], ['cat', 'dog'])\n * @param matrix - The confusion matrix, a 2D Array. Rows represent the actual label and columns the predicted label.\n * @param labels - Labels of the confusion matrix, a 1D Array\n */\nexport class ConfusionMatrix {\n    constructor(matrix, labels) {\n        if (matrix.length !== matrix[0].length) {\n            throw new Error('Confusion matrix must be square');\n        }\n        if (labels.length !== matrix.length) {\n            throw new Error('Confusion matrix and labels should have the same length');\n        }\n        this.labels = labels;\n        this.matrix = matrix;\n    }\n    /**\n     * Construct confusion matrix from the predicted and actual labels (classes). Be sure to provide the arguments in\n     * the correct order!\n     * @param actual  - The predicted labels of the classification\n     * @param predicted - The actual labels of the classification. Has to be of same length as predicted.\n     * @param [options] - Additional options\n     * @param [options.labels] - The list of labels that should be used. If not provided the distinct set\n     *     of labels present in predicted and actual is used. Labels are compared using the strict equality operator\n     *     '==='\n     * @param [options.sort]\n     * @return Confusion matrix\n     */\n    static fromLabels(actual, predicted, options = {}) {\n        if (predicted.length !== actual.length) {\n            throw new Error('predicted and actual must have the same length');\n        }\n        let distinctLabels;\n        if (options.labels) {\n            distinctLabels = new Set(options.labels);\n        }\n        else {\n            distinctLabels = new Set([...actual, ...predicted]);\n        }\n        const labels = Array.from(distinctLabels);\n        if (options.sort) {\n            labels.sort(options.sort);\n        }\n        // Create confusion matrix and fill with 0's\n        const matrix = Array.from({ length: labels.length });\n        for (let i = 0; i < matrix.length; i++) {\n            matrix[i] = new Array(matrix.length);\n            matrix[i].fill(0);\n        }\n        for (let i = 0; i < predicted.length; i++) {\n            const actualIdx = labels.indexOf(actual[i]);\n            const predictedIdx = labels.indexOf(predicted[i]);\n            if (actualIdx >= 0 && predictedIdx >= 0) {\n                matrix[actualIdx][predictedIdx]++;\n            }\n        }\n        return new ConfusionMatrix(matrix, labels);\n    }\n    /**\n     * Get the confusion matrix\n     */\n    getMatrix() {\n        return this.matrix;\n    }\n    getLabels() {\n        return this.labels;\n    }\n    /**\n     * Get the total number of samples\n     */\n    getTotalCount() {\n        let predicted = 0;\n        for (const row of this.matrix) {\n            for (const element of row) {\n                predicted += element;\n            }\n        }\n        return predicted;\n    }\n    /**\n     * Get the total number of true predictions\n     */\n    getTrueCount() {\n        let count = 0;\n        for (let i = 0; i < this.matrix.length; i++) {\n            count += this.matrix[i][i];\n        }\n        return count;\n    }\n    /**\n     * Get the total number of false predictions.\n     */\n    getFalseCount() {\n        return this.getTotalCount() - this.getTrueCount();\n    }\n    /**\n     * Get the number of true positive predictions.\n     * @param label - The label that should be considered \"positive\"\n     */\n    getTruePositiveCount(label) {\n        const index = this.getIndex(label);\n        return this.matrix[index][index];\n    }\n    /**\n     * Get the number of true negative predictions.\n     * @param label - The label that should be considered \"positive\"\n     */\n    getTrueNegativeCount(label) {\n        const index = this.getIndex(label);\n        let count = 0;\n        for (let i = 0; i < this.matrix.length; i++) {\n            for (let j = 0; j < this.matrix.length; j++) {\n                if (i !== index && j !== index) {\n                    count += this.matrix[i][j];\n                }\n            }\n        }\n        return count;\n    }\n    /**\n     * Get the number of false positive predictions.\n     * @param label - The label that should be considered \"positive\"\n     */\n    getFalsePositiveCount(label) {\n        const index = this.getIndex(label);\n        let count = 0;\n        for (let i = 0; i < this.matrix.length; i++) {\n            if (i !== index) {\n                count += this.matrix[i][index];\n            }\n        }\n        return count;\n    }\n    /**\n     * Get the number of false negative predictions.\n     * @param label - The label that should be considered \"positive\"\n     */\n    getFalseNegativeCount(label) {\n        const index = this.getIndex(label);\n        let count = 0;\n        for (let i = 0; i < this.matrix.length; i++) {\n            if (i !== index) {\n                count += this.matrix[index][i];\n            }\n        }\n        return count;\n    }\n    /**\n     * Get the number of real positive samples.\n     * @param label - The label that should be considered \"positive\"\n     */\n    getPositiveCount(label) {\n        return this.getTruePositiveCount(label) + this.getFalseNegativeCount(label);\n    }\n    /**\n     * Get the number of real negative samples.\n     * @param  label - The label that should be considered \"positive\"\n     */\n    getNegativeCount(label) {\n        return this.getTrueNegativeCount(label) + this.getFalsePositiveCount(label);\n    }\n    /**\n     * Get the index in the confusion matrix that corresponds to the given label\n     * @param label - The label to search for\n     * @throws if the label is not found\n     */\n    getIndex(label) {\n        const index = this.labels.indexOf(label);\n        if (index === -1)\n            throw new Error('The label does not exist');\n        return index;\n    }\n    /**\n     * Get the true positive rate a.k.a. sensitivity. Computes the ratio between the number of true positive predictions and the total number of positive samples.\n     * {@link https://en.wikipedia.org/wiki/Sensitivity_and_specificity}\n     * @param label - The label that should be considered \"positive\"\n     * @return The true positive rate [0-1]\n     */\n    getTruePositiveRate(label) {\n        return this.getTruePositiveCount(label) / this.getPositiveCount(label);\n    }\n    /**\n     * Get the true negative rate a.k.a. specificity. Computes the ration between the number of true negative predictions and the total number of negative samples.\n     * {@link https://en.wikipedia.org/wiki/Sensitivity_and_specificity}\n     * @param label - The label that should be considered \"positive\"\n     * @return The true negative rate a.k.a. specificity.\n     */\n    getTrueNegativeRate(label) {\n        return this.getTrueNegativeCount(label) / this.getNegativeCount(label);\n    }\n    /**\n     * Get the positive predictive value a.k.a. precision. Computes TP / (TP + FP)\n     * {@link https://en.wikipedia.org/wiki/Positive_and_negative_predictive_values}\n     * @param label - The label that should be considered \"positive\"\n     * @return the positive predictive value a.k.a. precision.\n     */\n    getPositivePredictiveValue(label) {\n        const TP = this.getTruePositiveCount(label);\n        return TP / (TP + this.getFalsePositiveCount(label));\n    }\n    /**\n     * Negative predictive value\n     * {@link https://en.wikipedia.org/wiki/Positive_and_negative_predictive_values}\n     * @param label - The label that should be considered \"positive\"\n     */\n    getNegativePredictiveValue(label) {\n        const TN = this.getTrueNegativeCount(label);\n        return TN / (TN + this.getFalseNegativeCount(label));\n    }\n    /**\n     * False negative rate a.k.a. miss rate.\n     * {@link https://en.wikipedia.org/wiki/Type_I_and_type_II_errors#False_positive_and_false_negative_rates}\n     * @param label - The label that should be considered \"positive\"\n     */\n    getFalseNegativeRate(label) {\n        return 1 - this.getTruePositiveRate(label);\n    }\n    /**\n     * False positive rate a.k.a. fall-out rate.\n     * {@link https://en.wikipedia.org/wiki/Type_I_and_type_II_errors#False_positive_and_false_negative_rates}\n     * @param  label - The label that should be considered \"positive\"\n     */\n    getFalsePositiveRate(label) {\n        return 1 - this.getTrueNegativeRate(label);\n    }\n    /**\n     * False discovery rate (FDR)\n     * {@link https://en.wikipedia.org/wiki/False_discovery_rate}\n     * @param label - The label that should be considered \"positive\"\n     */\n    getFalseDiscoveryRate(label) {\n        const FP = this.getFalsePositiveCount(label);\n        return FP / (FP + this.getTruePositiveCount(label));\n    }\n    /**\n     * False omission rate (FOR)\n     * @param label - The label that should be considered \"positive\"\n     */\n    getFalseOmissionRate(label) {\n        const FN = this.getFalseNegativeCount(label);\n        return FN / (FN + this.getTruePositiveCount(label));\n    }\n    /**\n     * F1 score\n     * {@link https://en.wikipedia.org/wiki/F1_score}\n     * @param label - The label that should be considered \"positive\"\n     */\n    getF1Score(label) {\n        const TP = this.getTruePositiveCount(label);\n        return ((2 * TP) /\n            (2 * TP +\n                this.getFalsePositiveCount(label) +\n                this.getFalseNegativeCount(label)));\n    }\n    /**\n     * Matthews correlation coefficient (MCC)\n     * {@link https://en.wikipedia.org/wiki/Matthews_correlation_coefficient}\n     * @param label - The label that should be considered \"positive\"\n     */\n    getMatthewsCorrelationCoefficient(label) {\n        const TP = this.getTruePositiveCount(label);\n        const TN = this.getTrueNegativeCount(label);\n        const FP = this.getFalsePositiveCount(label);\n        const FN = this.getFalseNegativeCount(label);\n        return ((TP * TN - FP * FN) /\n            Math.sqrt((TP + FP) * (TP + FN) * (TN + FP) * (TN + FN)));\n    }\n    /**\n     * Informedness\n     * {@link https://en.wikipedia.org/wiki/Youden%27s_J_statistic}\n     * @param label - The label that should be considered \"positive\"\n     */\n    getInformedness(label) {\n        return (this.getTruePositiveRate(label) + this.getTrueNegativeRate(label) - 1);\n    }\n    /**\n     * Markedness\n     * @param label - The label that should be considered \"positive\"\n     */\n    getMarkedness(label) {\n        return (this.getPositivePredictiveValue(label) +\n            this.getNegativePredictiveValue(label) -\n            1);\n    }\n    /**\n     * Get the confusion table.\n     * @param label - The label that should be considered \"positive\"\n     * @return The 2x2 confusion table. [[TP, FN], [FP, TN]]\n     */\n    getConfusionTable(label) {\n        return [\n            [this.getTruePositiveCount(label), this.getFalseNegativeCount(label)],\n            [this.getFalsePositiveCount(label), this.getTrueNegativeCount(label)],\n        ];\n    }\n    /**\n     * Get total accuracy.\n     * The ratio between the number of true predictions and total number of classifications ([0-1])\n     */\n    getAccuracy() {\n        let correct = 0;\n        let incorrect = 0;\n        for (let i = 0; i < this.matrix.length; i++) {\n            for (let j = 0; j < this.matrix.length; j++) {\n                if (i === j)\n                    correct += this.matrix[i][j];\n                else\n                    incorrect += this.matrix[i][j];\n            }\n        }\n        return correct / (correct + incorrect);\n    }\n    /**\n     * Returns the element in the confusion matrix that corresponds to the given actual and predicted labels.\n     * @param actual - The true label\n     * @param predicted - The predicted label\n     * @return The element in the confusion matrix\n     */\n    getCount(actual, predicted) {\n        const actualIndex = this.getIndex(actual);\n        const predictedIndex = this.getIndex(predicted);\n        return this.matrix[actualIndex][predictedIndex];\n    }\n    /**\n     * Compute the general prediction accuracy\n     * @deprecated Use getAccuracy\n     * @return The prediction accuracy ([0-1]\n     */\n    get accuracy() {\n        return this.getAccuracy();\n    }\n    /**\n     * Compute the number of predicted observations\n     * @deprecated Use getTotalCount\n     */\n    get total() {\n        return this.getTotalCount();\n    }\n}\n//# sourceMappingURL=index.js.map","(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n\ttypeof define === 'function' && define.amd ? define(factory) :\n\t(factory());\n}(this, (function () { 'use strict';\n\n\tfunction createCommonjsModule(fn, module) {\n\t\treturn module = { exports: {} }, fn(module, module.exports), module.exports;\n\t}\n\n\tvar runtime = createCommonjsModule(function (module) {\n\t/**\n\t * Copyright (c) 2014-present, Facebook, Inc.\n\t *\n\t * This source code is licensed under the MIT license found in the\n\t * LICENSE file in the root directory of this source tree.\n\t */\n\n\t!(function(global) {\n\n\t  var Op = Object.prototype;\n\t  var hasOwn = Op.hasOwnProperty;\n\t  var undefined; // More compressible than void 0.\n\t  var $Symbol = typeof Symbol === \"function\" ? Symbol : {};\n\t  var iteratorSymbol = $Symbol.iterator || \"@@iterator\";\n\t  var asyncIteratorSymbol = $Symbol.asyncIterator || \"@@asyncIterator\";\n\t  var toStringTagSymbol = $Symbol.toStringTag || \"@@toStringTag\";\n\t  var runtime = global.regeneratorRuntime;\n\t  if (runtime) {\n\t    {\n\t      // If regeneratorRuntime is defined globally and we're in a module,\n\t      // make the exports object identical to regeneratorRuntime.\n\t      module.exports = runtime;\n\t    }\n\t    // Don't bother evaluating the rest of this file if the runtime was\n\t    // already defined globally.\n\t    return;\n\t  }\n\n\t  // Define the runtime globally (as expected by generated code) as either\n\t  // module.exports (if we're in a module) or a new, empty object.\n\t  runtime = global.regeneratorRuntime = module.exports;\n\n\t  function wrap(innerFn, outerFn, self, tryLocsList) {\n\t    // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.\n\t    var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;\n\t    var generator = Object.create(protoGenerator.prototype);\n\t    var context = new Context(tryLocsList || []);\n\n\t    // The ._invoke method unifies the implementations of the .next,\n\t    // .throw, and .return methods.\n\t    generator._invoke = makeInvokeMethod(innerFn, self, context);\n\n\t    return generator;\n\t  }\n\t  runtime.wrap = wrap;\n\n\t  // Try/catch helper to minimize deoptimizations. Returns a completion\n\t  // record like context.tryEntries[i].completion. This interface could\n\t  // have been (and was previously) designed to take a closure to be\n\t  // invoked without arguments, but in all the cases we care about we\n\t  // already have an existing method we want to call, so there's no need\n\t  // to create a new function object. We can even get away with assuming\n\t  // the method takes exactly one argument, since that happens to be true\n\t  // in every case, so we don't have to touch the arguments object. The\n\t  // only additional allocation required is the completion record, which\n\t  // has a stable shape and so hopefully should be cheap to allocate.\n\t  function tryCatch(fn, obj, arg) {\n\t    try {\n\t      return { type: \"normal\", arg: fn.call(obj, arg) };\n\t    } catch (err) {\n\t      return { type: \"throw\", arg: err };\n\t    }\n\t  }\n\n\t  var GenStateSuspendedStart = \"suspendedStart\";\n\t  var GenStateSuspendedYield = \"suspendedYield\";\n\t  var GenStateExecuting = \"executing\";\n\t  var GenStateCompleted = \"completed\";\n\n\t  // Returning this object from the innerFn has the same effect as\n\t  // breaking out of the dispatch switch statement.\n\t  var ContinueSentinel = {};\n\n\t  // Dummy constructor functions that we use as the .constructor and\n\t  // .constructor.prototype properties for functions that return Generator\n\t  // objects. For full spec compliance, you may wish to configure your\n\t  // minifier not to mangle the names of these two functions.\n\t  function Generator() {}\n\t  function GeneratorFunction() {}\n\t  function GeneratorFunctionPrototype() {}\n\n\t  // This is a polyfill for %IteratorPrototype% for environments that\n\t  // don't natively support it.\n\t  var IteratorPrototype = {};\n\t  IteratorPrototype[iteratorSymbol] = function () {\n\t    return this;\n\t  };\n\n\t  var getProto = Object.getPrototypeOf;\n\t  var NativeIteratorPrototype = getProto && getProto(getProto(values([])));\n\t  if (NativeIteratorPrototype &&\n\t      NativeIteratorPrototype !== Op &&\n\t      hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {\n\t    // This environment has a native %IteratorPrototype%; use it instead\n\t    // of the polyfill.\n\t    IteratorPrototype = NativeIteratorPrototype;\n\t  }\n\n\t  var Gp = GeneratorFunctionPrototype.prototype =\n\t    Generator.prototype = Object.create(IteratorPrototype);\n\t  GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;\n\t  GeneratorFunctionPrototype.constructor = GeneratorFunction;\n\t  GeneratorFunctionPrototype[toStringTagSymbol] =\n\t    GeneratorFunction.displayName = \"GeneratorFunction\";\n\n\t  // Helper for defining the .next, .throw, and .return methods of the\n\t  // Iterator interface in terms of a single ._invoke method.\n\t  function defineIteratorMethods(prototype) {\n\t    [\"next\", \"throw\", \"return\"].forEach(function(method) {\n\t      prototype[method] = function(arg) {\n\t        return this._invoke(method, arg);\n\t      };\n\t    });\n\t  }\n\n\t  runtime.isGeneratorFunction = function(genFun) {\n\t    var ctor = typeof genFun === \"function\" && genFun.constructor;\n\t    return ctor\n\t      ? ctor === GeneratorFunction ||\n\t        // For the native GeneratorFunction constructor, the best we can\n\t        // do is to check its .name property.\n\t        (ctor.displayName || ctor.name) === \"GeneratorFunction\"\n\t      : false;\n\t  };\n\n\t  runtime.mark = function(genFun) {\n\t    if (Object.setPrototypeOf) {\n\t      Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);\n\t    } else {\n\t      genFun.__proto__ = GeneratorFunctionPrototype;\n\t      if (!(toStringTagSymbol in genFun)) {\n\t        genFun[toStringTagSymbol] = \"GeneratorFunction\";\n\t      }\n\t    }\n\t    genFun.prototype = Object.create(Gp);\n\t    return genFun;\n\t  };\n\n\t  // Within the body of any async function, `await x` is transformed to\n\t  // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test\n\t  // `hasOwn.call(value, \"__await\")` to determine if the yielded value is\n\t  // meant to be awaited.\n\t  runtime.awrap = function(arg) {\n\t    return { __await: arg };\n\t  };\n\n\t  function AsyncIterator(generator) {\n\t    function invoke(method, arg, resolve, reject) {\n\t      var record = tryCatch(generator[method], generator, arg);\n\t      if (record.type === \"throw\") {\n\t        reject(record.arg);\n\t      } else {\n\t        var result = record.arg;\n\t        var value = result.value;\n\t        if (value &&\n\t            typeof value === \"object\" &&\n\t            hasOwn.call(value, \"__await\")) {\n\t          return Promise.resolve(value.__await).then(function(value) {\n\t            invoke(\"next\", value, resolve, reject);\n\t          }, function(err) {\n\t            invoke(\"throw\", err, resolve, reject);\n\t          });\n\t        }\n\n\t        return Promise.resolve(value).then(function(unwrapped) {\n\t          // When a yielded Promise is resolved, its final value becomes\n\t          // the .value of the Promise<{value,done}> result for the\n\t          // current iteration. If the Promise is rejected, however, the\n\t          // result for this iteration will be rejected with the same\n\t          // reason. Note that rejections of yielded Promises are not\n\t          // thrown back into the generator function, as is the case\n\t          // when an awaited Promise is rejected. This difference in\n\t          // behavior between yield and await is important, because it\n\t          // allows the consumer to decide what to do with the yielded\n\t          // rejection (swallow it and continue, manually .throw it back\n\t          // into the generator, abandon iteration, whatever). With\n\t          // await, by contrast, there is no opportunity to examine the\n\t          // rejection reason outside the generator function, so the\n\t          // only option is to throw it from the await expression, and\n\t          // let the generator function handle the exception.\n\t          result.value = unwrapped;\n\t          resolve(result);\n\t        }, reject);\n\t      }\n\t    }\n\n\t    var previousPromise;\n\n\t    function enqueue(method, arg) {\n\t      function callInvokeWithMethodAndArg() {\n\t        return new Promise(function(resolve, reject) {\n\t          invoke(method, arg, resolve, reject);\n\t        });\n\t      }\n\n\t      return previousPromise =\n\t        // If enqueue has been called before, then we want to wait until\n\t        // all previous Promises have been resolved before calling invoke,\n\t        // so that results are always delivered in the correct order. If\n\t        // enqueue has not been called before, then it is important to\n\t        // call invoke immediately, without waiting on a callback to fire,\n\t        // so that the async generator function has the opportunity to do\n\t        // any necessary setup in a predictable way. This predictability\n\t        // is why the Promise constructor synchronously invokes its\n\t        // executor callback, and why async functions synchronously\n\t        // execute code before the first await. Since we implement simple\n\t        // async functions in terms of async generators, it is especially\n\t        // important to get this right, even though it requires care.\n\t        previousPromise ? previousPromise.then(\n\t          callInvokeWithMethodAndArg,\n\t          // Avoid propagating failures to Promises returned by later\n\t          // invocations of the iterator.\n\t          callInvokeWithMethodAndArg\n\t        ) : callInvokeWithMethodAndArg();\n\t    }\n\n\t    // Define the unified helper method that is used to implement .next,\n\t    // .throw, and .return (see defineIteratorMethods).\n\t    this._invoke = enqueue;\n\t  }\n\n\t  defineIteratorMethods(AsyncIterator.prototype);\n\t  AsyncIterator.prototype[asyncIteratorSymbol] = function () {\n\t    return this;\n\t  };\n\t  runtime.AsyncIterator = AsyncIterator;\n\n\t  // Note that simple async functions are implemented on top of\n\t  // AsyncIterator objects; they just return a Promise for the value of\n\t  // the final result produced by the iterator.\n\t  runtime.async = function(innerFn, outerFn, self, tryLocsList) {\n\t    var iter = new AsyncIterator(\n\t      wrap(innerFn, outerFn, self, tryLocsList)\n\t    );\n\n\t    return runtime.isGeneratorFunction(outerFn)\n\t      ? iter // If outerFn is a generator, return the full iterator.\n\t      : iter.next().then(function(result) {\n\t          return result.done ? result.value : iter.next();\n\t        });\n\t  };\n\n\t  function makeInvokeMethod(innerFn, self, context) {\n\t    var state = GenStateSuspendedStart;\n\n\t    return function invoke(method, arg) {\n\t      if (state === GenStateExecuting) {\n\t        throw new Error(\"Generator is already running\");\n\t      }\n\n\t      if (state === GenStateCompleted) {\n\t        if (method === \"throw\") {\n\t          throw arg;\n\t        }\n\n\t        // Be forgiving, per 25.3.3.3.3 of the spec:\n\t        // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume\n\t        return doneResult();\n\t      }\n\n\t      context.method = method;\n\t      context.arg = arg;\n\n\t      while (true) {\n\t        var delegate = context.delegate;\n\t        if (delegate) {\n\t          var delegateResult = maybeInvokeDelegate(delegate, context);\n\t          if (delegateResult) {\n\t            if (delegateResult === ContinueSentinel) continue;\n\t            return delegateResult;\n\t          }\n\t        }\n\n\t        if (context.method === \"next\") {\n\t          // Setting context._sent for legacy support of Babel's\n\t          // function.sent implementation.\n\t          context.sent = context._sent = context.arg;\n\n\t        } else if (context.method === \"throw\") {\n\t          if (state === GenStateSuspendedStart) {\n\t            state = GenStateCompleted;\n\t            throw context.arg;\n\t          }\n\n\t          context.dispatchException(context.arg);\n\n\t        } else if (context.method === \"return\") {\n\t          context.abrupt(\"return\", context.arg);\n\t        }\n\n\t        state = GenStateExecuting;\n\n\t        var record = tryCatch(innerFn, self, context);\n\t        if (record.type === \"normal\") {\n\t          // If an exception is thrown from innerFn, we leave state ===\n\t          // GenStateExecuting and loop back for another invocation.\n\t          state = context.done\n\t            ? GenStateCompleted\n\t            : GenStateSuspendedYield;\n\n\t          if (record.arg === ContinueSentinel) {\n\t            continue;\n\t          }\n\n\t          return {\n\t            value: record.arg,\n\t            done: context.done\n\t          };\n\n\t        } else if (record.type === \"throw\") {\n\t          state = GenStateCompleted;\n\t          // Dispatch the exception by looping back around to the\n\t          // context.dispatchException(context.arg) call above.\n\t          context.method = \"throw\";\n\t          context.arg = record.arg;\n\t        }\n\t      }\n\t    };\n\t  }\n\n\t  // Call delegate.iterator[context.method](context.arg) and handle the\n\t  // result, either by returning a { value, done } result from the\n\t  // delegate iterator, or by modifying context.method and context.arg,\n\t  // setting context.delegate to null, and returning the ContinueSentinel.\n\t  function maybeInvokeDelegate(delegate, context) {\n\t    var method = delegate.iterator[context.method];\n\t    if (method === undefined) {\n\t      // A .throw or .return when the delegate iterator has no .throw\n\t      // method always terminates the yield* loop.\n\t      context.delegate = null;\n\n\t      if (context.method === \"throw\") {\n\t        if (delegate.iterator.return) {\n\t          // If the delegate iterator has a return method, give it a\n\t          // chance to clean up.\n\t          context.method = \"return\";\n\t          context.arg = undefined;\n\t          maybeInvokeDelegate(delegate, context);\n\n\t          if (context.method === \"throw\") {\n\t            // If maybeInvokeDelegate(context) changed context.method from\n\t            // \"return\" to \"throw\", let that override the TypeError below.\n\t            return ContinueSentinel;\n\t          }\n\t        }\n\n\t        context.method = \"throw\";\n\t        context.arg = new TypeError(\n\t          \"The iterator does not provide a 'throw' method\");\n\t      }\n\n\t      return ContinueSentinel;\n\t    }\n\n\t    var record = tryCatch(method, delegate.iterator, context.arg);\n\n\t    if (record.type === \"throw\") {\n\t      context.method = \"throw\";\n\t      context.arg = record.arg;\n\t      context.delegate = null;\n\t      return ContinueSentinel;\n\t    }\n\n\t    var info = record.arg;\n\n\t    if (! info) {\n\t      context.method = \"throw\";\n\t      context.arg = new TypeError(\"iterator result is not an object\");\n\t      context.delegate = null;\n\t      return ContinueSentinel;\n\t    }\n\n\t    if (info.done) {\n\t      // Assign the result of the finished delegate to the temporary\n\t      // variable specified by delegate.resultName (see delegateYield).\n\t      context[delegate.resultName] = info.value;\n\n\t      // Resume execution at the desired location (see delegateYield).\n\t      context.next = delegate.nextLoc;\n\n\t      // If context.method was \"throw\" but the delegate handled the\n\t      // exception, let the outer generator proceed normally. If\n\t      // context.method was \"next\", forget context.arg since it has been\n\t      // \"consumed\" by the delegate iterator. If context.method was\n\t      // \"return\", allow the original .return call to continue in the\n\t      // outer generator.\n\t      if (context.method !== \"return\") {\n\t        context.method = \"next\";\n\t        context.arg = undefined;\n\t      }\n\n\t    } else {\n\t      // Re-yield the result returned by the delegate method.\n\t      return info;\n\t    }\n\n\t    // The delegate iterator is finished, so forget it and continue with\n\t    // the outer generator.\n\t    context.delegate = null;\n\t    return ContinueSentinel;\n\t  }\n\n\t  // Define Generator.prototype.{next,throw,return} in terms of the\n\t  // unified ._invoke helper method.\n\t  defineIteratorMethods(Gp);\n\n\t  Gp[toStringTagSymbol] = \"Generator\";\n\n\t  // A Generator should always return itself as the iterator object when the\n\t  // @@iterator function is called on it. Some browsers' implementations of the\n\t  // iterator prototype chain incorrectly implement this, causing the Generator\n\t  // object to not be returned from this call. This ensures that doesn't happen.\n\t  // See https://github.com/facebook/regenerator/issues/274 for more details.\n\t  Gp[iteratorSymbol] = function() {\n\t    return this;\n\t  };\n\n\t  Gp.toString = function() {\n\t    return \"[object Generator]\";\n\t  };\n\n\t  function pushTryEntry(locs) {\n\t    var entry = { tryLoc: locs[0] };\n\n\t    if (1 in locs) {\n\t      entry.catchLoc = locs[1];\n\t    }\n\n\t    if (2 in locs) {\n\t      entry.finallyLoc = locs[2];\n\t      entry.afterLoc = locs[3];\n\t    }\n\n\t    this.tryEntries.push(entry);\n\t  }\n\n\t  function resetTryEntry(entry) {\n\t    var record = entry.completion || {};\n\t    record.type = \"normal\";\n\t    delete record.arg;\n\t    entry.completion = record;\n\t  }\n\n\t  function Context(tryLocsList) {\n\t    // The root entry object (effectively a try statement without a catch\n\t    // or a finally block) gives us a place to store values thrown from\n\t    // locations where there is no enclosing try statement.\n\t    this.tryEntries = [{ tryLoc: \"root\" }];\n\t    tryLocsList.forEach(pushTryEntry, this);\n\t    this.reset(true);\n\t  }\n\n\t  runtime.keys = function(object) {\n\t    var keys = [];\n\t    for (var key in object) {\n\t      keys.push(key);\n\t    }\n\t    keys.reverse();\n\n\t    // Rather than returning an object with a next method, we keep\n\t    // things simple and return the next function itself.\n\t    return function next() {\n\t      while (keys.length) {\n\t        var key = keys.pop();\n\t        if (key in object) {\n\t          next.value = key;\n\t          next.done = false;\n\t          return next;\n\t        }\n\t      }\n\n\t      // To avoid creating an additional object, we just hang the .value\n\t      // and .done properties off the next function object itself. This\n\t      // also ensures that the minifier will not anonymize the function.\n\t      next.done = true;\n\t      return next;\n\t    };\n\t  };\n\n\t  function values(iterable) {\n\t    if (iterable) {\n\t      var iteratorMethod = iterable[iteratorSymbol];\n\t      if (iteratorMethod) {\n\t        return iteratorMethod.call(iterable);\n\t      }\n\n\t      if (typeof iterable.next === \"function\") {\n\t        return iterable;\n\t      }\n\n\t      if (!isNaN(iterable.length)) {\n\t        var i = -1, next = function next() {\n\t          while (++i < iterable.length) {\n\t            if (hasOwn.call(iterable, i)) {\n\t              next.value = iterable[i];\n\t              next.done = false;\n\t              return next;\n\t            }\n\t          }\n\n\t          next.value = undefined;\n\t          next.done = true;\n\n\t          return next;\n\t        };\n\n\t        return next.next = next;\n\t      }\n\t    }\n\n\t    // Return an iterator with no values.\n\t    return { next: doneResult };\n\t  }\n\t  runtime.values = values;\n\n\t  function doneResult() {\n\t    return { value: undefined, done: true };\n\t  }\n\n\t  Context.prototype = {\n\t    constructor: Context,\n\n\t    reset: function(skipTempReset) {\n\t      this.prev = 0;\n\t      this.next = 0;\n\t      // Resetting context._sent for legacy support of Babel's\n\t      // function.sent implementation.\n\t      this.sent = this._sent = undefined;\n\t      this.done = false;\n\t      this.delegate = null;\n\n\t      this.method = \"next\";\n\t      this.arg = undefined;\n\n\t      this.tryEntries.forEach(resetTryEntry);\n\n\t      if (!skipTempReset) {\n\t        for (var name in this) {\n\t          // Not sure about the optimal order of these conditions:\n\t          if (name.charAt(0) === \"t\" &&\n\t              hasOwn.call(this, name) &&\n\t              !isNaN(+name.slice(1))) {\n\t            this[name] = undefined;\n\t          }\n\t        }\n\t      }\n\t    },\n\n\t    stop: function() {\n\t      this.done = true;\n\n\t      var rootEntry = this.tryEntries[0];\n\t      var rootRecord = rootEntry.completion;\n\t      if (rootRecord.type === \"throw\") {\n\t        throw rootRecord.arg;\n\t      }\n\n\t      return this.rval;\n\t    },\n\n\t    dispatchException: function(exception) {\n\t      if (this.done) {\n\t        throw exception;\n\t      }\n\n\t      var context = this;\n\t      function handle(loc, caught) {\n\t        record.type = \"throw\";\n\t        record.arg = exception;\n\t        context.next = loc;\n\n\t        if (caught) {\n\t          // If the dispatched exception was caught by a catch block,\n\t          // then let that catch block handle the exception normally.\n\t          context.method = \"next\";\n\t          context.arg = undefined;\n\t        }\n\n\t        return !! caught;\n\t      }\n\n\t      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n\t        var entry = this.tryEntries[i];\n\t        var record = entry.completion;\n\n\t        if (entry.tryLoc === \"root\") {\n\t          // Exception thrown outside of any try block that could handle\n\t          // it, so set the completion value of the entire function to\n\t          // throw the exception.\n\t          return handle(\"end\");\n\t        }\n\n\t        if (entry.tryLoc <= this.prev) {\n\t          var hasCatch = hasOwn.call(entry, \"catchLoc\");\n\t          var hasFinally = hasOwn.call(entry, \"finallyLoc\");\n\n\t          if (hasCatch && hasFinally) {\n\t            if (this.prev < entry.catchLoc) {\n\t              return handle(entry.catchLoc, true);\n\t            } else if (this.prev < entry.finallyLoc) {\n\t              return handle(entry.finallyLoc);\n\t            }\n\n\t          } else if (hasCatch) {\n\t            if (this.prev < entry.catchLoc) {\n\t              return handle(entry.catchLoc, true);\n\t            }\n\n\t          } else if (hasFinally) {\n\t            if (this.prev < entry.finallyLoc) {\n\t              return handle(entry.finallyLoc);\n\t            }\n\n\t          } else {\n\t            throw new Error(\"try statement without catch or finally\");\n\t          }\n\t        }\n\t      }\n\t    },\n\n\t    abrupt: function(type, arg) {\n\t      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n\t        var entry = this.tryEntries[i];\n\t        if (entry.tryLoc <= this.prev &&\n\t            hasOwn.call(entry, \"finallyLoc\") &&\n\t            this.prev < entry.finallyLoc) {\n\t          var finallyEntry = entry;\n\t          break;\n\t        }\n\t      }\n\n\t      if (finallyEntry &&\n\t          (type === \"break\" ||\n\t           type === \"continue\") &&\n\t          finallyEntry.tryLoc <= arg &&\n\t          arg <= finallyEntry.finallyLoc) {\n\t        // Ignore the finally entry if control is not jumping to a\n\t        // location outside the try/catch block.\n\t        finallyEntry = null;\n\t      }\n\n\t      var record = finallyEntry ? finallyEntry.completion : {};\n\t      record.type = type;\n\t      record.arg = arg;\n\n\t      if (finallyEntry) {\n\t        this.method = \"next\";\n\t        this.next = finallyEntry.finallyLoc;\n\t        return ContinueSentinel;\n\t      }\n\n\t      return this.complete(record);\n\t    },\n\n\t    complete: function(record, afterLoc) {\n\t      if (record.type === \"throw\") {\n\t        throw record.arg;\n\t      }\n\n\t      if (record.type === \"break\" ||\n\t          record.type === \"continue\") {\n\t        this.next = record.arg;\n\t      } else if (record.type === \"return\") {\n\t        this.rval = this.arg = record.arg;\n\t        this.method = \"return\";\n\t        this.next = \"end\";\n\t      } else if (record.type === \"normal\" && afterLoc) {\n\t        this.next = afterLoc;\n\t      }\n\n\t      return ContinueSentinel;\n\t    },\n\n\t    finish: function(finallyLoc) {\n\t      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n\t        var entry = this.tryEntries[i];\n\t        if (entry.finallyLoc === finallyLoc) {\n\t          this.complete(entry.completion, entry.afterLoc);\n\t          resetTryEntry(entry);\n\t          return ContinueSentinel;\n\t        }\n\t      }\n\t    },\n\n\t    \"catch\": function(tryLoc) {\n\t      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n\t        var entry = this.tryEntries[i];\n\t        if (entry.tryLoc === tryLoc) {\n\t          var record = entry.completion;\n\t          if (record.type === \"throw\") {\n\t            var thrown = record.arg;\n\t            resetTryEntry(entry);\n\t          }\n\t          return thrown;\n\t        }\n\t      }\n\n\t      // The context.catch method must only be called with a location\n\t      // argument that corresponds to a known catch block.\n\t      throw new Error(\"illegal catch attempt\");\n\t    },\n\n\t    delegateYield: function(iterable, resultName, nextLoc) {\n\t      this.delegate = {\n\t        iterator: values(iterable),\n\t        resultName: resultName,\n\t        nextLoc: nextLoc\n\t      };\n\n\t      if (this.method === \"next\") {\n\t        // Deliberately forget the last sent value so that we don't\n\t        // accidentally pass it on to the delegate.\n\t        this.arg = undefined;\n\t      }\n\n\t      return ContinueSentinel;\n\t    }\n\t  };\n\t})(\n\t  // In sloppy mode, unbound `this` refers to the global object, fallback to\n\t  // Function constructor if we're in global strict mode. That is sadly a form\n\t  // of indirect eval which violates Content Security Policy.\n\t  (function() { return this })() || Function(\"return this\")()\n\t);\n\t});\n\n\t/**\n\t * Copyright (c) 2014-present, Facebook, Inc.\n\t *\n\t * This source code is licensed under the MIT license found in the\n\t * LICENSE file in the root directory of this source tree.\n\t */\n\n\t// This method of obtaining a reference to the global object needs to be\n\t// kept identical to the way it is obtained in runtime.js\n\tvar g = (function() { return this })() || Function(\"return this\")();\n\n\t// Use `getOwnPropertyNames` because not all browsers support calling\n\t// `hasOwnProperty` on the global `self` object in a worker. See #183.\n\tvar hadRuntime = g.regeneratorRuntime &&\n\t  Object.getOwnPropertyNames(g).indexOf(\"regeneratorRuntime\") >= 0;\n\n\t// Save the old regeneratorRuntime in case it needs to be restored later.\n\tvar oldRuntime = hadRuntime && g.regeneratorRuntime;\n\n\t// Force reevalutation of runtime.js.\n\tg.regeneratorRuntime = undefined;\n\n\tvar runtimeModule = runtime;\n\n\tif (hadRuntime) {\n\t  // Restore the original runtime.\n\t  g.regeneratorRuntime = oldRuntime;\n\t} else {\n\t  // Remove the global property added by runtime.js.\n\t  try {\n\t    delete g.regeneratorRuntime;\n\t  } catch(e) {\n\t    g.regeneratorRuntime = undefined;\n\t  }\n\t}\n\n\tvar regenerator = runtimeModule;\n\n\tvar defaultOptions = {\n\t  mode: 'index'\n\t};\n\n\tmodule.exports = /*#__PURE__*/regenerator.mark(function _callee(M, N, options) {\n\t  var a, c, b, p, x, y, z, i, twiddle;\n\t  return regenerator.wrap(function _callee$(_context) {\n\t    while (1) {\n\t      switch (_context.prev = _context.next) {\n\t        case 0:\n\t          twiddle = function twiddle() {\n\t            var i, j, k;\n\t            j = 1;\n\t            while (p[j] <= 0) {\n\t              j++;\n\t            }\n\t            if (p[j - 1] === 0) {\n\t              for (i = j - 1; i !== 1; i--) {\n\t                p[i] = -1;\n\t              }\n\t              p[j] = 0;\n\t              x = z = 0;\n\t              p[1] = 1;\n\t              y = j - 1;\n\t            } else {\n\t              if (j > 1) {\n\t                p[j - 1] = 0;\n\t              }\n\t              do {\n\t                j++;\n\t              } while (p[j] > 0);\n\t              k = j - 1;\n\t              i = j;\n\t              while (p[i] === 0) {\n\t                p[i++] = -1;\n\t              }\n\t              if (p[i] === -1) {\n\t                p[i] = p[k];\n\t                z = p[k] - 1;\n\t                x = i - 1;\n\t                y = k - 1;\n\t                p[k] = -1;\n\t              } else {\n\t                if (i === p[0]) {\n\t                  return 0;\n\t                } else {\n\t                  p[j] = p[i];\n\t                  z = p[i] - 1;\n\t                  p[i] = 0;\n\t                  x = j - 1;\n\t                  y = i - 1;\n\t                }\n\t              }\n\t            }\n\t            return 1;\n\t          };\n\n\t          options = Object.assign({}, defaultOptions, options);\n\t          a = new Array(N);\n\t          c = new Array(M);\n\t          b = new Array(N);\n\t          p = new Array(N + 2);\n\n\n\t          // init a and b\n\t          for (i = 0; i < N; i++) {\n\t            a[i] = i;\n\t            if (i < N - M) b[i] = 0;else b[i] = 1;\n\t          }\n\n\t          // init c\n\t          for (i = 0; i < M; i++) {\n\t            c[i] = N - M + i;\n\t          }\n\n\t          // init p\n\t          for (i = 0; i < p.length; i++) {\n\t            if (i === 0) p[i] = N + 1;else if (i <= N - M) p[i] = 0;else if (i <= N) p[i] = i - N + M;else p[i] = -2;\n\t          }\n\n\t          if (!(options.mode === 'index')) {\n\t            _context.next = 20;\n\t            break;\n\t          }\n\n\t          _context.next = 12;\n\t          return c.slice();\n\n\t        case 12:\n\t          if (!twiddle()) {\n\t            _context.next = 18;\n\t            break;\n\t          }\n\n\t          c[z] = a[x];\n\t          _context.next = 16;\n\t          return c.slice();\n\n\t        case 16:\n\t          _context.next = 12;\n\t          break;\n\n\t        case 18:\n\t          _context.next = 33;\n\t          break;\n\n\t        case 20:\n\t          if (!(options.mode === 'mask')) {\n\t            _context.next = 32;\n\t            break;\n\t          }\n\n\t          _context.next = 23;\n\t          return b.slice();\n\n\t        case 23:\n\t          if (!twiddle()) {\n\t            _context.next = 30;\n\t            break;\n\t          }\n\n\t          b[x] = 1;\n\t          b[y] = 0;\n\t          _context.next = 28;\n\t          return b.slice();\n\n\t        case 28:\n\t          _context.next = 23;\n\t          break;\n\n\t        case 30:\n\t          _context.next = 33;\n\t          break;\n\n\t        case 32:\n\t          throw new Error('Invalid mode');\n\n\t        case 33:\n\t        case 'end':\n\t          return _context.stop();\n\t      }\n\t    }\n\t  }, _callee, this);\n\t});\n\n})));\n","// eslint-disable-next-line @typescript-eslint/unbound-method\nconst toString = Object.prototype.toString;\n/**\n * Checks if an object is an instance of an Array (array or typed array, except those that contain bigint values).\n *\n * @param value - Object to check.\n * @returns True if the object is an array or a typed array.\n */\nexport function isAnyArray(value) {\n    const tag = toString.call(value);\n    return tag.endsWith('Array]') && !tag.includes('Big');\n}\n//# sourceMappingURL=index.js.map","import { isAnyArray } from 'is-any-array';\n\nfunction sum(input) {\n  if (!isAnyArray(input)) {\n    throw new TypeError('input must be an array');\n  }\n\n  if (input.length === 0) {\n    throw new TypeError('input must not be empty');\n  }\n\n  var sumValue = 0;\n\n  for (var i = 0; i < input.length; i++) {\n    sumValue += input[i];\n  }\n\n  return sumValue;\n}\n\nexport { sum as default };\n","import mean from 'ml-array-mean';\n/**\n * Returns the Area under the curve.\n * @param curves Object containing the true positivie and false positive rate vectors.\n * @return Area under the curve.\n */\nexport function getAuc(curves) {\n    const auc = [];\n    for (const curve of curves) {\n        let area = 0;\n        const x = curve.specificities;\n        const y = curve.sensitivities;\n        for (let i = 1; i < x.length; i++) {\n            area += 0.5 * (x[i] - x[i - 1]) * (y[i] + y[i - 1]);\n        }\n        area = area > 0.5 ? area : 1 - area;\n        auc.push(area);\n    }\n    return mean(auc);\n}\n//# sourceMappingURL=getAuc.js.map","import sum from 'ml-array-sum';\n\nfunction mean(input) {\n  return sum(input) / input.length;\n}\n\nexport { mean as default };\n","import { getThresholds } from './utilities/getThresholds';\n/**\n * Returns a ROC (Receiver Operating Characteristic) curve for a given response and prediction vectors.\n * @param responses Array containing category metadata.\n * @param predictions Array containing the results of regression.\n * @return sensitivities and specificities as a object.\n */\nexport function getBinaryClassifiers(responses, predictions) {\n    const limits = getThresholds(predictions);\n    const truePositives = [];\n    const falsePositives = [];\n    const trueNegatives = [];\n    const falseNegatives = [];\n    for (const limit of limits) {\n        let truePositive = 0;\n        let falsePositive = 0;\n        let trueNegative = 0;\n        let falseNegative = 0;\n        const category = responses[0];\n        for (let j = 0; j < responses.length; j++) {\n            if (responses[j] !== category && predictions[j] > limit)\n                truePositive++;\n            if (responses[j] === category && predictions[j] > limit)\n                falsePositive++;\n            if (responses[j] === category && predictions[j] < limit)\n                trueNegative++;\n            if (responses[j] !== category && predictions[j] < limit)\n                falseNegative++;\n        }\n        truePositives.push(truePositive);\n        falsePositives.push(falsePositive);\n        trueNegatives.push(trueNegative);\n        falseNegatives.push(falseNegative);\n    }\n    return {\n        truePositives,\n        falsePositives,\n        trueNegatives,\n        falseNegatives,\n    };\n}\n//# sourceMappingURL=getBinaryClassifiers.js.map","/**\n * Returns an array of thresholds to build the curve.\n * @param predictions Array of predictions.\n * @return An array of thresholds.\n */\nexport function getThresholds(predictions) {\n    const uniques = [...new Set(predictions)].sort((a, b) => a - b);\n    const thresholds = [Number.NEGATIVE_INFINITY];\n    for (let i = 0; i < uniques.length - 1; i++) {\n        const half = (uniques[i + 1] - uniques[i]) / 2;\n        thresholds.push(uniques[i] + half);\n    }\n    thresholds.push(Number.POSITIVE_INFINITY);\n    return thresholds;\n}\n//# sourceMappingURL=getThresholds.js.map","/**\n * @param array Array containing category metadata\n * @return Class object.\n */\nexport function getClasses(array) {\n    let nbClasses = 0;\n    const classes = [{ name: array[0], value: 0, ids: [] }];\n    for (const element of array) {\n        const currentClass = classes.some((item) => item.name === element);\n        if (!currentClass) {\n            nbClasses++;\n            classes.push({ name: element, value: nbClasses, ids: [] });\n        }\n    }\n    for (const category of classes) {\n        const label = category.name;\n        const indexes = [];\n        for (let j = 0; j < array.length; j++) {\n            if (array[j] === label)\n                indexes.push(j);\n        }\n        category.ids = indexes;\n    }\n    return classes;\n}\n//# sourceMappingURL=getClasses.js.map","/**\n * Returns the array of metadata numerically categorized.\n * @param array Array containing the categories.\n * @param pair Object containing information about the two classes to deal with.\n * @return Array containing the prediction values arranged for the corresponding classes.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function getSelectedResults(array, pair) {\n    const results = [];\n    for (const item of pair) {\n        for (const id of item.ids) {\n            const result = array[id];\n            results.push(result);\n        }\n    }\n    return results;\n}\n//# sourceMappingURL=getSelectedResults.js.map","import { getBinaryClassifiers } from './getBinaryClassifiers';\nimport { getClasses } from './utilities/getClasses';\nimport { getClassesPairs } from './utilities/getClassesPairs';\nimport { getSelectedResults } from './utilities/getSelectedResults';\n/**\n * Returns a ROC (Receiver Operating Characteristic) curve for a given response and prediction vectors.\n * @param responses Array containing category metadata.\n * @param predictions Array containing the results of regression.\n * @return sensitivities and specificities as a object.\n */\nexport function getRocCurve(responses, predictions) {\n    const classes = getClasses(responses);\n    const pairsOfClasses = getClassesPairs(classes);\n    const curves = [];\n    for (const pairs of pairsOfClasses) {\n        const tests = getSelectedResults(predictions, pairs);\n        const targets = getSelectedResults(responses, pairs);\n        const { truePositives, falsePositives, trueNegatives, falseNegatives } = getBinaryClassifiers(targets, tests);\n        const curve = { sensitivities: [], specificities: [] };\n        for (let i = 0; i < truePositives.length; i++) {\n            curve.sensitivities.push(truePositives[i] / (truePositives[i] + falseNegatives[i]));\n            curve.specificities.push(trueNegatives[i] / (falsePositives[i] + trueNegatives[i]));\n        }\n        curves.push(curve);\n    }\n    return curves;\n}\n//# sourceMappingURL=getRocCurve.js.map","/**\n * Returns an array of pairs of classes.\n * @param list Array containing a list of classes.\n * @return Array with pairs of classes.\n */\nexport function getClassesPairs(list) {\n    const pairs = [];\n    for (let i = 0; i < list.length - 1; i++) {\n        for (let j = i + 1; j < list.length; j++) {\n            pairs.push([list[i], list[j]]);\n        }\n    }\n    return pairs;\n}\n//# sourceMappingURL=getClassesPairs.js.map","import { Matrix, NIPALS } from 'ml-matrix';\n/**\n * Single OPLS (orthogonal projections to latent structures) NIPALS iteration.\n * Computes the predictive and Y-orthogonal components and returns the data with\n * the orthogonal variation filtered out.\n * @param {Array|Matrix} data - matrix with features (X).\n * @param {Array|Matrix} labels - an array of labels (dependent variable Y).\n * @param {object} [options={}] - an object with options.\n * @param {number} [options.numberOSC=1000] - maximum number of NIPALS iterations.\n * @param {number} [options.limit=1e-10] - convergence threshold used to stop the iteration.\n * @returns {object} the computed model with the following properties:\n * - `filteredX`: X with the orthogonal component removed.\n * - `weightsXOrtho`: Y-orthogonal weights of X.\n * - `loadingsXOrtho`: Y-orthogonal loadings of X.\n * - `scoresXOrtho`: Y-orthogonal scores of X.\n * - `weightsXPred`: predictive weights of X.\n * - `loadingsXpred`: predictive loadings of X.\n * - `scoresXpred`: predictive scores of X.\n * - `loadingsY`: loadings of Y.\n */\nexport function oplsNipals(data, labels, options = {}) {\n    const { numberOSC = 1000, limit = 1e-10 } = options;\n    data = Matrix.checkMatrix(data);\n    labels = Matrix.checkMatrix(labels);\n    let tW = [];\n    if (labels.columns > 1) {\n        const wh = getWh(data, labels);\n        const ssWh = wh.norm() ** 2;\n        let ssT = ssWh;\n        let pcaW;\n        let count = 0;\n        do {\n            if (count === 0) {\n                pcaW = new NIPALS(wh.clone());\n                tW.push(pcaW.t);\n            }\n            else {\n                const data = pcaW.xResidual;\n                pcaW = new NIPALS(data);\n                tW.push(pcaW.t);\n            }\n            ssT = pcaW.t.norm() ** 2;\n            count++;\n        } while (ssT / ssWh > limit);\n    }\n    let u = labels.getColumnVector(0);\n    let diff = 1;\n    let t, c, w, uNew;\n    for (let i = 0; i < numberOSC && diff > limit; i++) {\n        w = u\n            .transpose()\n            .mmul(data)\n            .div(u.norm() ** 2);\n        w = w.transpose().div(w.norm());\n        t = data.mmul(w).div(w.norm() ** 2); // t_h paso 3\n        // calc loading\n        c = t\n            .transpose()\n            .mmul(labels)\n            .div(t.norm() ** 2);\n        // calc new u and compare with one in previus iteration (stop criterion)\n        uNew = labels.mmul(c.transpose()).div(c.norm() ** 2);\n        if (i > 0) {\n            // same value as uNew.clone().sub(u).pow(2).sum() / uNew.clone().pow(2).sum()\n            // but without allocating three full-vector clones per iteration.\n            let numerator = 0;\n            let denominator = 0;\n            for (let row = 0; row < uNew.rows; row++) {\n                const newValue = uNew.get(row, 0);\n                const delta = newValue - u.get(row, 0);\n                numerator += delta * delta;\n                denominator += newValue * newValue;\n            }\n            diff = numerator / denominator;\n        }\n        // uNew is reassigned to a fresh matrix next iteration, so a reference is safe.\n        u = uNew;\n    }\n    // calc loadings\n    let wOrtho;\n    let p = t\n        .transpose()\n        .mmul(data)\n        .div(t.norm() ** 2);\n    if (labels.columns > 1) {\n        for (let i = 0; i < tW.length - 1; i++) {\n            let tw = tW[i].transpose();\n            p = p.sub(tw\n                .mmul(p.transpose())\n                .div(tw.norm() ** 2)\n                .mmul(tw));\n        }\n        wOrtho = p.clone();\n    }\n    else {\n        wOrtho = p.clone().sub(w\n            .transpose()\n            .mmul(p.transpose())\n            .div(w.norm() ** 2)\n            .mmul(w.transpose()));\n    }\n    wOrtho.div(wOrtho.norm());\n    let tOrtho = data.mmul(wOrtho.transpose()).div(wOrtho.norm() ** 2);\n    // orthogonal loadings\n    let pOrtho = tOrtho\n        .transpose()\n        .mmul(data)\n        .div(tOrtho.norm() ** 2);\n    // filtered data\n    let err = data.clone().sub(tOrtho.mmul(pOrtho));\n    return {\n        filteredX: err,\n        weightsXOrtho: wOrtho,\n        loadingsXOrtho: pOrtho,\n        scoresXOrtho: tOrtho,\n        weightsXPred: w,\n        loadingsXpred: p,\n        scoresXpred: t,\n        loadingsY: c,\n    };\n}\n/**\n * Computes the W matrix used to initialize the orthogonal loop for multi-column Y.\n * @private\n * @param {Matrix} xValue - the feature matrix (X).\n * @param {Matrix} yValue - the label matrix (Y).\n * @returns {Matrix} the W matrix (one column per Y variable).\n */\nfunction getWh(xValue, yValue) {\n    let result = new Matrix(xValue.columns, yValue.columns);\n    for (let i = 0; i < yValue.columns; i++) {\n        let yN = yValue.getColumnVector(i).transpose();\n        let component = yN.mmul(xValue).div(yN.norm() ** 2);\n        result.setColumn(i, component.getRow(0));\n    }\n    return result;\n}\n//# sourceMappingURL=oplsNipals.js.map","/**\n * Computes the per-column standard deviations of a matrix, replacing any zero\n * (a constant column) by `1`.\n *\n * Scaling a column by its standard deviation is a division; for a constant\n * column the standard deviation is `0`, so the division yields `Infinity`/`NaN`\n * which then poisons every downstream computation. Replacing the zero by `1`\n * leaves the already-centered constant column at all-zeros, which is the\n * neutral, information-free contribution expected from such a column.\n * @private\n * @param {import('ml-matrix').Matrix} matrix - the matrix whose columns are scaled.\n * @returns {number[]} the per-column standard deviations, with every zero replaced by `1`.\n */\nexport function getSafeStandardDeviations(matrix) {\n    const standardDeviations = matrix.standardDeviation('column');\n    for (let i = 0; i < standardDeviations.length; i++) {\n        if (standardDeviations[i] === 0)\n            standardDeviations[i] = 1;\n    }\n    return standardDeviations;\n}\n//# sourceMappingURL=getSafeStandardDeviations.js.map","import { Matrix } from 'ml-matrix';\n/**\n * Get total sum of square\n * @param {Array} x - an array\n * @returns {number} - the sum of the squares\n */\nexport function tss(x) {\n    return Matrix.mul(x, x).sum();\n}\n//# sourceMappingURL=tss.js.map","import { isAnyArray } from 'is-any-array';\nimport { ConfusionMatrix } from 'ml-confusion-matrix';\nimport { getFolds } from 'ml-cross-validation';\nimport { Matrix, NIPALS } from 'ml-matrix';\nimport { getAuc, getClasses, getRocCurve } from 'ml-roc-multiclass';\nimport { oplsNipals } from './oplsNipals.js';\nimport { getSafeStandardDeviations } from './util/getSafeStandardDeviations.js';\nimport { tss } from './util/tss.js';\n/**\n * OPLS (orthogonal projections to latent structures).\n */\nexport class OPLS {\n    /**\n     * Creates a new OPLS model from features and labels.\n     * @param {Array} data - matrix containing data (X).\n     * @param {Array} labels - 1D Array containing metadata (Y). Numeric labels trigger regression, string labels trigger discriminant analysis.\n     * @param {object} [options={}] - constructor options.\n     * @param {boolean} [options.center=true] - should the data be centered (subtract the mean).\n     * @param {boolean} [options.scale=true] - should the data be scaled (divide by the standard deviation).\n     * @param {Array} [options.cvFolds=[]] - Allows to provide folds as array of objects with the arrays trainIndex and testIndex as properties.\n     * @param {number} [options.nbFolds=7] - Allows to generate the defined number of folds with the training and test set chosen randomly from the data set.\n     * @param {number} [options.maxComponents=min(rows - 1, columns)] - upper bound on the number of orthogonal components. The fit normally stops earlier (when adding a component no longer improves the cross-validated metric by at least 0.05); this is a hard cap that guarantees termination even when the metric never plateaus.\n     */\n    constructor(data, labels, options = {}) {\n        if (data === true) {\n            const opls = options;\n            this.labels = opls.labels;\n            this.center = opls.center;\n            this.scale = opls.scale;\n            this.means = opls.means;\n            this.meansY = opls.meansY;\n            this.stdevs = opls.stdevs;\n            this.stdevsY = opls.stdevsY;\n            this.model = opls.model;\n            this.predictiveScoresCV = opls.predictiveScoresCV;\n            this.orthogonalScoresCV = opls.orthogonalScoresCV;\n            this.yHatScoresCV = opls.yHatScoresCV;\n            this.mode = opls.mode;\n            this.output = opls.output;\n            return;\n        }\n        const features = new Matrix(data);\n        // set default values\n        // cvFolds allows to define folds for testing purpose\n        const { center = true, scale = true, cvFolds = [], nbFolds = 7, maxComponents = Math.min(features.rows - 1, features.columns), } = options;\n        this.labels = labels;\n        // a constant Y has zero variance: it cannot define a direction to model and\n        // would silently produce NaN once scaled. Fail loudly instead of hiding it.\n        if (new Set(labels).size < 2) {\n            throw new RangeError('labels must contain at least two distinct values; a constant Y has zero variance and cannot fit an OPLS model');\n        }\n        let group;\n        if (typeof labels[0] === 'number') {\n            // numeric labels: OPLS regression is used\n            this.mode = 'regression';\n            group = Matrix.from1DArray(labels.length, 1, labels);\n        }\n        else if (typeof labels[0] === 'string') {\n            // non-numeric labels: OPLS-DA is used\n            this.mode = 'discriminantAnalysis';\n            group = Matrix.checkMatrix(createDummyY(labels)).transpose();\n        }\n        // getting center and scale the features (all)\n        this.center = center;\n        if (this.center) {\n            this.means = features.mean('column');\n            this.meansY = group.mean('column');\n        }\n        else {\n            this.stdevs = null;\n        }\n        this.scale = scale;\n        if (this.scale) {\n            // constant columns (sd = 0) would divide by zero when scaling and produce\n            // NaN; getSafeStandardDeviations replaces those zeros by 1 (check opls.R line 70).\n            this.stdevs = getSafeStandardDeviations(features);\n            this.stdevsY = getSafeStandardDeviations(group);\n        }\n        else {\n            this.means = null;\n        }\n        const folds = cvFolds.length > 0 ? cvFolds : getFolds(labels, nbFolds);\n        const Q2 = [];\n        const aucResult = [];\n        this.model = [];\n        this.predictiveScoresCV = [];\n        this.orthogonalScoresCV = [];\n        this.yHatScoresCV = [];\n        const oplsCV = [];\n        let modelNC = [];\n        // this code could be made more efficient by reverting the order of the loops\n        // this is a legacy loop to be consistent with R code from MetaboMate package\n        // this allows for having statistic (R2) from CV to decide wether to continue\n        // with more latent structures\n        let overfitted = false;\n        let nc = 0;\n        let value;\n        do {\n            const yHatk = new Matrix(group.rows, 1);\n            const predictiveScoresK = new Matrix(group.rows, 1);\n            const orthogonalScoresK = new Matrix(group.rows, 1);\n            oplsCV[nc] = [];\n            for (let f = 0; f < folds.length; f++) {\n                const trainTest = this._getTrainTest(features, group, folds[f]);\n                const testFeatures = trainTest.testFeatures;\n                const trainFeatures = trainTest.trainFeatures;\n                const trainLabels = trainTest.trainLabels;\n                // determine center and scale of training set\n                const dataCenter = trainFeatures.mean('column');\n                const dataSD = getSafeStandardDeviations(trainFeatures);\n                // center and scale training set. trainFeatures is only consumed for the\n                // first component; later components run oplsNipals on the stored\n                // filteredX, so centering/scaling trainFeatures again would be dead work.\n                if (center) {\n                    if (nc === 0)\n                        trainFeatures.center('column');\n                    trainLabels.center('column');\n                }\n                if (scale) {\n                    if (nc === 0) {\n                        // std computed after centering to stay bit-identical to the previous\n                        // internal scale('column'); sanitized to avoid dividing by a zero sd.\n                        trainFeatures.scale('column', {\n                            scale: getSafeStandardDeviations(trainFeatures),\n                        });\n                    }\n                    trainLabels.scale('column');\n                }\n                // perform opls\n                let oplsk;\n                if (nc === 0) {\n                    oplsk = oplsNipals(trainFeatures, trainLabels);\n                }\n                else {\n                    oplsk = oplsNipals(oplsCV[nc - 1][f].filteredX, trainLabels);\n                }\n                // store model for next component\n                oplsCV[nc][f] = oplsk;\n                const plsCV = new NIPALS(oplsk.filteredX, { Y: trainLabels });\n                // scaling the test dataset with respect to the train\n                testFeatures.center('column', { center: dataCenter });\n                testFeatures.scale('column', { scale: dataSD });\n                const Eh = testFeatures;\n                // removing the orthogonal components from PLS\n                let scores;\n                for (let idx = 0; idx < nc + 1; idx++) {\n                    scores = Eh.mmul(oplsCV[idx][f].weightsXOrtho.transpose()); // ok\n                    Eh.sub(scores.mmul(oplsCV[idx][f].loadingsXOrtho));\n                }\n                // prediction\n                const predictiveComponents = Eh.mmul(plsCV.w.transpose());\n                const yHatComponents = predictiveComponents\n                    .mmul(plsCV.betas)\n                    .mmul(plsCV.q.transpose()); // ok\n                const yHat = new Matrix(yHatComponents.rows, 1);\n                for (let i = 0; i < yHatComponents.rows; i++) {\n                    yHat.setRow(i, [yHatComponents.getRowVector(i).sum()]);\n                }\n                // adding all prediction from all folds\n                for (let i = 0; i < folds[f].testIndex.length; i++) {\n                    yHatk.setRow(folds[f].testIndex[i], [yHat.get(i, 0)]);\n                    predictiveScoresK.setRow(folds[f].testIndex[i], [\n                        predictiveComponents.get(i, 0),\n                    ]);\n                    orthogonalScoresK.setRow(folds[f].testIndex[i], [scores.get(i, 0)]);\n                }\n            } // end of loop over folds\n            this.predictiveScoresCV.push(predictiveScoresK);\n            this.orthogonalScoresCV.push(orthogonalScoresK);\n            this.yHatScoresCV.push(yHatk);\n            // calculate Q2y for all the prediction (all folds)\n            // ROC for DA is not implemented (check opls.R line 183) TODO\n            const tssy = tss(group.center('column').scale('column'));\n            let press = 0;\n            for (let i = 0; i < group.columns; i++) {\n                press += tss(group.getColumnVector(i).sub(yHatk));\n            }\n            const Q2y = 1 - press / group.columns / tssy;\n            Q2.push(Q2y);\n            if (this.mode === 'regression') {\n                value = Q2y;\n            }\n            else if (this.mode === 'discriminantAnalysis') {\n                const rocCurve = getRocCurve(labels, yHatk.to1DArray());\n                const areaUnderCurve = getAuc(rocCurve);\n                aucResult.push(areaUnderCurve);\n                value = areaUnderCurve;\n            }\n            // calculate the R2y for the complete data\n            if (nc === 0) {\n                modelNC = this._predictAll(features, group);\n            }\n            else {\n                modelNC = this._predictAll(modelNC.xRes, group, {\n                    scale: false,\n                    center: false,\n                });\n            }\n            // adding the predictive statistics from CV\n            let listOfValues;\n            modelNC.Q2y = Q2;\n            if (this.mode === 'regression') {\n                listOfValues = Q2;\n            }\n            else {\n                listOfValues = aucResult;\n                modelNC.auc = aucResult;\n            }\n            modelNC.value = value;\n            if (nc > 0) {\n                // a non-finite metric means the fit degenerated; stop rather than keep\n                // adding components until the maxComponents cap.\n                overfitted =\n                    !Number.isFinite(value) || value - listOfValues[nc - 1] < 0.05;\n            }\n            this.model.push(modelNC);\n            // store the model for each component\n            nc++;\n            // console.warn(`OPLS iteration over # of Components: ${nc + 1}`);\n        } while (!overfitted && nc < maxComponents); // end of loop over nc\n        // store scores from CV\n        const predictiveScoresCV = this.predictiveScoresCV;\n        const orthogonalScoresCV = this.orthogonalScoresCV;\n        const yHatScoresCV = this.yHatScoresCV;\n        const m = this.model[nc - 1];\n        const orthogonalData = new Matrix(features.rows, features.columns);\n        const orthogonalScores = new Matrix(features.rows, nc - 1);\n        const orthogonalLoadings = new Matrix(nc - 1, features.columns);\n        const orthogonalWeights = new Matrix(nc - 1, features.columns);\n        for (let i = 0; i < this.model.length - 1; i++) {\n            orthogonalData.add(this.model[i].XOrth);\n            orthogonalScores.setSubMatrix(this.model[i].orthogonalScores, 0, i);\n            orthogonalLoadings.setSubMatrix(this.model[i].orthogonalLoadings, i, 0);\n            orthogonalWeights.setSubMatrix(this.model[i].orthogonalWeights, i, 0);\n        }\n        const FeaturesCS = features.center('column');\n        FeaturesCS.scale('column', {\n            scale: getSafeStandardDeviations(FeaturesCS),\n        });\n        let labelsCS;\n        if (this.mode === 'regression') {\n            labelsCS = group.clone().center('column').scale('column');\n        }\n        else {\n            labelsCS = group;\n        }\n        const orthogonalizedData = FeaturesCS.clone().sub(orthogonalData);\n        const plsCall = new NIPALS(orthogonalizedData, { Y: labelsCS });\n        const residualData = orthogonalizedData\n            .clone()\n            .sub(plsCall.t.mmul(plsCall.p));\n        const R2x = this.model.map((x) => x.R2x);\n        const R2y = this.model.map((x) => x.R2y);\n        this.output = {\n            Q2y: Q2,\n            auc: aucResult,\n            R2x,\n            R2y,\n            predictiveComponents: plsCall.t,\n            predictiveLoadings: plsCall.p,\n            predictiveWeights: plsCall.w,\n            betas: plsCall.betas,\n            Qpc: plsCall.q,\n            predictiveScoresCV,\n            orthogonalScoresCV,\n            yHatScoresCV,\n            oplsCV,\n            orthogonalScores,\n            orthogonalLoadings,\n            orthogonalWeights,\n            Xorth: orthogonalData,\n            yHat: m.totalPred,\n            Yres: m.plsC.yResidual,\n            residualData,\n            folds,\n        };\n    }\n    /**\n     * get access to all the computed elements\n     * Mainly for debug and testing\n     * @returns {object} output object\n     */\n    getLogs() {\n        return this.output;\n    }\n    /**\n     * Returns the cross-validated predictive and orthogonal scores.\n     * @returns {{scoresX: Array<Array<number>>, scoresY: Array<Array<number>>}} the predictive (`scoresX`) and orthogonal (`scoresY`) cross-validated scores.\n     */\n    getScores() {\n        const scoresX = this.predictiveScoresCV.map((x) => x.to1DArray());\n        const scoresY = this.orthogonalScoresCV.map((x) => x.to1DArray());\n        return { scoresX, scoresY };\n    }\n    /**\n     * Load an OPLS model from JSON\n     * @param {object} model - the serialized model to load.\n     * @returns {OPLS} the loaded OPLS model.\n     */\n    static load(model) {\n        if (typeof model.name !== 'string') {\n            throw new TypeError('model must have a name property');\n        }\n        if (model.name !== 'OPLS') {\n            throw new RangeError(`invalid model: ${model.name}`);\n        }\n        return new OPLS(true, [], model);\n    }\n    /**\n     * Export the current model to a JSON object\n     * @returns {object} model\n     */\n    toJSON() {\n        return {\n            name: 'OPLS',\n            labels: this.labels,\n            center: this.center,\n            scale: this.scale,\n            means: this.means,\n            stdevs: this.stdevs,\n            model: this.model,\n            mode: this.mode,\n            output: this.output,\n            predictiveScoresCV: this.predictiveScoresCV,\n            orthogonalScoresCV: this.orthogonalScoresCV,\n            yHatScoresCV: this.yHatScoresCV,\n        };\n    }\n    /**\n     * Predicts the class of each row of new data (discriminant analysis mode).\n     * @param {Matrix} features - a matrix containing new data.\n     * @param {object} [options={}] - prediction options.\n     * @param {Array} [options.trueLabels] - an array with true values to compute confusion matrix.\n     * @param {boolean} [options.center=this.center] - should the data be centered before prediction.\n     * @param {boolean} [options.scale=this.scale] - should the data be scaled before prediction.\n     * @returns {Array} the predicted class name for each row of `features`.\n     */\n    predictCategory(features, options = {}) {\n        const { trueLabels = [], center = this.center, scale = this.scale, } = options;\n        if (isAnyArray(features)) {\n            if (features[0].length === undefined) {\n                features = Matrix.from1DArray(1, features.length, features);\n            }\n            else {\n                features = Matrix.checkMatrix(features);\n            }\n        }\n        const prediction = this.predict(features, { trueLabels, center, scale });\n        const predictiveComponents = Matrix.checkMatrix(this.output.predictiveComponents).to1DArray();\n        const newTPred = Matrix.checkMatrix(prediction.predictiveComponents).to1DArray();\n        const categories = getClasses(this.labels);\n        const classes = this.labels.slice();\n        const result = [];\n        for (const pred of newTPred) {\n            let item;\n            let auc = 0;\n            for (const category of categories) {\n                const testTPred = predictiveComponents.slice();\n                testTPred.push(pred);\n                const testClasses = classes.slice();\n                testClasses.push(category.name);\n                const rocCurve = getRocCurve(testClasses, testTPred);\n                const areaUnderCurve = getAuc(rocCurve);\n                if (auc < areaUnderCurve) {\n                    item = category.name;\n                    auc = areaUnderCurve;\n                }\n            }\n            result.push(item);\n        }\n        return result;\n    }\n    /* eslint-disable-next-line jsdoc/require-returns-check -- always returns for the supported modes (regression / discriminantAnalysis) */\n    /**\n     * Predict scores for new data\n     * @param {Matrix} features - a matrix containing new data\n     * @param {object} [options={}] - prediction options.\n     * @param {Array} [options.trueLabels] - an array with true values to compute confusion matrix.\n     * @param {boolean} [options.center=this.center] - should the data be centered before prediction.\n     * @param {boolean} [options.scale=this.scale] - should the data be scaled before prediction.\n     * @returns {object} - predictions\n     */\n    predict(features, options = {}) {\n        const { trueLabels = [], center = this.center, scale = this.scale, } = options;\n        let labels;\n        if (typeof trueLabels[0] === 'number') {\n            labels = Matrix.from1DArray(trueLabels.length, 1, trueLabels);\n        }\n        else if (typeof trueLabels[0] === 'string') {\n            labels = Matrix.checkMatrix(createDummyY(trueLabels)).transpose();\n        }\n        features = new Matrix(features);\n        // scaling the test dataset with respect to the train\n        if (center) {\n            features.center('column', { center: this.means });\n            if (labels?.rows > 0) {\n                labels.center('column', { center: this.meansY });\n            }\n        }\n        if (scale) {\n            features.scale('column', { scale: this.stdevs });\n            if (labels?.rows > 0) {\n                labels.scale('column', { scale: this.stdevsY });\n            }\n        }\n        const nc = this.mode === 'regression'\n            ? this.model[0].Q2y.length\n            : this.model[0].auc.length - 1;\n        const Eh = features.clone();\n        // removing the orthogonal components from PLS\n        let orthogonalScores;\n        let orthogonalWeights;\n        let orthogonalLoadings;\n        let totalPred;\n        let predictiveComponents;\n        for (let idx = 0; idx < nc; idx++) {\n            const model = this.model[idx];\n            orthogonalWeights = Matrix.checkMatrix(model.orthogonalWeights).transpose();\n            orthogonalLoadings = Matrix.checkMatrix(model.orthogonalLoadings);\n            orthogonalScores = Eh.mmul(orthogonalWeights);\n            Eh.sub(orthogonalScores.mmul(orthogonalLoadings));\n            // prediction\n            predictiveComponents = Eh.mmul(Matrix.checkMatrix(model.plsC.w).transpose());\n            const components = predictiveComponents\n                .mmul(model.plsC.betas)\n                .mmul(Matrix.checkMatrix(model.plsC.q).transpose());\n            totalPred = new Matrix(components.rows, 1);\n            for (let i = 0; i < components.rows; i++) {\n                totalPred.setRow(i, [components.getRowVector(i).sum()]);\n            }\n        }\n        if (labels?.rows > 0) {\n            if (this.mode === 'regression') {\n                const tssy = tss(labels);\n                const press = tss(labels.clone().sub(totalPred));\n                const Q2y = 1 - press / tssy;\n                return { predictiveComponents, orthogonalScores, yHat: totalPred, Q2y };\n            }\n            else if (this.mode === 'discriminantAnalysis') {\n                const confusionMatrix = ConfusionMatrix.fromLabels(trueLabels, totalPred.to1DArray());\n                const rocCurve = getRocCurve(trueLabels, totalPred.to1DArray());\n                const auc = getAuc(rocCurve);\n                return {\n                    predictiveComponents,\n                    orthogonalScores,\n                    yHat: totalPred,\n                    confusionMatrix,\n                    auc,\n                };\n            }\n        }\n        else {\n            return { predictiveComponents, orthogonalScores, yHat: totalPred };\n        }\n    }\n    /**\n     * Fits a one-component OPLS model on the full data set and computes its R2 statistics.\n     * @private\n     * @param {Matrix} data - the feature matrix (X).\n     * @param {Matrix} categories - the label matrix (Y).\n     * @param {object} [options={}] - prediction options.\n     * @param {boolean} [options.center=true] - should the data be centered.\n     * @param {boolean} [options.scale=true] - should the data be scaled.\n     * @returns {object} the fitted component with its scores, loadings, weights and R2x/R2y statistics.\n     */\n    _predictAll(data, categories, options = {}) {\n        // cannot use the global this.center here\n        // since it is used in the NC loop and\n        // centering and scaling should only be\n        // performed once\n        const { center = true, scale = true } = options;\n        // clone only when we mutate the inputs (center/scale below); oplsNipals and\n        // NIPALS do not mutate the X/Y passed here, so when called with\n        // center/scale = false (every component after the first) the clones are pure\n        // waste of a full-matrix copy per iteration.\n        const features = center || scale ? data.clone() : data;\n        const labels = center || scale ? categories.clone() : categories;\n        if (center) {\n            const means = features.mean('column');\n            features.center('column', { center: means });\n            labels.center('column');\n        }\n        if (scale) {\n            const stdevs = getSafeStandardDeviations(features);\n            features.scale('column', { scale: stdevs });\n            labels.scale('column');\n            // reevaluate tssy and tssx after scaling\n            // must be global because re-used for next nc iteration\n            // tssx is only evaluate the first time\n            this.tssy = tss(labels);\n            this.tssx = tss(features);\n        }\n        const oplsC = oplsNipals(features, labels);\n        const plsC = new NIPALS(oplsC.filteredX, { Y: labels });\n        const predictiveComponents = plsC.t.clone();\n        // const yHat = tPred.mmul(plsC.betas).mmul(plsC.q.transpose()); // ok\n        const yHatComponents = predictiveComponents\n            .mmul(plsC.betas)\n            .mmul(plsC.q.transpose()); // ok\n        const yHat = new Matrix(yHatComponents.rows, 1);\n        for (let i = 0; i < yHatComponents.rows; i++) {\n            yHat.setRow(i, [yHatComponents.getRowVector(i).sum()]);\n        }\n        let rss = 0;\n        for (let i = 0; i < labels.columns; i++) {\n            rss += tss(labels.getColumnVector(i).sub(yHat));\n        }\n        const R2y = 1 - rss / labels.columns / this.tssy;\n        const xEx = plsC.t.mmul(plsC.p);\n        const rssx = tss(xEx);\n        const R2x = rssx / this.tssx;\n        return {\n            R2y,\n            R2x,\n            xRes: oplsC.filteredX,\n            orthogonalScores: oplsC.scoresXOrtho,\n            orthogonalLoadings: oplsC.loadingsXOrtho,\n            orthogonalWeights: oplsC.weightsXOrtho,\n            predictiveComponents,\n            totalPred: yHat,\n            XOrth: oplsC.scoresXOrtho.mmul(oplsC.loadingsXOrtho),\n            oplsC,\n            plsC,\n        };\n    }\n    /**\n     * Splits the data into train and test sets for the given fold.\n     * @private\n     * @param {Matrix} X - dataset matrix object.\n     * @param {Matrix} group - labels matrix object.\n     * @param {object} index - train and test index (output from getFold()).\n     * @returns {object} train and test features and labels.\n     */\n    _getTrainTest(X, group, index) {\n        const testFeatures = new Matrix(index.testIndex.length, X.columns);\n        const testLabels = new Matrix(index.testIndex.length, group.columns);\n        for (const [idx, el] of index.testIndex.entries()) {\n            testFeatures.setRow(idx, X.getRow(el));\n            testLabels.setRow(idx, group.getRow(el));\n        }\n        const trainFeatures = new Matrix(index.trainIndex.length, X.columns);\n        const trainLabels = new Matrix(index.trainIndex.length, group.columns);\n        for (const [idx, el] of index.trainIndex.entries()) {\n            trainFeatures.setRow(idx, X.getRow(el));\n            trainLabels.setRow(idx, group.getRow(el));\n        }\n        return {\n            trainFeatures,\n            testFeatures,\n            trainLabels,\n            testLabels,\n        };\n    }\n}\n/**\n * Builds a dummy (indicator) Y matrix from an array of class labels.\n * For more than two classes each row encodes one class as `1` and the others as `-1`;\n * for two classes a single row of `2`/`1` values is returned.\n * @private\n * @param {Array} array - the array of class labels.\n * @returns {Array<Array<number>>} the dummy Y matrix.\n */\nfunction createDummyY(array) {\n    const features = [...new Set(array)];\n    const result = [];\n    if (features.length > 2) {\n        for (let i = 0; i < features.length; i++) {\n            const feature = [];\n            for (let j = 0; j < array.length; j++) {\n                const point = features[i] === array[j] ? 1 : -1;\n                feature.push(point);\n            }\n            result.push(feature);\n        }\n        return result;\n    }\n    else {\n        const result = [];\n        for (let j = 0; j < array.length; j++) {\n            const point = features[0] === array[j] ? 2 : 1;\n            result.push(point);\n        }\n        return [result];\n    }\n}\n//# sourceMappingURL=OPLS.js.map","/**\n * get folds indexes\n * @param {Array} features\n * @param {Number} k - number of folds, a\n */\nexport function getFolds(features, k = 5) {\n  let N = features.length;\n  let allIdx = new Array(N);\n  for (let i = 0; i < N; i++) {\n    allIdx[i] = i;\n  }\n\n  let l = Math.floor(N / k);\n  // create random k-folds\n  let current = [];\n  let folds = [];\n  while (allIdx.length) {\n    let randi = Math.floor(Math.random() * allIdx.length);\n    current.push(allIdx[randi]);\n    allIdx.splice(randi, 1);\n    if (current.length === l) {\n      folds.push(current);\n      current = [];\n    }\n  }\n  // we push the remaining to the last fold so that the total length is\n  // preserved. Otherwise the Q2 will fail.\n  if (current.length) current.forEach((e) => folds[k - 1].push(e));\n  folds = folds.slice(0, k);\n\n  let foldsIndex = folds.map((x, idx) => ({\n    testIndex: x,\n    trainIndex: [].concat(...folds.filter((el, idx2) => idx2 !== idx)),\n  }));\n  return foldsIndex;\n}\n"],"names":["isAnyArray","value","Matrix","matrix","NIPALS","SingularValueDecomposition","inverse","norm","X","Math","sqrt","clone","apply","pow2array","sum","i","j","this","set","get","initializeMatrices","array","isMatrix","length","elem","undefined","PLS","constructor","options","model","meanX","stdDevX","meanY","stdDevY","PBQ","checkMatrix","R2X","scale","scaleMethod","tolerance","latentVectors","train","trainingSet","trainingValues","RangeError","mean","standardDeviation","unbiased","subRowVector","divRowVector","min","rows","columns","t","w","q","p","rx","cx","ry","cy","ssqXcal","mul","sumOfSquaresY","n","T","zeros","P","U","Q","B","W","k","Utils","transposeX","transpose","transposeY","tIndex","maxSumColIndex","uIndex","t1","getColumnVector","u","sub","mmul","div","num","den","pnorm","b","setColumn","subMatrix","ssqYcal","E","F","predict","dataset","Y","mulRowVector","addRowVector","getExplainedVariance","toJSON","name","load","data","rowVector","maxIndex","KOPLS","YLoadingMat","SigmaPow","YScoreMat","predScoreMat","YOrthLoadingVec","YOrthEigen","YOrthScoreMat","toNorm","TURegressionCoeff","kernelX","kernel","orthogonalComp","predictiveComp","predictiveComponents","orthogonalComponents","compute","Identity","eye","temp","Array","result","computeLeftSingularVectors","computeRightSingularVectors","leftSingularVectors","Sigma","diagonalMatrix","YOrthScoreNorm","pow","removeInfinity","TpiPrime","CoTemp","SoTemp","toiPrime","ITo","lastScoreMat","lastTpPrime","toPredict","KTestTrain","YOrthScoreVector","scoreMatPrime","p1","p2","p3","add","prediction","predYOrthVectors","Infinity","toString","Object","prototype","ConfusionMatrix","labels","Error","fromLabels","actual","predicted","distinctLabels","Set","from","sort","fill","actualIdx","indexOf","predictedIdx","getMatrix","getLabels","getTotalCount","row","element","getTrueCount","count","getFalseCount","getTruePositiveCount","label","index","getIndex","getTrueNegativeCount","getFalsePositiveCount","getFalseNegativeCount","getPositiveCount","getNegativeCount","getTruePositiveRate","getTrueNegativeRate","getPositivePredictiveValue","TP","getNegativePredictiveValue","TN","getFalseNegativeRate","getFalsePositiveRate","getFalseDiscoveryRate","FP","getFalseOmissionRate","FN","getF1Score","getMatthewsCorrelationCoefficient","getInformedness","getMarkedness","getConfusionTable","getAccuracy","correct","incorrect","getCount","actualIndex","predictedIndex","accuracy","total","createCommonjsModule","fn","module","exports","runtime","global","Op","hasOwn","hasOwnProperty","$Symbol","Symbol","iteratorSymbol","iterator","asyncIteratorSymbol","asyncIterator","toStringTagSymbol","toStringTag","regeneratorRuntime","wrap","GenStateSuspendedStart","GenStateSuspendedYield","GenStateExecuting","GenStateCompleted","ContinueSentinel","IteratorPrototype","getProto","getPrototypeOf","NativeIteratorPrototype","values","call","Gp","GeneratorFunctionPrototype","Generator","create","GeneratorFunction","displayName","isGeneratorFunction","genFun","ctor","mark","setPrototypeOf","__proto__","awrap","arg","__await","defineIteratorMethods","AsyncIterator","async","innerFn","outerFn","self","tryLocsList","iter","next","then","done","keys","object","key","push","reverse","pop","Context","reset","skipTempReset","prev","sent","_sent","delegate","method","tryEntries","forEach","resetTryEntry","charAt","isNaN","slice","stop","rootRecord","completion","type","rval","dispatchException","exception","context","handle","loc","caught","record","entry","tryLoc","hasCatch","hasFinally","catchLoc","finallyLoc","abrupt","finallyEntry","complete","afterLoc","finish","catch","thrown","delegateYield","iterable","resultName","nextLoc","protoGenerator","generator","_invoke","makeInvokeMethod","tryCatch","obj","err","invoke","resolve","reject","Promise","unwrapped","previousPromise","enqueue","callInvokeWithMethodAndArg","state","doneResult","delegateResult","maybeInvokeDelegate","return","TypeError","info","pushTryEntry","locs","iteratorMethod","Function","g","hadRuntime","getOwnPropertyNames","oldRuntime","runtimeModule","e","regenerator","defaultOptions","mode","_callee","M","N","a","c","x","y","z","twiddle","_context","assign","factory","input","tag","endsWith","includes","sumValue","getAuc","curves","auc","curve","area","specificities","sensitivities","getBinaryClassifiers","responses","predictions","limits","uniques","thresholds","Number","NEGATIVE_INFINITY","half","POSITIVE_INFINITY","getThresholds","truePositives","falsePositives","trueNegatives","falseNegatives","limit","truePositive","falsePositive","trueNegative","falseNegative","category","getClasses","nbClasses","classes","ids","some","item","indexes","getSelectedResults","pair","results","id","getRocCurve","pairsOfClasses","list","pairs","getClassesPairs","tests","targets","oplsNipals","numberOSC","tW","wh","xValue","yValue","yN","component","getRow","getWh","ssWh","pcaW","ssT","xResidual","uNew","wOrtho","diff","numerator","denominator","newValue","delta","tw","tOrtho","pOrtho","filteredX","weightsXOrtho","loadingsXOrtho","scoresXOrtho","weightsXPred","loadingsXpred","scoresXpred","loadingsY","getSafeStandardDeviations","standardDeviations","tss","OPLS","opls","center","means","meansY","stdevs","stdevsY","predictiveScoresCV","orthogonalScoresCV","yHatScoresCV","output","features","cvFolds","nbFolds","maxComponents","size","group","from1DArray","createDummyY","folds","allIdx","l","floor","current","randi","random","splice","map","idx","testIndex","trainIndex","concat","filter","el","idx2","getFolds","Q2","aucResult","oplsCV","modelNC","overfitted","nc","yHatk","predictiveScoresK","orthogonalScoresK","f","trainTest","_getTrainTest","testFeatures","trainFeatures","trainLabels","dataCenter","dataSD","oplsk","plsCV","Eh","scores","yHatComponents","betas","yHat","setRow","getRowVector","tssy","press","Q2y","areaUnderCurve","to1DArray","listOfValues","_predictAll","xRes","isFinite","m","orthogonalData","orthogonalScores","orthogonalLoadings","orthogonalWeights","XOrth","setSubMatrix","FeaturesCS","labelsCS","orthogonalizedData","plsCall","residualData","R2x","R2y","predictiveLoadings","predictiveWeights","Qpc","Xorth","totalPred","Yres","plsC","yResidual","getLogs","getScores","scoresX","scoresY","predictCategory","trueLabels","newTPred","categories","pred","testTPred","testClasses","components","confusionMatrix","rocCurve","tssx","oplsC","rss","testLabels","entries","feature","point"],"mappings":"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","x_google_ignoreList":[0,1,5,6,7,8,9,10,11,12,13,14,15,16,17,22]}