Skip to content

Commit

Permalink
Fix #1789: Function eigs not calculating with BigNumber precision w…
Browse files Browse the repository at this point in the history
…hen input contains BigNumbers
  • Loading branch information
josdejong committed Mar 29, 2020
1 parent b2af1d7 commit 5624e69
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 19 deletions.
2 changes: 2 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

# not yet published, version 6.6.2

- Fix #1789: Function `eigs` not calculating with BigNumber precision
when input contains BigNumbers.
- Run the build script during npm `prepare`, so you can use the library
directly when installing directly from git. Thanks @cinderblock.

Expand Down
34 changes: 15 additions & 19 deletions src/function/matrix/eigs.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { factory } from '../../utils/factory'
import { format } from '../../utils/string'

const name = 'eigs'
const dependencies = ['typed', 'matrix', 'addScalar', 'equal', 'subtract', 'abs', 'atan', 'cos', 'sin', 'multiplyScalar', 'inv', 'bignumber', 'multiply', 'add']
const dependencies = ['config', 'typed', 'matrix', 'addScalar', 'equal', 'subtract', 'abs', 'atan', 'cos', 'sin', 'multiplyScalar', 'inv', 'bignumber', 'multiply', 'add']

export const createEigs = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, addScalar, subtract, equal, abs, atan, cos, sin, multiplyScalar, inv, bignumber, multiply, add }) => {
export const createEigs = /* #__PURE__ */ factory(name, dependencies, ({ config, typed, matrix, addScalar, subtract, equal, abs, atan, cos, sin, multiplyScalar, inv, bignumber, multiply, add }) => {
/**
* Compute eigenvalue and eigenvector of a real symmetric matrix.
* Only applicable to two dimensional symmetric matrices. Uses Jacobi
Expand Down Expand Up @@ -172,26 +172,22 @@ export const createEigs = /* #__PURE__ */ factory(name, dependencies, ({ typed,

// get angle
function getTheta (aii, ajj, aij) {
let th = 0
const denom = (ajj - aii)
if (Math.abs(denom) <= 1E-14) {
th = Math.PI / 4.0
if (Math.abs(denom) <= config.epsilon) {
return Math.PI / 4
} else {
th = 0.5 * Math.atan(2.0 * aij / (ajj - aii))
return 0.5 * Math.atan(2 * aij / (ajj - aii))
}
return th
}

// get angle
function getThetaBig (aii, ajj, aij) {
let th = 0
const denom = subtract(ajj, aii)
if (abs(denom) <= 1E-14) {
th = Math.PI / 4.0
if (abs(denom) <= config.epsilon) {
return bignumber(-1).acos().div(4)
} else {
th = multiplyScalar(0.5, atan(multiply(2.0, aij, inv(denom))))
return multiplyScalar(0.5, atan(multiply(2, aij, inv(denom))))
}
return th
}

// update eigvec
Expand All @@ -216,8 +212,8 @@ export const createEigs = /* #__PURE__ */ factory(name, dependencies, ({ typed,
const N = Sij.length
const c = cos(theta)
const s = sin(theta)
const Ski = createArray(N, 0)
const Skj = createArray(N, 0)
const Ski = createArray(N, bignumber(0))
const Skj = createArray(N, bignumber(0))
for (let k = 0; k < N; k++) {
Ski[k] = subtract(multiplyScalar(c, Sij[k][i]), multiplyScalar(s, Sij[k][j]))
Skj[k] = addScalar(multiplyScalar(s, Sij[k][i]), multiplyScalar(c, Sij[k][j]))
Expand All @@ -236,10 +232,10 @@ export const createEigs = /* #__PURE__ */ factory(name, dependencies, ({ typed,
const s = bignumber(sin(theta))
const c2 = multiplyScalar(c, c)
const s2 = multiplyScalar(s, s)
const Aki = createArray(N, 0)
const Akj = createArray(N, 0)
const Aki = createArray(N, bignumber(0))
const Akj = createArray(N, bignumber(0))
// 2cs Hij
const csHij = multiply(2, c, s, Hij[i][j])
const csHij = multiply(bignumber(2), c, s, Hij[i][j])
// Aii
const Aii = addScalar(subtract(multiplyScalar(c2, Hij[i][i]), csHij), multiplyScalar(s2, Hij[j][j]))
const Ajj = add(multiplyScalar(s2, Hij[i][i]), csHij, multiplyScalar(c2, Hij[j][j]))
Expand All @@ -251,8 +247,8 @@ export const createEigs = /* #__PURE__ */ factory(name, dependencies, ({ typed,
// Modify Hij
Hij[i][i] = Aii
Hij[j][j] = Ajj
Hij[i][j] = 0
Hij[j][i] = 0
Hij[i][j] = bignumber(0)
Hij[j][i] = bignumber(0)
// 0 to i
for (let k = 0; k < N; k++) {
if (k !== i && k !== j) {
Expand Down
13 changes: 13 additions & 0 deletions test/unit-tests/function/matrix/eigs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,17 @@ describe('eigs', function () {
}
approx.deepEqual(Ei, E)
})

it('make sure BigNumbers input is actually calculated with BigNumber precision', function () {
const B = math.bignumber([
[0, 1],
[1, 0]
])
const eig = math.eigs(B)

assert.strictEqual(eig.values[0].toString(),
'-0.9999999999999999999999999999999999999999999999999999999999999999')
assert.strictEqual(eig.values[1].toString(),
'0.9999999999999999999999999999999999999999999999999999999999999999')
})
})

0 comments on commit 5624e69

Please sign in to comment.