Skip to content

Commit

Permalink
Determinant with small numbers fix (#3139)
Browse files Browse the repository at this point in the history
  • Loading branch information
dvd101x authored Feb 14, 2024
1 parent 24b79ae commit e1817ba
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 34 deletions.
18 changes: 9 additions & 9 deletions src/function/utils/isNegative.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { deepMap } from '../../utils/collection.js'
import { factory } from '../../utils/factory.js'
import { isNegativeNumber } from '../../plain/number/index.js'
import { nearlyEqual as bigNearlyEqual } from '../../utils/bignumber/nearlyEqual.js'
import { nearlyEqual } from '../../utils/number.js'

const name = 'isNegative'
const dependencies = ['typed']
const dependencies = ['typed', 'config']

export const createIsNegative = /* #__PURE__ */ factory(name, dependencies, ({ typed }) => {
export const createIsNegative = /* #__PURE__ */ factory(name, dependencies, ({ typed, config }) => {
/**
* Test whether a value is negative: smaller than zero.
* The function supports types `number`, `BigNumber`, `Fraction`, and `Unit`.
Expand Down Expand Up @@ -36,15 +38,13 @@ export const createIsNegative = /* #__PURE__ */ factory(name, dependencies, ({ t
* Throws an error in case of an unknown data type.
*/
return typed(name, {
number: isNegativeNumber,
number: x => nearlyEqual(x, 0, config.epsilon) ? false : isNegativeNumber(x),

BigNumber: function (x) {
return x.isNeg() && !x.isZero() && !x.isNaN()
},
BigNumber: x => bigNearlyEqual(x, new x.constructor(0), config.epsilon)
? false
: x.isNeg() && !x.isZero() && !x.isNaN(),

Fraction: function (x) {
return x.s < 0 // It's enough to decide on the sign
},
Fraction: x => x.s < 0, // It's enough to decide on the sign

Unit: typed.referToSelf(self =>
x => typed.find(self, x.valueType())(x.value)),
Expand Down
19 changes: 10 additions & 9 deletions src/function/utils/isPositive.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { deepMap } from '../../utils/collection.js'
import { factory } from '../../utils/factory.js'
import { isPositiveNumber } from '../../plain/number/index.js'
import { nearlyEqual as bigNearlyEqual } from '../../utils/bignumber/nearlyEqual.js'
import { nearlyEqual } from '../../utils/number.js'

const name = 'isPositive'
const dependencies = ['typed']
const dependencies = ['typed', 'config']

export const createIsPositive = /* #__PURE__ */ factory(name, dependencies, ({ typed }) => {
export const createIsPositive = /* #__PURE__ */ factory(name, dependencies, ({ typed, config }) => {
/**
* Test whether a value is positive: larger than zero.
* The function supports types `number`, `BigNumber`, `Fraction`, and `Unit`.
Expand Down Expand Up @@ -38,15 +40,14 @@ export const createIsPositive = /* #__PURE__ */ factory(name, dependencies, ({ t
* Throws an error in case of an unknown data type.
*/
return typed(name, {
number: isPositiveNumber,
number: x => nearlyEqual(x, 0, config.epsilon) ? false : isPositiveNumber(x),

BigNumber: function (x) {
return !x.isNeg() && !x.isZero() && !x.isNaN()
},
BigNumber: x =>
bigNearlyEqual(x, new x.constructor(0), config.epsilon)
? false
: !x.isNeg() && !x.isZero() && !x.isNaN(),

Fraction: function (x) {
return x.s > 0 && x.n > 0
},
Fraction: x => x.s > 0 && x.n > 0,

Unit: typed.referToSelf(self =>
x => typed.find(self, x.valueType())(x.value)),
Expand Down
19 changes: 3 additions & 16 deletions src/function/utils/isZero.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { deepMap } from '../../utils/collection.js'
import { factory } from '../../utils/factory.js'
import { isZeroNumber } from '../../plain/number/index.js'

const name = 'isZero'
const dependencies = ['typed']
const dependencies = ['typed', 'equalScalar']

export const createIsZero = /* #__PURE__ */ factory(name, dependencies, ({ typed }) => {
export const createIsZero = /* #__PURE__ */ factory(name, dependencies, ({ typed, equalScalar }) => {
/**
* Test whether a value is zero.
* The function can check for zero for types `number`, `BigNumber`, `Fraction`,
Expand Down Expand Up @@ -40,19 +39,7 @@ export const createIsZero = /* #__PURE__ */ factory(name, dependencies, ({ typed
* Throws an error in case of an unknown data type.
*/
return typed(name, {
number: isZeroNumber,

BigNumber: function (x) {
return x.isZero()
},

Complex: function (x) {
return x.re === 0 && x.im === 0
},

Fraction: function (x) {
return x.d === 1 && x.n === 0
},
'number | BigNumber | Complex | Fraction': x => equalScalar(x, 0),

Unit: typed.referToSelf(self =>
x => typed.find(self, x.valueType())(x.value)),
Expand Down
6 changes: 6 additions & 0 deletions test/unit-tests/function/matrix/det.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ describe('det', function () {
[2, 7, 4, 3, 7]
]), 1176)
assert.strictEqual(det(diag([4, -5, 6])), -120)
assert.strictEqual(
det([
[6.123234262925839e-17, -1, 1],
[-0.8660253882408142, 0.5, 1],
[-0.6495190262794495, -0.3749999701976776, 1]
]), 0.4330126459590976)
})

it('should return the determinant of a sparse matrix', function () {
Expand Down
8 changes: 8 additions & 0 deletions test/unit-tests/function/utils/isNegative.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ describe('isNegative', function () {
assert.strictEqual(isNegative(NaN), false)
})

it('should test whether a number is near negative', function () {
// when epsilon is 1e-12
assert.strictEqual(isNegative(1e-17), false)
assert.strictEqual(isNegative(-1e-17), false)
assert.strictEqual(isNegative(1e-14), false)
assert.strictEqual(isNegative(-1e-14), true)
})

it('should test whether a boolean is negative', function () {
assert.strictEqual(isNegative(true), false)
assert.strictEqual(isNegative(false), false)
Expand Down
8 changes: 8 additions & 0 deletions test/unit-tests/function/utils/isPositive.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ describe('isPositive', function () {
assert.strictEqual(isPositive(NaN), false)
})

it('should test whether a number is near positive', function () {
// when epsilon is 1e-12
assert.strictEqual(isPositive(1e-17), false)
assert.strictEqual(isPositive(-1e-17), false)
assert.strictEqual(isPositive(1e-14), true)
assert.strictEqual(isPositive(-1e-14), false)
})

it('should test whether a boolean is positive', function () {
assert.strictEqual(isPositive(true), true)
assert.strictEqual(isPositive(false), false)
Expand Down
8 changes: 8 additions & 0 deletions test/unit-tests/function/utils/isZero.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ describe('isZero', function () {
assert.strictEqual(isZero(NaN), false)
})

it('should test whether a number is near zero', function () {
// when epsilon is 1e-12
assert.strictEqual(isZero(1e-17), true)
assert.strictEqual(isZero(1e-16), true)
assert.strictEqual(isZero(1e-15), false)
assert.strictEqual(isZero(1e-14), false)
})

it('should test whether a boolean is zero', function () {
assert.strictEqual(isZero(true), false)
assert.strictEqual(isZero(false), true)
Expand Down

0 comments on commit e1817ba

Please sign in to comment.