mathjs/test/unit-tests/function/algebra/simplifyConstant.test.js
Samuel TLG 49fed5bc25
Improve simplifying operations on constants in non-commutative contexts (#2827)
* Simplify: improve constant op. eval. in non-commutative contexts

Addresses the constant evaluation aspect as discussed in #2825.

Changes in simplifyConstant.js are accredited to @gwhitney

* Add simplifyConstant test for expr. with a non-evaluable constant

(uncomments a pre-existing test suggestion for an 'incomplete'
simplification example, more specifically)

Additionally adds commented TODO tests for additional expr. variations
with current incomplete simplification (non-commutative context)
2022-11-08 15:17:22 +01:00

87 lines
3.7 KiB
JavaScript

// test simplifyConstant
import assert from 'assert'
import math from '../../../../src/defaultInstance.js'
describe('simplifyConstant', function () {
const testSimplifyConstant = function (expr, expected, opts = {}, simpOpts = {}) {
let actual = math.simplifyConstant(math.parse(expr), simpOpts).toString(opts)
assert.strictEqual(actual, expected)
actual = math.simplifyConstant(expr, simpOpts).toString(opts)
assert.strictEqual(actual, expected)
}
it('should evaluate constant subexpressions', function () {
testSimplifyConstant('2+2', '4')
testSimplifyConstant('x+3*5', 'x + 15')
testSimplifyConstant('f(sin(0))', 'f(0)')
testSimplifyConstant('[10/2, y, 8-4]', '[5, y, 4]')
})
it('should by default convert decimals into fractions', function () {
testSimplifyConstant('0.5 x', '1 / 2 x')
})
describe('should coalesce constants in a multi-argument expression', function () {
it('in the default context', function () {
testSimplifyConstant('3 + x + 7 + y', '10 + x + y')
testSimplifyConstant('3 * x * 7 * y', '21 * x * y')
// including an 'unevaluable' constant
// note: output here not currently as expected/desired ( '20 + "foo"' )
testSimplifyConstant('2 + 7 + "foo" + 3 + 8', '9 + "foo" + 11')
// (^ todo (FIX): constant evaluation (in the default context) should be able to simplify all
// evaluable constants in a multi-arg expression containing a non evaluable/collapsable
// constant such as 'foo')
})
it('in non-commutative contexts', function () {
const context = {
add: { commutative: false },
multiply: { commutative: false }
}
const opts = { context }
/*
* Exprs. with non-constants/symbols
*/
// leading consts.
testSimplifyConstant('2 + 2 + a', '4 + a', undefined, opts)
testSimplifyConstant('2 * 2 * b', '4 * b', undefined, opts)
// trailing consts.
testSimplifyConstant('a + 3 + 2', 'a + 5', undefined, opts)
testSimplifyConstant('a * 3 * 2', 'a * 6', undefined, opts)
// 'wedged' constants
testSimplifyConstant('a + 3 + 2 + a + 4 + 4 + b', 'a + 5 + a + 8 + b', undefined, opts)
testSimplifyConstant('c * 3 * 2 * d * 4 * 1 * d', 'c * 6 * d * 4 * d', undefined, opts)
// including an 'unevaluable' constant
testSimplifyConstant('2 + 7 + "foo" + 3 + 8', '9 + "foo" + 11', undefined, opts)
// collapsing of constants with a 'falsy' value (e.g. '0')
testSimplifyConstant('a + 0 + 7 + b', 'a + 7 + b', undefined, opts)
// TODO: implement support for simplification of constant sub-expressions for inverses of
// commutative ops. (i.e. addition/subtraction), in cases for expressions with leading
// symbols, and with 'wedged' constants. Expected behaviour is illustrated with todo-tests
// below.
// - note that these tests are only apt for this block (multi arg expressions) if
// simplifyConstant is later able to flatten inverse commutative binary ops
// - for all of the following tests, output remains unchanged
// testSimplifyConstant('a + 2 - 2', 'a', undefined, opts)
// testSimplifyConstant('b + 4 - 2 - 1 + b', 'b + 1 + b', undefined, opts)
// testSimplifyConstant('c * 6 / 3', 'c * 2', undefined, opts)
// testSimplifyConstant('c * 1 / 1 * 3 * d', 'c * 3 * d', undefined, opts)
})
})
it('should respect simplify options', function () {
testSimplifyConstant('0.5 x', '0.5 * x', { implicit: 'show' },
{ exactFractions: false })
testSimplifyConstant('0.001 x', '0.001 * x', { implicit: 'show' },
{ fractionsLimit: 999 })
testSimplifyConstant('3 * x * 7 * y', '3 * x * 7 * y', {},
{ context: { multiply: { commutative: false } } })
})
})