Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
94b7812
Add MUNIT, MDETERM and MINVERSE functions
marcin-kordas-hoc Oct 15, 2026
2004308
docs: link the pull request in the changelog
marcin-kordas-hoc Oct 15, 2026
2366fcf
Merge remote-tracking branch 'origin/develop' into feat/hf-matrix-mun…
marcin-kordas-hoc Oct 23, 2026
938b724
HF-399: Compute MDETERM and MINVERSE with an LU decomposition with pa…
marcin-kordas-hoc Oct 23, 2026
b83f3cc
HF-401: Use the MUNIT names from the Microsoft function pages in esES…
marcin-kordas-hoc Oct 23, 2026
b37ce5d
HF-401: Replace the MUNIT example that needs a parse-time size and li…
marcin-kordas-hoc Oct 23, 2026
3d8c23f
HF-401: Limit MUNIT to the sheet size and size a signed literal dimen…
marcin-kordas-hoc Oct 23, 2026
afd65cf
HF-401: Coerce numeric text in MUNIT and let text win over an error i…
marcin-kordas-hoc Oct 25, 2026
f7a20f9
HF-401: List MUNIT over a range of dimensions as a difference from Excel
marcin-kordas-hoc Oct 25, 2026
078e2a9
HF-401: Coerce a MUNIT text dimension at parse time the way evaluatio…
marcin-kordas-hoc Oct 25, 2026
48eaed2
Merge remote-tracking branch 'origin/develop' into feat/hf-matrix-mun…
marcin-kordas-hoc Nov 2, 2026
443deef
HF-399: Report a non-square matrix in MDETERM and MINVERSE with its o…
marcin-kordas-hoc Nov 2, 2026
f638d2c
HF-401: Read a signed number literal for MUNIT and SEQUENCE result si…
marcin-kordas-hoc Nov 2, 2026
a4f00d6
Merge branch 'develop' into feat/hf-matrix-munit-mdeterm-minverse
marcin-kordas-hoc Nov 3, 2026
e6578aa
Merge branch 'develop' into feat/hf-matrix-munit-mdeterm-minverse
marcin-kordas-hoc Nov 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

- Added `LINEST` for simple and multiple linear regression, with optional intercept and regression statistics. The `stats` argument must be constant because result dimensions are determined before evaluation. [#1769](https://github.com/handsontable/hyperformula/pull/1769)
- Added the `CONCAT` function, which joins text from values, ranges, and arrays, and the `VALUETOTEXT` function, which returns a value as text in a concise or a strict format. [#1816](https://github.com/handsontable/hyperformula/pull/1816)
- Added the `MUNIT`, `MDETERM` and `MINVERSE` matrix functions: the identity matrix, the determinant and the inverse of a square matrix. [#1817](https://github.com/handsontable/hyperformula/pull/1817)

### Fixed

Expand Down
2 changes: 1 addition & 1 deletion docs/guide/known-limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ a circular reference.
* For certain inputs, the RATE function might have no solutions, or have multiple solutions. Our implementation uses an iterative algorithm (Newton's method) to find an approximation for one of the solutions to within 1e-7. If the approximation is not found after 50 iterations, the RATE function returns the `#NUM!` error.
* The INDEX function doesn't support returning whole rows or columns of the source range – it always returns the contents of a single cell.
* The FILTER function accepts either single rows of equal width or single columns of equal height. In other words, all arrays passed to the FILTER function must have equal dimensions, and at least one of those dimensions must be 1.
* Array-producing functions (e.g., SEQUENCE, FILTER) require their output dimensions to be determinable at parse time. Passing cell references or formulas as dimension arguments (e.g., `=SEQUENCE(A1)`) results in a `#VALUE!` error, because the output size cannot be resolved before evaluation.
* Array-producing functions (e.g., SEQUENCE, MUNIT, FILTER) require their output dimensions to be determinable at parse time. Passing cell references or formulas as dimension arguments (e.g., `=SEQUENCE(A1)`) results in a `#VALUE!` error, because the output size cannot be resolved before evaluation.
* The TEXT function does not accept embedded double-quote literals in the format string. In Excel, `""` inside a format string is an escape sequence for a literal `"` character — e.g. `=TEXT(1234.5, "#,##0.00 ""zł""")` returns `"1,234.50 zł"`. If your application requires this escape sequence, supply a custom [`stringifyCurrency`](currency-handling.md) callback.

### UNIQUE function
Expand Down
1 change: 1 addition & 0 deletions docs/guide/list-of-differences.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ To remove the differences, create [custom implementations](custom-functions.md)
| ISODD | =ISODD(3.5) | FALSE | TRUE | TRUE |
| CEILING.MATH | =CEILING.MATH(-4.3, 2, 2) | -4 | -6 | -6 |
| FLOOR.MATH | =FLOOR.MATH(-4.7, 2, 2) | -6 | -4 | -4 |
| MUNIT | =ROWS(MUNIT(A1:A2))<br>where A1:A2: 3, 2 | VALUE | Not checked | 2 |

A few of the rows above share a root cause worth stating once:

Expand Down
2 changes: 2 additions & 0 deletions hyperformula/src/error-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export class ErrorMessage {
public static EmptyArray = 'Empty array not allowed.'
public static ArrayDimensions = 'Array dimensions are not compatible.'
public static PoolDimensions = 'Range dimensions are not compatible with the window size and the stride.'
public static SingularMatrix = 'Matrix is singular.'
public static SquareMatrix = 'Matrix must be square.'
public static NoSpaceForArrayResult = 'No space for array result.'
public static ValueSmall = 'Value too small.'
public static ValueLarge = 'Value too large.'
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/csCZ.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MINIFS',
MINUTE: 'MINUTA',
MIRR: 'MOD.MÍRA.VÝNOSNOSTI',
MDETERM: 'DETERMINANT',
MINVERSE: 'INVERZE',
MMULT: 'SOUČIN.MATIC',
MUNIT: 'MUNIT',
MOD: 'MOD',
MONTH: 'MĚSÍC',
N: 'N',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/daDK.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MINHVISER',
MINUTE: 'MINUT',
MIRR: 'MIA',
MDETERM: 'MDETERM',
MINVERSE: 'MINVERT',
MMULT: 'MPRODUKT',
MUNIT: 'MENHED',
MOD: 'REST',
MONTH: 'MÅNED',
N: 'TAL',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/deDE.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MINWENNS',
MINUTE: 'MINUTE',
MIRR: 'QIKV',
MDETERM: 'MDET',
MINVERSE: 'MINV',
MMULT: 'MMULT',
MUNIT: 'MEINHEIT',
MOD: 'REST',
MONTH: 'MONAT',
N: 'N',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/enGB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MINIFS',
MINUTE: 'MINUTE',
MIRR: 'MIRR',
MDETERM: 'MDETERM',
MINVERSE: 'MINVERSE',
MMULT: 'MMULT',
MUNIT: 'MUNIT',
MOD: 'MOD',
MONTH: 'MONTH',
N: 'N',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/esES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ export const dictionary: RawTranslationPackage = {
MINIFS: 'MIN.SI.CONJUNTO',
MINUTE: 'MINUTO',
MIRR: 'TIRM',
MDETERM: 'MDETERM',
MINVERSE: 'MINVERSA',
MMULT: 'MMULT',
MUNIT: 'M.UNIDAD',
MOD: 'RESIDUO',
MONTH: 'MES',
N: 'N',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/fiFI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MIN.JOS',
MINUTE: 'MINUUTIT',
MIRR: 'MSISÄINEN',
MDETERM: 'MDETERM',
MINVERSE: 'MKÄÄNTEINEN',
MMULT: 'MKERRO',
MUNIT: 'YKSIKKÖM',
MOD: 'JAKOJ',
MONTH: 'KUUKAUSI',
N: 'N',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/frFR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MIN.SI',
MINUTE: 'MINUTE',
MIRR: 'TRIM',
MDETERM: 'DETERMAT',
MINVERSE: 'INVERSEMAT',
MMULT: 'PRODUITMAT',
MUNIT: 'MATRICE.UNITAIRE',
MOD: 'MOD',
MONTH: 'MOIS',
N: 'N',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/huHU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MINHA',
MINUTE: 'PERCEK',
MIRR: 'MEGTÉRÜLÉS',
MDETERM: 'MDETERM',
MINVERSE: 'INVERZ.MÁTRIX',
MMULT: 'MSZORZAT',
MUNIT: 'MMÁTRIX',
MOD: 'MARADÉK',
MONTH: 'HÓNAP',
N: 'S',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/idID.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MIN.JIKAS',
MINUTE: 'MENIT',
MIRR: 'MIRR',
MDETERM: 'MDETERM',
MINVERSE: 'MINVERSE',
MMULT: 'MMULT',
MUNIT: 'MUNIT',
MOD: 'MOD',
MONTH: 'BULAN',
N: 'N',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/itIT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MIN.PIÙ.SE',
MINUTE: 'MINUTO',
MIRR: 'TIR.VAR',
MDETERM: 'MATR.DETERM',
MINVERSE: 'MATR.INVERSA',
MMULT: 'MATR.PRODOTTO',
MUNIT: 'MATR.UNIT',
MOD: 'RESTO',
MONTH: 'MESE',
N: 'NUM',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/nbNO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MIN.HVIS.SETT',
MINUTE: 'MINUTT',
MIRR: 'MODIR',
MDETERM: 'MDETERM',
MINVERSE: 'MINVERS',
MMULT: 'MMULT',
MUNIT: 'MENHET',
MOD: 'REST',
MONTH: 'MÅNED',
N: 'N',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/nlNL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MIN.ALS.VOORWAARDEN',
MINUTE: 'MINUUT',
MIRR: 'GIR',
MDETERM: 'DETERMINANTMAT',
MINVERSE: 'INVERSEMAT',
MMULT: 'PRODUCTMAT',
MUNIT: 'EENHEIDMAT',
MOD: 'REST',
MONTH: 'MAAND',
N: 'N',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/plPL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MIN.WARUNKÓW',
MINUTE: 'MINUTA',
MIRR: 'MIRR',
MDETERM: 'WYZNACZNIK.MACIERZY',
MINVERSE: 'MACIERZ.ODW',
MMULT: 'MACIERZ.ILOCZYN',
MUNIT: 'MACIERZ.JEDNOSTKOWA',
MOD: 'MOD',
MONTH: 'MIESIĄC',
N: 'N',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/ptPT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MÍNIMOSES',
MINUTE: 'MINUTO',
MIRR: 'MTIR',
MDETERM: 'MATRIZ.DETERM',
MINVERSE: 'MATRIZ.INVERSA',
MMULT: 'MATRIZ.MULT',
MUNIT: 'UNIDM',
MOD: 'MOD',
MONTH: 'MÊS',
N: 'N',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/ruRU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'МИНЕСЛИ',
MINUTE: 'МИНУТЫ',
MIRR: 'МВСД',
MDETERM: 'МОПРЕД',
MINVERSE: 'МОБР',
MMULT: 'МУМНОЖ',
MUNIT: 'МЕДИН',
MOD: 'ОСТАТ',
MONTH: 'МЕСЯЦ',
N: 'Ч',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/svSE.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'MINIFS',
MINUTE: 'MINUT',
MIRR: 'MODIR',
MDETERM: 'MDETERM',
MINVERSE: 'MINVERT',
MMULT: 'MMULT',
MUNIT: 'MENHET',
MOD: 'REST',
MONTH: 'MÅNAD',
N: 'N',
Expand Down
3 changes: 3 additions & 0 deletions hyperformula/src/i18n/languages/trTR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const dictionary: RawTranslationPackage = {
MINIFS: 'ÇOKEĞERMİN',
MINUTE: 'DAKİKA',
MIRR: 'D_İÇ_VERİM_ORANI',
MDETERM: 'DETERMİNANT',
MINVERSE: 'DİZEY_TERS',
MMULT: 'DÇARP',
MUNIT: 'BİRİMMATRİS',
MOD: 'MOD',
MONTH: 'AY',
N: 'S',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,32 @@ export const MATRIX_FUNCTIONS_DOCS: Record<string, FunctionDoc> = {
documentationUrl: 'https://hyperformula.handsontable.com/docs/guide/built-in-functions.html',
examples: ['=MEDIANPOOL(A1:D4, 2)', '=MEDIANPOOL(A1:D4, 2, 1)'],
},
MDETERM: {
category: 'Matrix functions',
shortDescription: 'Calculates the determinant of a square array. A non-square array or an array with a non-numeric value returns the #VALUE! error.',
parameters: [{name: 'array', description: 'The square range or array of numbers whose determinant is calculated.'}],
documentationUrl: 'https://hyperformula.handsontable.com/docs/guide/built-in-functions.html',
examples: ['=MDETERM(A1:B2)', '=MDETERM({1,2;3,4})'],
},
MINVERSE: {
category: 'Matrix functions',
shortDescription: 'Calculates the inverse of a square array. A non-square array or an array with a non-numeric value returns the #VALUE! error; a singular array returns the #NUM! error.',
parameters: [{name: 'array', description: 'The square range or array of numbers to invert.'}],
documentationUrl: 'https://hyperformula.handsontable.com/docs/guide/built-in-functions.html',
examples: ['=MINVERSE(A1:B2)', '=MINVERSE({1,2;3,4})'],
},
MMULT: {
category: 'Matrix functions',
shortDescription: 'Calculates the array product of two arrays.',
parameters: [{name: 'array1', description: 'The first range of numbers in the matrix multiplication; its column count must equal the row count of array2.'}, {name: 'array2', description: 'The second range of numbers in the matrix multiplication; its row count must equal the column count of array1.'}],
documentationUrl: 'https://hyperformula.handsontable.com/docs/guide/built-in-functions.html',
examples: ['=MMULT(A1:B2, D1:E2)', '=MMULT(A1:C2, A4:B6)'],
},
MUNIT: {
category: 'Matrix functions',
shortDescription: 'Returns the identity matrix of the given dimension. A fractional dimension is truncated; a dimension below 1 or a non-numeric one returns the #VALUE! error.',
parameters: [{name: 'dimension', description: 'The number of rows and columns of the returned matrix.'}],
documentationUrl: 'https://hyperformula.handsontable.com/docs/guide/built-in-functions.html',
examples: ['=MUNIT(3)', '=MMULT(A1:C3, MUNIT(3))'],
},
}
17 changes: 17 additions & 0 deletions hyperformula/src/interpreter/plugin/FunctionPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,23 @@ export abstract class FunctionPlugin implements FunctionPluginTypecheck<Function

protected coerceScalarToNumberOrError = (arg: InternalScalarValue): ExtendedNumber | CellError => this.arithmeticHelper.coerceScalarToNumberOrError(arg)

/**
* Reads a number written directly in a formula, with an optional sign, such as `3`, `+3` or `-3`. A function whose
* result size depends on an argument uses it to predict that size before the formula is evaluated.
*
* @param node - an argument of a function call
* @returns the number, or undefined when the argument is anything else and its value is known only after evaluation
*/
protected signedNumberLiteral(node: Ast): Maybe<number> {
if (node.type === AstNodeType.NUMBER) {
return node.value
}
if ((node.type === AstNodeType.PLUS_UNARY_OP || node.type === AstNodeType.MINUS_UNARY_OP) && node.value.type === AstNodeType.NUMBER) {
return node.type === AstNodeType.MINUS_UNARY_OP ? -node.value.value : node.value.value
}
return undefined
}

protected coerceToType(arg: InterpreterValue, coercedType: FunctionArgument, state: InterpreterState): Maybe<InterpreterValue | complex | RawNoErrorScalarValue> {
let ret
if (arg instanceof SimpleRangeValue) {
Expand Down
Loading
Loading