mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-18 14:59:29 +00:00
feat: implement negative integer exponents for square matrices (#2517)
Resolves #2463 Co-authored-by: Glen Whitney <glen@studioinfinity.org>
This commit is contained in:
parent
36e7e46289
commit
7480c11bf7
1
AUTHORS
1
AUTHORS
@ -187,5 +187,6 @@ Hjortur Jonasson <hjorturjonasson@gmail.com>
|
||||
Abraham <abraham@abranhe.com>
|
||||
Sam Estep <sam@samestep.com>
|
||||
Sinan <43215895+SinanAkkoyun@users.noreply.github.com>
|
||||
HanchaiN <85230240+HanchaiN@users.noreply.github.com>
|
||||
|
||||
# Generated by tools/update-authors.js
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
# History
|
||||
|
||||
# unpublished changes since 10.4.3:
|
||||
|
||||
- Implement #2463: allow negative integer powers of invertible square matrices
|
||||
(#2517). Thanks @HanchaiN.
|
||||
|
||||
# 2022-04-08, version 10.4.3
|
||||
|
||||
|
||||
@ -10,7 +10,9 @@ export const powDocs = {
|
||||
examples: [
|
||||
'2^3',
|
||||
'2*2*2',
|
||||
'1 + e ^ (pi * i)'
|
||||
'1 + e ^ (pi * i)',
|
||||
'math.pow([[1, 2], [4, 3]], 2)',
|
||||
'math.pow([[1, 2], [4, 3]], -1)'
|
||||
],
|
||||
seealso: [
|
||||
'multiply',
|
||||
|
||||
@ -10,16 +10,20 @@ const dependencies = [
|
||||
'identity',
|
||||
'multiply',
|
||||
'matrix',
|
||||
'inv',
|
||||
'fraction',
|
||||
'number',
|
||||
'Complex'
|
||||
]
|
||||
|
||||
export const createPow = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, identity, multiply, matrix, number, fraction, Complex }) => {
|
||||
export const createPow = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, identity, multiply, matrix, inv, number, fraction, Complex }) => {
|
||||
/**
|
||||
* Calculates the power of x to y, `x ^ y`.
|
||||
* Matrix exponentiation is supported for square matrices `x`, and positive
|
||||
* integer exponents `y`.
|
||||
*
|
||||
* Matrix exponentiation is supported for square matrices `x` and integers `y`:
|
||||
* when `y` is nonnegative, `x` may be any square matrix; and when `y` is
|
||||
* negative, `x` must be invertible, and then this function returns
|
||||
* inv(x)^(-y).
|
||||
*
|
||||
* For cubic roots of negative numbers, the function returns the principal
|
||||
* root by default. In order to let the function return the real root,
|
||||
@ -40,6 +44,9 @@ export const createPow = /* #__PURE__ */ factory(name, dependencies, ({ typed, c
|
||||
* const b = [[1, 2], [4, 3]]
|
||||
* math.pow(b, 2) // returns Array [[9, 8], [16, 17]]
|
||||
*
|
||||
* const c = [[1, 2], [4, 3]]
|
||||
* math.pow(c, -1) // returns Array [[-0.6, 0.4], [0.8, -0.2]]
|
||||
*
|
||||
* See also:
|
||||
*
|
||||
* multiply, sqrt, cbrt, nthRoot
|
||||
@ -150,13 +157,13 @@ export const createPow = /* #__PURE__ */ factory(name, dependencies, ({ typed, c
|
||||
/**
|
||||
* Calculate the power of a 2d array
|
||||
* @param {Array} x must be a 2 dimensional, square matrix
|
||||
* @param {number} y a positive, integer value
|
||||
* @param {number} y a integer value (positive if `x` is not invertible)
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
function _powArray (x, y) {
|
||||
if (!isInteger(y) || y < 0) {
|
||||
throw new TypeError('For A^b, b must be a positive integer (value is ' + y + ')')
|
||||
if (!isInteger(y)) {
|
||||
throw new TypeError('For A^b, b must be an integer (value is ' + y + ')')
|
||||
}
|
||||
// verify that A is a 2 dimensional square matrix
|
||||
const s = size(x)
|
||||
@ -166,6 +173,16 @@ export const createPow = /* #__PURE__ */ factory(name, dependencies, ({ typed, c
|
||||
if (s[0] !== s[1]) {
|
||||
throw new Error('For A^b, A must be square (size is ' + s[0] + 'x' + s[1] + ')')
|
||||
}
|
||||
if (y < 0) {
|
||||
try {
|
||||
return _powArray(inv(x), -y)
|
||||
} catch (error) {
|
||||
if (error.message === 'Cannot calculate inverse, determinant is zero') {
|
||||
throw new TypeError('For A^b, when A is not invertible, b must be a positive integer (value is ' + y + ')')
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
let res = identity(s[0]).valueOf()
|
||||
let px = x
|
||||
|
||||
@ -241,6 +241,21 @@ describe('pow', function () {
|
||||
approx.deepEqual(pow(matrix(a), 2), matrix(res))
|
||||
})
|
||||
|
||||
it('should raise an inverted matrix for power -1', function () {
|
||||
const a = [
|
||||
[2, -1, 0],
|
||||
[-1, 2, -1],
|
||||
[0, -1, 2]
|
||||
]
|
||||
const res = [
|
||||
[3 / 4, 1 / 2, 1 / 4],
|
||||
[1 / 2, 1, 1 / 2],
|
||||
[1 / 4, 1 / 2, 3 / 4]
|
||||
]
|
||||
approx.deepEqual(pow(a, -1), res)
|
||||
approx.deepEqual(pow(matrix(a), -1), matrix(res))
|
||||
})
|
||||
|
||||
it('should return identity matrix for power 0', function () {
|
||||
const a = [[1, 2], [3, 4]]
|
||||
const res = [[1, 0], [0, 1]]
|
||||
@ -266,6 +281,11 @@ describe('pow', function () {
|
||||
assert.throws(function () { pow(a, [2, 3]) })
|
||||
})
|
||||
|
||||
it('should throw an error when raising a non-invertible matrix to a negative integer power', function () {
|
||||
const a = [[1, 1, 1], [1, 0, 0], [0, 0, 0]]
|
||||
assert.throws(function () { pow(a, -1) })
|
||||
})
|
||||
|
||||
it('should LaTeX pow', function () {
|
||||
const expression = math.parse('pow(2,10)')
|
||||
assert.strictEqual(expression.toTex(), '\\left(2\\right)^{10}')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user