@cortex-js/compute-engine 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compute-engine.esm.js +746 -671
- package/dist/compute-engine.min.esm.js +2 -2
- package/dist/compute-engine.min.js +2 -2
- package/dist/math-json.esm.js +2 -2
- package/dist/math-json.min.esm.js +2 -2
- package/dist/math-json.min.js +2 -2
- package/dist/types/common/grapheme-splitter.d.ts +1 -1
- package/dist/types/common/signals.d.ts +1 -1
- package/dist/types/compute-engine/assume.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/abstract-boxed-expression.d.ts +65 -62
- package/dist/types/compute-engine/boxed-expression/box.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/boxed-dictionary.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/boxed-domain.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/boxed-function-definition.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/boxed-function.d.ts +38 -31
- package/dist/types/compute-engine/boxed-expression/boxed-number.d.ts +4 -2
- package/dist/types/compute-engine/boxed-expression/boxed-patterns.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/boxed-string.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/boxed-symbol-definition.d.ts +6 -6
- package/dist/types/compute-engine/boxed-expression/boxed-symbol.d.ts +6 -6
- package/dist/types/compute-engine/boxed-expression/expression-map.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/order.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/serialize.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/utils.d.ts +3 -3
- package/dist/types/compute-engine/compute-engine.d.ts +2 -3
- package/dist/types/compute-engine/cost-function.d.ts +1 -1
- package/dist/types/compute-engine/domain-utils.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/dictionary/definitions-algebra.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/dictionary/definitions-arithmetic.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/dictionary/definitions-calculus.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/dictionary/definitions-core.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/dictionary/definitions-inequalities.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/dictionary/definitions-logic.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/dictionary/definitions-other.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/dictionary/definitions-sets.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/dictionary/definitions-symbols.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/dictionary/definitions-trigonometry.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/dictionary/definitions.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/latex-syntax.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/parse.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/public.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/serialize-number.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/serializer-style.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/serializer.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/tokenizer.d.ts +1 -1
- package/dist/types/compute-engine/library/arithmetic-add.d.ts +1 -1
- package/dist/types/compute-engine/library/arithmetic-divide.d.ts +1 -1
- package/dist/types/compute-engine/library/arithmetic-multiply.d.ts +1 -1
- package/dist/types/compute-engine/library/arithmetic-power.d.ts +1 -1
- package/dist/types/compute-engine/library/arithmetic.d.ts +1 -1
- package/dist/types/compute-engine/library/calculus.d.ts +1 -1
- package/dist/types/compute-engine/library/collections.d.ts +1 -1
- package/dist/types/compute-engine/library/core.d.ts +1 -1
- package/dist/types/compute-engine/library/domains.d.ts +1 -1
- package/dist/types/compute-engine/library/library.d.ts +1 -1
- package/dist/types/compute-engine/library/logic.d.ts +1 -1
- package/dist/types/compute-engine/library/polynomials.d.ts +1 -1
- package/dist/types/compute-engine/library/relational-operator.d.ts +1 -1
- package/dist/types/compute-engine/library/sets.d.ts +1 -1
- package/dist/types/compute-engine/library/trigonometry.d.ts +1 -1
- package/dist/types/compute-engine/numerics/numeric-complex.d.ts +1 -1
- package/dist/types/compute-engine/numerics/numeric-decimal.d.ts +1 -1
- package/dist/types/compute-engine/numerics/numeric.d.ts +1 -1
- package/dist/types/compute-engine/numerics/primes.d.ts +1 -1
- package/dist/types/compute-engine/public.d.ts +514 -351
- package/dist/types/compute-engine/rules.d.ts +1 -1
- package/dist/types/compute-engine/simplify-rules.d.ts +1 -1
- package/dist/types/compute-engine/symbolic/expand.d.ts +1 -1
- package/dist/types/compute-engine/symbolic/flatten.d.ts +1 -1
- package/dist/types/compute-engine/symbolic/negate.d.ts +1 -1
- package/dist/types/compute-engine/symbolic/polynomials.d.ts +1 -1
- package/dist/types/compute-engine/symbolic/product.d.ts +1 -1
- package/dist/types/compute-engine/symbolic/sum.d.ts +1 -1
- package/dist/types/compute-engine/symbolic/utils.d.ts +1 -1
- package/dist/types/compute-engine.d.ts +2 -2
- package/dist/types/math-json/math-json-format.d.ts +1 -1
- package/dist/types/math-json/utils.d.ts +1 -1
- package/dist/types/math-json.d.ts +2 -2
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** CortexJS Compute Engine 0.
|
|
1
|
+
/** CortexJS Compute Engine 0.8.0 */
|
|
2
2
|
/** @internal */
|
|
3
3
|
function isSymbolEntry(entry) {
|
|
4
4
|
return !('kind' in entry) || entry.kind === 'symbol';
|
|
@@ -29,7 +29,7 @@ function isEnvironmentEntry(entry) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/*!
|
|
32
|
-
* decimal.js v10.4.
|
|
32
|
+
* decimal.js v10.4.1
|
|
33
33
|
* An arbitrary-precision Decimal type for JavaScript.
|
|
34
34
|
* https://github.com/MikeMcl/decimal.js
|
|
35
35
|
* Copyright (c) 2022 Michael Mclaughlin <M8ch88l@gmail.com>
|
|
@@ -7287,8 +7287,23 @@ function numeratorDenominator(expr) {
|
|
|
7287
7287
|
}
|
|
7288
7288
|
}
|
|
7289
7289
|
}
|
|
7290
|
+
else if (head(arg) === 'Rational' && nops(arg) === 2) {
|
|
7291
|
+
const op1 = op(arg, 1);
|
|
7292
|
+
const op2 = op(arg, 2);
|
|
7293
|
+
if (machineValue(op1) !== 1)
|
|
7294
|
+
numerator.push(op1);
|
|
7295
|
+
if (machineValue(op2) !== 1)
|
|
7296
|
+
denominator.push(op2);
|
|
7297
|
+
}
|
|
7290
7298
|
else {
|
|
7291
|
-
|
|
7299
|
+
const [n, d] = rationalValue(arg);
|
|
7300
|
+
if (n !== null) {
|
|
7301
|
+
if (n !== 1)
|
|
7302
|
+
numerator.push(n);
|
|
7303
|
+
denominator.push(d);
|
|
7304
|
+
}
|
|
7305
|
+
else
|
|
7306
|
+
numerator.push(arg);
|
|
7292
7307
|
}
|
|
7293
7308
|
}
|
|
7294
7309
|
return [numerator, denominator];
|
|
@@ -7422,15 +7437,12 @@ function serializeMultiply(serializer, expr) {
|
|
|
7422
7437
|
const [numer, denom] = numeratorDenominator(expr);
|
|
7423
7438
|
if (denom.length > 0) {
|
|
7424
7439
|
if (denom.length === 1 && denom[0] === 1) {
|
|
7425
|
-
if (numer.length === 0)
|
|
7440
|
+
if (numer.length === 0)
|
|
7426
7441
|
result = '1';
|
|
7427
|
-
|
|
7428
|
-
else if (numer.length === 1) {
|
|
7442
|
+
else if (numer.length === 1)
|
|
7429
7443
|
result = serializer.serialize(numer[0]);
|
|
7430
|
-
|
|
7431
|
-
else {
|
|
7444
|
+
else
|
|
7432
7445
|
result = serializeMultiply(serializer, [MULTIPLY, ...numer]);
|
|
7433
|
-
}
|
|
7434
7446
|
}
|
|
7435
7447
|
else {
|
|
7436
7448
|
result = serializer.serialize([
|
|
@@ -7986,7 +7998,11 @@ const DEFINITIONS_ARITHMETIC = [
|
|
|
7986
7998
|
{
|
|
7987
7999
|
name: 'Rational',
|
|
7988
8000
|
precedence: 660,
|
|
7989
|
-
serialize:
|
|
8001
|
+
serialize: (serializer, expr) => {
|
|
8002
|
+
if (expr && nops(expr) === 1)
|
|
8003
|
+
return '\\mathrm{Rational}' + serializer.wrapArguments(expr);
|
|
8004
|
+
return serializeFraction(serializer, expr);
|
|
8005
|
+
},
|
|
7990
8006
|
},
|
|
7991
8007
|
{
|
|
7992
8008
|
name: ROOT,
|
|
@@ -14914,8 +14930,8 @@ function preferDecimal(ce) {
|
|
|
14914
14930
|
return (ce.numericMode === 'decimal' ||
|
|
14915
14931
|
(ce.numericMode === 'auto' && ce.precision > Math.floor(MACHINE_PRECISION)));
|
|
14916
14932
|
}
|
|
14917
|
-
/**
|
|
14918
|
-
* return `NaN` if `
|
|
14933
|
+
/** When result of a numeric evaluation is a complex number,
|
|
14934
|
+
* return `NaN` if not `complexallowed()`
|
|
14919
14935
|
*/
|
|
14920
14936
|
function complexAllowed(ce) {
|
|
14921
14937
|
return ce.numericMode === 'auto' || ce.numericMode === 'complex';
|
|
@@ -14968,20 +14984,32 @@ class AbstractBoxedExpression {
|
|
|
14968
14984
|
if (metadata?.wikidata !== undefined)
|
|
14969
14985
|
this._wikidata = metadata.wikidata;
|
|
14970
14986
|
}
|
|
14971
|
-
/** Object.
|
|
14972
|
-
|
|
14973
|
-
|
|
14987
|
+
/** `Object.valueOf()`: return a primitive value for the object
|
|
14988
|
+
*
|
|
14989
|
+
*/
|
|
14990
|
+
valueOf() {
|
|
14991
|
+
if (this.symbol === 'True')
|
|
14992
|
+
return true;
|
|
14993
|
+
if (this.symbol === 'False')
|
|
14994
|
+
return false;
|
|
14995
|
+
return (this.asFloat ?? this.string ?? this.symbol ?? JSON.stringify(this.json));
|
|
14974
14996
|
}
|
|
14975
14997
|
/** Object.toString() */
|
|
14976
14998
|
toString() {
|
|
14977
|
-
return this.
|
|
14999
|
+
return String(this.valueOf());
|
|
14978
15000
|
}
|
|
14979
|
-
|
|
14980
|
-
|
|
14981
|
-
|
|
14982
|
-
if (
|
|
14983
|
-
|
|
14984
|
-
|
|
15001
|
+
[Symbol.toPrimitive](hint) {
|
|
15002
|
+
if (hint === 'string')
|
|
15003
|
+
return this.toString();
|
|
15004
|
+
if (hint === 'number') {
|
|
15005
|
+
const v = this.valueOf();
|
|
15006
|
+
return typeof v === 'number' ? v : null;
|
|
15007
|
+
}
|
|
15008
|
+
return this.toString();
|
|
15009
|
+
}
|
|
15010
|
+
/** Called by `JSON.stringify()` when serializing to json */
|
|
15011
|
+
toJSON() {
|
|
15012
|
+
return this.json;
|
|
14985
15013
|
}
|
|
14986
15014
|
/** Object.is() */
|
|
14987
15015
|
is(rhs) {
|
|
@@ -14989,49 +15017,20 @@ class AbstractBoxedExpression {
|
|
|
14989
15017
|
return false;
|
|
14990
15018
|
return this.isSame(this.engine.box(rhs));
|
|
14991
15019
|
}
|
|
14992
|
-
isCompatible(_dom, _kind) {
|
|
14993
|
-
return false;
|
|
14994
|
-
}
|
|
14995
|
-
has(_v) {
|
|
14996
|
-
return false;
|
|
14997
|
-
}
|
|
14998
|
-
get description() {
|
|
14999
|
-
return [];
|
|
15000
|
-
}
|
|
15001
|
-
get url() {
|
|
15002
|
-
return '';
|
|
15003
|
-
}
|
|
15004
|
-
get isPure() {
|
|
15005
|
-
return false;
|
|
15006
|
-
}
|
|
15007
|
-
/** For a symbol, true if the symbol is a free variable (no value) */
|
|
15008
|
-
get isFree() {
|
|
15009
|
-
return false;
|
|
15010
|
-
}
|
|
15011
|
-
/** For a symbol, true if the symbol is a constant (unchangeable value) */
|
|
15012
|
-
get isConstant() {
|
|
15013
|
-
return false;
|
|
15014
|
-
}
|
|
15015
|
-
get isLiteral() {
|
|
15016
|
-
return false;
|
|
15017
|
-
}
|
|
15018
15020
|
get latex() {
|
|
15019
15021
|
return this._latex ?? this.engine.serialize(this);
|
|
15020
15022
|
}
|
|
15021
15023
|
set latex(val) {
|
|
15022
15024
|
this._latex = val;
|
|
15023
15025
|
}
|
|
15024
|
-
get
|
|
15025
|
-
return
|
|
15026
|
-
}
|
|
15027
|
-
set wikidata(val) {
|
|
15028
|
-
this._wikidata = val;
|
|
15026
|
+
get symbol() {
|
|
15027
|
+
return null;
|
|
15029
15028
|
}
|
|
15030
|
-
get
|
|
15031
|
-
return
|
|
15029
|
+
get isNothing() {
|
|
15030
|
+
return false;
|
|
15032
15031
|
}
|
|
15033
|
-
get
|
|
15034
|
-
return
|
|
15032
|
+
get string() {
|
|
15033
|
+
return null;
|
|
15035
15034
|
}
|
|
15036
15035
|
getSubexpressions(head) {
|
|
15037
15036
|
return getSubexpressions(this, head);
|
|
@@ -15039,6 +15038,9 @@ class AbstractBoxedExpression {
|
|
|
15039
15038
|
get subexpressions() {
|
|
15040
15039
|
return this.getSubexpressions('');
|
|
15041
15040
|
}
|
|
15041
|
+
get symbols() {
|
|
15042
|
+
return [...getSymbols(this, new Set())].map((x) => this.engine.symbol(x));
|
|
15043
|
+
}
|
|
15042
15044
|
get errors() {
|
|
15043
15045
|
return this.getSubexpressions('Error');
|
|
15044
15046
|
}
|
|
@@ -15058,88 +15060,94 @@ class AbstractBoxedExpression {
|
|
|
15058
15060
|
get op3() {
|
|
15059
15061
|
return this.engine.symbol('Nothing');
|
|
15060
15062
|
}
|
|
15061
|
-
get
|
|
15062
|
-
return
|
|
15063
|
+
get isValid() {
|
|
15064
|
+
return true;
|
|
15063
15065
|
}
|
|
15064
|
-
get
|
|
15065
|
-
return
|
|
15066
|
+
get isPure() {
|
|
15067
|
+
return false;
|
|
15066
15068
|
}
|
|
15067
|
-
|
|
15068
|
-
|
|
15069
|
+
/** For a symbol, true if the symbol is a free variable (no value) */
|
|
15070
|
+
get isFree() {
|
|
15071
|
+
return false;
|
|
15069
15072
|
}
|
|
15070
|
-
|
|
15071
|
-
|
|
15073
|
+
/** For a symbol, true if the symbol is a constant (unchangeable value) */
|
|
15074
|
+
get isConstant() {
|
|
15075
|
+
return false;
|
|
15072
15076
|
}
|
|
15073
|
-
|
|
15074
|
-
return;
|
|
15077
|
+
get canonical() {
|
|
15078
|
+
return this;
|
|
15075
15079
|
}
|
|
15076
|
-
|
|
15077
|
-
return
|
|
15080
|
+
apply(_fn, _head) {
|
|
15081
|
+
return this;
|
|
15078
15082
|
}
|
|
15079
|
-
|
|
15080
|
-
return
|
|
15083
|
+
subs(_sub) {
|
|
15084
|
+
return this;
|
|
15081
15085
|
}
|
|
15082
|
-
|
|
15083
|
-
return
|
|
15086
|
+
solve(_vars) {
|
|
15087
|
+
return null;
|
|
15084
15088
|
}
|
|
15085
|
-
|
|
15089
|
+
replace(_rules) {
|
|
15090
|
+
return null;
|
|
15091
|
+
}
|
|
15092
|
+
has(_v) {
|
|
15086
15093
|
return false;
|
|
15087
15094
|
}
|
|
15088
|
-
get
|
|
15089
|
-
return
|
|
15095
|
+
get isNaN() {
|
|
15096
|
+
return undefined;
|
|
15090
15097
|
}
|
|
15091
|
-
get
|
|
15092
|
-
return
|
|
15098
|
+
get isZero() {
|
|
15099
|
+
return undefined;
|
|
15093
15100
|
}
|
|
15094
|
-
get
|
|
15095
|
-
return
|
|
15101
|
+
get isNotZero() {
|
|
15102
|
+
return undefined;
|
|
15096
15103
|
}
|
|
15097
|
-
get
|
|
15098
|
-
return
|
|
15104
|
+
get isOne() {
|
|
15105
|
+
return undefined;
|
|
15099
15106
|
}
|
|
15100
|
-
get
|
|
15101
|
-
return
|
|
15107
|
+
get isNegativeOne() {
|
|
15108
|
+
return undefined;
|
|
15102
15109
|
}
|
|
15103
|
-
get
|
|
15104
|
-
return
|
|
15110
|
+
get isInfinity() {
|
|
15111
|
+
return undefined;
|
|
15105
15112
|
}
|
|
15106
|
-
|
|
15107
|
-
|
|
15113
|
+
// Not +- Infinity, not NaN
|
|
15114
|
+
get isFinite() {
|
|
15115
|
+
return undefined;
|
|
15108
15116
|
}
|
|
15109
|
-
get
|
|
15110
|
-
return
|
|
15117
|
+
get isEven() {
|
|
15118
|
+
return undefined;
|
|
15111
15119
|
}
|
|
15112
|
-
get
|
|
15113
|
-
return
|
|
15120
|
+
get isOdd() {
|
|
15121
|
+
return undefined;
|
|
15114
15122
|
}
|
|
15115
|
-
get
|
|
15116
|
-
return
|
|
15123
|
+
get isPrime() {
|
|
15124
|
+
return undefined;
|
|
15117
15125
|
}
|
|
15118
|
-
get
|
|
15119
|
-
return
|
|
15126
|
+
get isComposite() {
|
|
15127
|
+
return undefined;
|
|
15120
15128
|
}
|
|
15121
|
-
get
|
|
15122
|
-
return
|
|
15129
|
+
get machineValue() {
|
|
15130
|
+
return null;
|
|
15123
15131
|
}
|
|
15124
|
-
|
|
15125
|
-
|
|
15132
|
+
get rationalValue() {
|
|
15133
|
+
return [null, null];
|
|
15126
15134
|
}
|
|
15127
|
-
get
|
|
15128
|
-
return
|
|
15135
|
+
get decimalValue() {
|
|
15136
|
+
return null;
|
|
15129
15137
|
}
|
|
15130
|
-
|
|
15131
|
-
return
|
|
15138
|
+
get complexValue() {
|
|
15139
|
+
return null;
|
|
15132
15140
|
}
|
|
15133
|
-
get
|
|
15134
|
-
return
|
|
15141
|
+
get asFloat() {
|
|
15142
|
+
return null;
|
|
15135
15143
|
}
|
|
15136
|
-
|
|
15137
|
-
|
|
15144
|
+
get asSmallInteger() {
|
|
15145
|
+
return null;
|
|
15138
15146
|
}
|
|
15139
|
-
get
|
|
15140
|
-
return
|
|
15147
|
+
get asRational() {
|
|
15148
|
+
return [null, null];
|
|
15141
15149
|
}
|
|
15142
|
-
get
|
|
15150
|
+
get sgn() {
|
|
15143
15151
|
return null;
|
|
15144
15152
|
}
|
|
15145
15153
|
isLess(_rhs) {
|
|
@@ -15154,12 +15162,6 @@ class AbstractBoxedExpression {
|
|
|
15154
15162
|
isGreaterEqual(_rhs) {
|
|
15155
15163
|
return undefined;
|
|
15156
15164
|
}
|
|
15157
|
-
get isZero() {
|
|
15158
|
-
return undefined;
|
|
15159
|
-
}
|
|
15160
|
-
get isNotZero() {
|
|
15161
|
-
return undefined;
|
|
15162
|
-
}
|
|
15163
15165
|
// x > 0
|
|
15164
15166
|
get isPositive() {
|
|
15165
15167
|
return undefined;
|
|
@@ -15176,16 +15178,80 @@ class AbstractBoxedExpression {
|
|
|
15176
15178
|
get isNonPositive() {
|
|
15177
15179
|
return undefined;
|
|
15178
15180
|
}
|
|
15179
|
-
|
|
15181
|
+
//
|
|
15182
|
+
//
|
|
15183
|
+
//
|
|
15184
|
+
//
|
|
15185
|
+
//
|
|
15186
|
+
isCompatible(_dom, _kind) {
|
|
15187
|
+
return false;
|
|
15188
|
+
}
|
|
15189
|
+
get description() {
|
|
15180
15190
|
return undefined;
|
|
15181
15191
|
}
|
|
15182
|
-
get
|
|
15192
|
+
get url() {
|
|
15183
15193
|
return undefined;
|
|
15184
15194
|
}
|
|
15185
|
-
|
|
15186
|
-
|
|
15195
|
+
get isLiteral() {
|
|
15196
|
+
return false;
|
|
15197
|
+
}
|
|
15198
|
+
get wikidata() {
|
|
15199
|
+
return this._wikidata;
|
|
15200
|
+
}
|
|
15201
|
+
set wikidata(val) {
|
|
15202
|
+
this._wikidata = val;
|
|
15203
|
+
}
|
|
15204
|
+
get complexity() {
|
|
15205
|
+
return undefined;
|
|
15206
|
+
}
|
|
15207
|
+
get basedDefinition() {
|
|
15208
|
+
return undefined;
|
|
15209
|
+
}
|
|
15210
|
+
get symbolDefinition() {
|
|
15211
|
+
return undefined;
|
|
15212
|
+
}
|
|
15213
|
+
get functionDefinition() {
|
|
15214
|
+
return undefined;
|
|
15215
|
+
}
|
|
15216
|
+
bind(_scope) {
|
|
15217
|
+
return;
|
|
15218
|
+
}
|
|
15219
|
+
unbind() {
|
|
15220
|
+
return;
|
|
15221
|
+
}
|
|
15222
|
+
get keys() {
|
|
15223
|
+
return null;
|
|
15224
|
+
}
|
|
15225
|
+
get keysCount() {
|
|
15226
|
+
return 0;
|
|
15227
|
+
}
|
|
15228
|
+
getKey(_key) {
|
|
15229
|
+
return undefined;
|
|
15230
|
+
}
|
|
15231
|
+
hasKey(_key) {
|
|
15232
|
+
return false;
|
|
15233
|
+
}
|
|
15234
|
+
get value() {
|
|
15235
|
+
return undefined;
|
|
15236
|
+
}
|
|
15237
|
+
set value(_value) {
|
|
15238
|
+
throw new Error(`Can't change the value of \\(${this.latex}\\)`);
|
|
15239
|
+
}
|
|
15240
|
+
get numericValue() {
|
|
15241
|
+
return undefined;
|
|
15242
|
+
}
|
|
15243
|
+
isSubdomainOf(_d) {
|
|
15187
15244
|
return undefined;
|
|
15188
15245
|
}
|
|
15246
|
+
get domain() {
|
|
15247
|
+
return this.engine.domain('Void');
|
|
15248
|
+
}
|
|
15249
|
+
set domain(_domain) {
|
|
15250
|
+
throw new Error(`Can't change the domain of \\(${this.latex}\\)`);
|
|
15251
|
+
}
|
|
15252
|
+
get explicitDomain() {
|
|
15253
|
+
return this.domain;
|
|
15254
|
+
}
|
|
15189
15255
|
get isNumber() {
|
|
15190
15256
|
return undefined;
|
|
15191
15257
|
}
|
|
@@ -15214,47 +15280,14 @@ class AbstractBoxedExpression {
|
|
|
15214
15280
|
get isExtendedComplex() {
|
|
15215
15281
|
return undefined;
|
|
15216
15282
|
}
|
|
15217
|
-
|
|
15218
|
-
return undefined;
|
|
15219
|
-
}
|
|
15220
|
-
get isNegativeOne() {
|
|
15221
|
-
return undefined;
|
|
15222
|
-
}
|
|
15223
|
-
get isEven() {
|
|
15224
|
-
return undefined;
|
|
15225
|
-
}
|
|
15226
|
-
get isOdd() {
|
|
15227
|
-
return undefined;
|
|
15228
|
-
}
|
|
15229
|
-
get isPrime() {
|
|
15230
|
-
return undefined;
|
|
15231
|
-
}
|
|
15232
|
-
get isComposite() {
|
|
15233
|
-
return undefined;
|
|
15234
|
-
}
|
|
15235
|
-
get canonical() {
|
|
15236
|
-
return this;
|
|
15237
|
-
}
|
|
15238
|
-
apply(_fn, _head) {
|
|
15283
|
+
simplify(_options) {
|
|
15239
15284
|
return this;
|
|
15240
15285
|
}
|
|
15241
15286
|
evaluate(options) {
|
|
15242
15287
|
return this.simplify(options);
|
|
15243
15288
|
}
|
|
15244
|
-
simplify(_options) {
|
|
15245
|
-
return this;
|
|
15246
|
-
}
|
|
15247
15289
|
N(_options) {
|
|
15248
|
-
return this;
|
|
15249
|
-
}
|
|
15250
|
-
replace(_rules) {
|
|
15251
|
-
return null;
|
|
15252
|
-
}
|
|
15253
|
-
subs(_sub) {
|
|
15254
|
-
return this;
|
|
15255
|
-
}
|
|
15256
|
-
solve(_vars) {
|
|
15257
|
-
return null;
|
|
15290
|
+
return this.evaluate();
|
|
15258
15291
|
}
|
|
15259
15292
|
}
|
|
15260
15293
|
|
|
@@ -15642,12 +15675,12 @@ function order(a, b) {
|
|
|
15642
15675
|
let bComplexity = 0;
|
|
15643
15676
|
let aComplexity = 0;
|
|
15644
15677
|
for (const key of b.keys)
|
|
15645
|
-
bComplexity += b.getKey(key).complexity;
|
|
15678
|
+
bComplexity += b.getKey(key).complexity ?? DEFAULT_COMPLEXITY;
|
|
15646
15679
|
for (const key of a.keys)
|
|
15647
|
-
aComplexity += a.getKey(key).complexity;
|
|
15680
|
+
aComplexity += a.getKey(key).complexity ?? DEFAULT_COMPLEXITY;
|
|
15648
15681
|
return aComplexity - bComplexity;
|
|
15649
15682
|
}
|
|
15650
|
-
return a.complexity - b.complexity;
|
|
15683
|
+
return ((a.complexity ?? DEFAULT_COMPLEXITY) - (b.complexity ?? DEFAULT_COMPLEXITY));
|
|
15651
15684
|
}
|
|
15652
15685
|
/** Get the number of atomic elements in the expression */
|
|
15653
15686
|
function getLeafCount(expr) {
|
|
@@ -16304,7 +16337,7 @@ function serializeJsonNumber(ce, value, metadata) {
|
|
|
16304
16337
|
num =
|
|
16305
16338
|
value.isInteger() && value.e < value.precision() + 4
|
|
16306
16339
|
? value.toFixed(0)
|
|
16307
|
-
: repeatingDecimal(ce, value.
|
|
16340
|
+
: repeatingDecimal(ce, value.toString());
|
|
16308
16341
|
}
|
|
16309
16342
|
if (ce.jsonSerializationOptions.metadata.includes('latex'))
|
|
16310
16343
|
metadata.latex = metadata.latex ?? ce.serialize({ num });
|
|
@@ -16903,20 +16936,26 @@ function includesDomain(xs, y) {
|
|
|
16903
16936
|
return false;
|
|
16904
16937
|
}
|
|
16905
16938
|
function serialize(ce, dom) {
|
|
16939
|
+
if (dom instanceof AbstractBoxedExpression)
|
|
16940
|
+
return dom.json;
|
|
16906
16941
|
if (typeof dom === 'string')
|
|
16907
|
-
return
|
|
16942
|
+
return dom;
|
|
16908
16943
|
if (dom[0] === 'Error') {
|
|
16909
16944
|
if (dom[2])
|
|
16910
|
-
return [
|
|
16911
|
-
|
|
16945
|
+
return [
|
|
16946
|
+
'Error',
|
|
16947
|
+
serialize(ce, dom[1]),
|
|
16948
|
+
serialize(ce, dom[2]),
|
|
16949
|
+
];
|
|
16950
|
+
return [
|
|
16951
|
+
'Error',
|
|
16952
|
+
serialize(ce, dom[1]),
|
|
16953
|
+
];
|
|
16912
16954
|
}
|
|
16913
16955
|
const result = [serializeJsonSymbol(ce, dom[0])];
|
|
16914
|
-
|
|
16915
|
-
|
|
16916
|
-
|
|
16917
|
-
else
|
|
16918
|
-
result.push(serialize(ce, dom[i]));
|
|
16919
|
-
}
|
|
16956
|
+
if (dom.length > 1)
|
|
16957
|
+
for (let i = 1; i <= dom.length - 1; i++)
|
|
16958
|
+
serialize(ce, dom[i]);
|
|
16920
16959
|
return result;
|
|
16921
16960
|
}
|
|
16922
16961
|
function hash(dom) {
|
|
@@ -17739,17 +17778,40 @@ function cheapest(oldExpr, newExpr) {
|
|
|
17739
17778
|
* BoxedFunction
|
|
17740
17779
|
*/
|
|
17741
17780
|
class BoxedFunction extends AbstractBoxedExpression {
|
|
17742
|
-
constructor(ce, head, ops,
|
|
17743
|
-
|
|
17781
|
+
constructor(ce, head, ops, options) {
|
|
17782
|
+
options ?? (options = {});
|
|
17783
|
+
options.canonical ?? (options.canonical = false);
|
|
17784
|
+
super(ce, options.metadata);
|
|
17744
17785
|
this._scope = ce.context;
|
|
17745
|
-
this._head =
|
|
17786
|
+
this._head = head;
|
|
17746
17787
|
this._ops = ops;
|
|
17747
|
-
|
|
17788
|
+
if (options.canonical)
|
|
17789
|
+
this._canonical = this;
|
|
17790
|
+
this._def = options.def ?? null; // Mark the def as not yet cached if none is provided
|
|
17748
17791
|
this._codomain = null;
|
|
17749
|
-
this.
|
|
17792
|
+
if (typeof this._head !== 'string')
|
|
17793
|
+
this._codomain = this._head.domain.codomain;
|
|
17794
|
+
else if (this._def) {
|
|
17795
|
+
const sig = this._def.signature;
|
|
17796
|
+
if (typeof sig.codomain === 'function') {
|
|
17797
|
+
this._codomain =
|
|
17798
|
+
sig.codomain(ce, this._ops.map((x) => x.domain)) ?? null;
|
|
17799
|
+
}
|
|
17800
|
+
else {
|
|
17801
|
+
this._codomain = sig.codomain ?? null;
|
|
17802
|
+
}
|
|
17803
|
+
}
|
|
17804
|
+
if (!this._codomain)
|
|
17805
|
+
this._codomain = ce.defaultDomain ?? ce.domain('Void');
|
|
17750
17806
|
// Note: _isPure is computed on demand and cached
|
|
17751
17807
|
ce._register(this);
|
|
17752
17808
|
}
|
|
17809
|
+
//
|
|
17810
|
+
// NON-CANONICAL OR CANONICAL OPERATIONS
|
|
17811
|
+
//
|
|
17812
|
+
// Those operations/properties can be applied to a canonical or
|
|
17813
|
+
// non-canonical expression
|
|
17814
|
+
//
|
|
17753
17815
|
get hash() {
|
|
17754
17816
|
if (this._hash !== undefined)
|
|
17755
17817
|
return this._hash;
|
|
@@ -17763,88 +17825,41 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
17763
17825
|
this._hash = h;
|
|
17764
17826
|
return h;
|
|
17765
17827
|
}
|
|
17766
|
-
|
|
17767
|
-
|
|
17768
|
-
this._head.unbind();
|
|
17769
|
-
for (const arg of this._ops)
|
|
17770
|
-
arg.unbind();
|
|
17771
|
-
if (this._value)
|
|
17772
|
-
this._value.unbind();
|
|
17773
|
-
if (this._numericValue)
|
|
17774
|
-
this._numericValue.unbind();
|
|
17775
|
-
}
|
|
17776
|
-
get wikidata() {
|
|
17777
|
-
return this._wikidata ?? this.functionDefinition?.wikidata ?? '';
|
|
17778
|
-
}
|
|
17779
|
-
get description() {
|
|
17780
|
-
const def = this.functionDefinition;
|
|
17781
|
-
if (!def)
|
|
17782
|
-
return [];
|
|
17783
|
-
if (!def.description)
|
|
17784
|
-
return [];
|
|
17785
|
-
if (typeof def.description === 'string')
|
|
17786
|
-
return [def.description];
|
|
17787
|
-
return def.description;
|
|
17788
|
-
}
|
|
17789
|
-
get url() {
|
|
17790
|
-
return this.functionDefinition?.url ?? '';
|
|
17791
|
-
}
|
|
17792
|
-
get complexity() {
|
|
17793
|
-
return this.functionDefinition?.complexity ?? DEFAULT_COMPLEXITY;
|
|
17794
|
-
}
|
|
17795
|
-
get head() {
|
|
17796
|
-
return this._head;
|
|
17828
|
+
get isCanonical() {
|
|
17829
|
+
return this._canonical === this;
|
|
17797
17830
|
}
|
|
17798
|
-
|
|
17799
|
-
|
|
17800
|
-
return undefined;
|
|
17801
|
-
// Use cached value if the function is pure
|
|
17802
|
-
if (this._value)
|
|
17803
|
-
return this._value;
|
|
17804
|
-
this._value = this.evaluate();
|
|
17805
|
-
return this._value;
|
|
17831
|
+
set isCanonical(val) {
|
|
17832
|
+
this._canonical = val ? this : undefined;
|
|
17806
17833
|
}
|
|
17807
|
-
get
|
|
17808
|
-
|
|
17809
|
-
return undefined;
|
|
17810
|
-
if (this._numericValue)
|
|
17811
|
-
return this._numericValue;
|
|
17812
|
-
const val = this.N();
|
|
17813
|
-
this._numericValue = val.isLiteral ? val : undefined;
|
|
17814
|
-
return this._numericValue;
|
|
17834
|
+
get isLiteral() {
|
|
17835
|
+
return false;
|
|
17815
17836
|
}
|
|
17816
17837
|
get isPure() {
|
|
17838
|
+
if (!this.isCanonical)
|
|
17839
|
+
return false;
|
|
17817
17840
|
if (this._isPure !== undefined)
|
|
17818
17841
|
return this._isPure;
|
|
17819
17842
|
let result = undefined;
|
|
17820
17843
|
if (this.functionDefinition?.pure !== undefined)
|
|
17821
17844
|
result = this.functionDefinition.pure;
|
|
17822
|
-
|
|
17823
|
-
|
|
17845
|
+
// The function might be pure. Let's check that all its arguments are pure.
|
|
17846
|
+
if (result !== false)
|
|
17824
17847
|
result = this._ops.every((x) => x.isPure);
|
|
17825
|
-
}
|
|
17826
17848
|
this._isPure = result;
|
|
17827
17849
|
return result;
|
|
17828
17850
|
}
|
|
17829
|
-
get
|
|
17830
|
-
|
|
17851
|
+
get json() {
|
|
17852
|
+
// If this expression is canonical, apply some transformations to the
|
|
17853
|
+
// JSON serialization to "reverse" some of the effects of canonicalization.
|
|
17854
|
+
if (this._canonical === this)
|
|
17855
|
+
return serializeJsonCanonicalFunction(this.engine, this._head, this._ops, { latex: this._latex, wikidata: this._wikidata });
|
|
17856
|
+
return serializeJsonFunction(this.engine, this._head, this._ops, {
|
|
17857
|
+
latex: this._latex,
|
|
17858
|
+
wikidata: this._wikidata,
|
|
17859
|
+
});
|
|
17831
17860
|
}
|
|
17832
|
-
get
|
|
17833
|
-
|
|
17834
|
-
if (this._head.isValid === false)
|
|
17835
|
-
return false;
|
|
17836
|
-
}
|
|
17837
|
-
else {
|
|
17838
|
-
if (this._head === 'Error')
|
|
17839
|
-
return false;
|
|
17840
|
-
// Need to check function definition before arguments: binding
|
|
17841
|
-
// as the side effect of normalizing arguments
|
|
17842
|
-
if (this.functionDefinition === undefined)
|
|
17843
|
-
return false;
|
|
17844
|
-
if (!this._ops.every((x) => x.isValid))
|
|
17845
|
-
return false;
|
|
17846
|
-
}
|
|
17847
|
-
return this._ops.every((x) => x.isValid);
|
|
17861
|
+
get head() {
|
|
17862
|
+
return this._head;
|
|
17848
17863
|
}
|
|
17849
17864
|
get ops() {
|
|
17850
17865
|
return this._ops;
|
|
@@ -17861,70 +17876,251 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
17861
17876
|
get op3() {
|
|
17862
17877
|
return this._ops[2] ?? this.engine.symbol('Nothing');
|
|
17863
17878
|
}
|
|
17864
|
-
get
|
|
17865
|
-
if (this._def !== null)
|
|
17866
|
-
return this._def;
|
|
17867
|
-
this.bind(this._scope);
|
|
17868
|
-
return this._def;
|
|
17869
|
-
}
|
|
17870
|
-
bind(scope) {
|
|
17871
|
-
this._def = undefined;
|
|
17872
|
-
const ce = this.engine;
|
|
17873
|
-
// Flatten the sequence, canonicalize
|
|
17874
|
-
this._ops = flattenSequence(this._ops.map((x) => x.canonical));
|
|
17875
|
-
// Is the head an expression?
|
|
17876
|
-
// For example, `['InverseFunction', 'Sin']`
|
|
17879
|
+
get isValid() {
|
|
17877
17880
|
if (typeof this._head !== 'string') {
|
|
17878
|
-
|
|
17879
|
-
|
|
17880
|
-
|
|
17881
|
-
this._codomain = this._head.domain.codomain ?? ce.domain('Void');
|
|
17882
|
-
return;
|
|
17883
|
-
}
|
|
17881
|
+
if (this._head.isValid === false)
|
|
17882
|
+
return false;
|
|
17883
|
+
return this._ops.every((x) => x.isValid);
|
|
17884
17884
|
}
|
|
17885
|
-
|
|
17886
|
-
|
|
17887
|
-
|
|
17888
|
-
|
|
17889
|
-
if (this.
|
|
17890
|
-
|
|
17891
|
-
|
|
17892
|
-
|
|
17893
|
-
|
|
17894
|
-
|
|
17895
|
-
|
|
17896
|
-
|
|
17897
|
-
|
|
17898
|
-
|
|
17899
|
-
|
|
17900
|
-
|
|
17901
|
-
|
|
17902
|
-
|
|
17903
|
-
|
|
17904
|
-
|
|
17905
|
-
|
|
17906
|
-
|
|
17907
|
-
|
|
17908
|
-
|
|
17909
|
-
|
|
17910
|
-
|
|
17885
|
+
if (this._head === 'Error')
|
|
17886
|
+
return false;
|
|
17887
|
+
// If this expression is not canonical, nothing else to check:
|
|
17888
|
+
// non-canonical expression are never bound
|
|
17889
|
+
if (this._canonical !== this)
|
|
17890
|
+
return true;
|
|
17891
|
+
// Need to check function definition before arguments: binding
|
|
17892
|
+
// as the side effect of normalizing arguments
|
|
17893
|
+
if (this.functionDefinition === undefined)
|
|
17894
|
+
return false;
|
|
17895
|
+
if (!this._ops.every((x) => x.isValid))
|
|
17896
|
+
return false;
|
|
17897
|
+
return true;
|
|
17898
|
+
}
|
|
17899
|
+
get canonical() {
|
|
17900
|
+
if (this._canonical)
|
|
17901
|
+
return this._canonical;
|
|
17902
|
+
if (this.isValid)
|
|
17903
|
+
this._canonical = makeCanonicalFunction(this.engine, this._head, this._ops);
|
|
17904
|
+
else
|
|
17905
|
+
this._canonical = this;
|
|
17906
|
+
return this._canonical;
|
|
17907
|
+
}
|
|
17908
|
+
*map(fn) {
|
|
17909
|
+
let i = 0;
|
|
17910
|
+
while (i < this._ops.length)
|
|
17911
|
+
yield fn(this._ops[i++]);
|
|
17912
|
+
}
|
|
17913
|
+
apply(fn, head) {
|
|
17914
|
+
const newHead = head ?? this.head;
|
|
17915
|
+
let opsChanged = false;
|
|
17916
|
+
const ops = [];
|
|
17917
|
+
for (const arg of this._ops) {
|
|
17918
|
+
const newArg = fn(arg);
|
|
17919
|
+
if (arg !== newArg)
|
|
17920
|
+
opsChanged = true;
|
|
17921
|
+
ops.push(this.engine.box(newArg));
|
|
17922
|
+
}
|
|
17923
|
+
if (!opsChanged && this.head === newHead)
|
|
17924
|
+
return this;
|
|
17925
|
+
return this.engine.fn(newHead, ops);
|
|
17926
|
+
}
|
|
17927
|
+
subs(sub) {
|
|
17928
|
+
return makeCanonicalFunction(this.engine, this._head, this._ops.map((x) => x.subs(sub)));
|
|
17929
|
+
}
|
|
17930
|
+
replace(rules, options) {
|
|
17931
|
+
return replace(this, rules, options);
|
|
17932
|
+
}
|
|
17933
|
+
has(x) {
|
|
17934
|
+
if (typeof this._head === 'string') {
|
|
17935
|
+
if (typeof x === 'string') {
|
|
17936
|
+
if (this._head === x)
|
|
17937
|
+
return true;
|
|
17911
17938
|
}
|
|
17939
|
+
else if (x.includes(this._head))
|
|
17940
|
+
return true;
|
|
17941
|
+
}
|
|
17942
|
+
for (const arg of this._ops)
|
|
17943
|
+
if (arg.has(x))
|
|
17944
|
+
return true;
|
|
17945
|
+
return false;
|
|
17946
|
+
}
|
|
17947
|
+
/** `isSame` is structural/symbolic equality */
|
|
17948
|
+
isSame(rhs) {
|
|
17949
|
+
if (this === rhs)
|
|
17950
|
+
return true;
|
|
17951
|
+
if (!(rhs instanceof BoxedFunction))
|
|
17952
|
+
return false;
|
|
17953
|
+
// Number of arguments must match
|
|
17954
|
+
if (this.nops !== rhs.nops)
|
|
17955
|
+
return false;
|
|
17956
|
+
// Head must match
|
|
17957
|
+
if (typeof this.head === 'string') {
|
|
17958
|
+
if (this.head !== rhs.head)
|
|
17959
|
+
return false;
|
|
17960
|
+
}
|
|
17961
|
+
else {
|
|
17962
|
+
if (typeof rhs.head === 'string')
|
|
17963
|
+
return false;
|
|
17964
|
+
else if (!rhs.head || !this.head.isSame(rhs.head))
|
|
17965
|
+
return false;
|
|
17966
|
+
}
|
|
17967
|
+
// Each argument must match
|
|
17968
|
+
const lhsTail = this._ops;
|
|
17969
|
+
const rhsTail = rhs._ops;
|
|
17970
|
+
for (let i = 0; i < lhsTail.length; i++)
|
|
17971
|
+
if (!lhsTail[i].isSame(rhsTail[i]))
|
|
17972
|
+
return false;
|
|
17973
|
+
return true;
|
|
17974
|
+
}
|
|
17975
|
+
match(rhs, options) {
|
|
17976
|
+
if (!(rhs instanceof BoxedFunction))
|
|
17977
|
+
return null;
|
|
17978
|
+
let result = {};
|
|
17979
|
+
// Head must match
|
|
17980
|
+
if (typeof this.head === 'string') {
|
|
17981
|
+
if (this.head !== rhs.head)
|
|
17982
|
+
return null;
|
|
17983
|
+
}
|
|
17984
|
+
else {
|
|
17985
|
+
if (typeof rhs.head === 'string')
|
|
17986
|
+
return null;
|
|
17912
17987
|
else {
|
|
17913
|
-
|
|
17988
|
+
if (!rhs.head)
|
|
17989
|
+
return null;
|
|
17990
|
+
const m = this.head.match(rhs.head, options);
|
|
17991
|
+
if (m === null)
|
|
17992
|
+
return null;
|
|
17993
|
+
result = { ...result, ...m };
|
|
17914
17994
|
}
|
|
17915
|
-
if (this._def.scoped)
|
|
17916
|
-
ce.popScope();
|
|
17917
17995
|
}
|
|
17918
|
-
|
|
17919
|
-
|
|
17996
|
+
// Each argument must match
|
|
17997
|
+
const lhsTail = this._ops;
|
|
17998
|
+
const rhsTail = rhs._ops;
|
|
17999
|
+
for (let i = 0; i < lhsTail.length; i++) {
|
|
18000
|
+
const m = lhsTail[i].match(rhsTail[i], options);
|
|
18001
|
+
if (m === null)
|
|
18002
|
+
return null;
|
|
18003
|
+
result = { ...result, ...m };
|
|
18004
|
+
}
|
|
18005
|
+
return result;
|
|
18006
|
+
}
|
|
18007
|
+
//
|
|
18008
|
+
// CANONICAL OPERATIONS
|
|
18009
|
+
//
|
|
18010
|
+
// These operations apply only to canonical expressions
|
|
18011
|
+
//
|
|
18012
|
+
unbind() {
|
|
18013
|
+
// Note: a non-canonical expression is never bound
|
|
18014
|
+
this._value = undefined;
|
|
18015
|
+
this._numericValue = undefined;
|
|
18016
|
+
// this._def = null;
|
|
18017
|
+
}
|
|
18018
|
+
get wikidata() {
|
|
18019
|
+
// Since the canonical and non-canonical version of the expression
|
|
18020
|
+
// may have different heads, not applicable to non-canonical expressions.
|
|
18021
|
+
if (!this.isCanonical)
|
|
18022
|
+
return undefined;
|
|
18023
|
+
return this._wikidata ?? this.functionDefinition?.wikidata ?? undefined;
|
|
18024
|
+
}
|
|
18025
|
+
get description() {
|
|
18026
|
+
// Since the canonical and non-canonical version of the expression
|
|
18027
|
+
// may have different heads, not applicable to non-canonical expressions.
|
|
18028
|
+
if (!this.isCanonical)
|
|
18029
|
+
return undefined;
|
|
18030
|
+
const def = this.functionDefinition;
|
|
18031
|
+
if (!def)
|
|
18032
|
+
return [];
|
|
18033
|
+
if (!def.description)
|
|
18034
|
+
return undefined;
|
|
18035
|
+
if (typeof def.description === 'string')
|
|
18036
|
+
return [def.description];
|
|
18037
|
+
return def.description;
|
|
18038
|
+
}
|
|
18039
|
+
get url() {
|
|
18040
|
+
// Since the canonical and non-canonical version of the expression
|
|
18041
|
+
// may have different heads, not applicable to non-canonical expressions.
|
|
18042
|
+
if (!this.isCanonical)
|
|
18043
|
+
return '';
|
|
18044
|
+
return this.functionDefinition?.url ?? undefined;
|
|
18045
|
+
}
|
|
18046
|
+
get complexity() {
|
|
18047
|
+
// Since the canonical and non-canonical version of the expression
|
|
18048
|
+
// may have different heads, not applicable to non-canonical expressions.
|
|
18049
|
+
if (!this.isCanonical)
|
|
18050
|
+
return undefined;
|
|
18051
|
+
return this.functionDefinition?.complexity ?? DEFAULT_COMPLEXITY;
|
|
18052
|
+
}
|
|
18053
|
+
get functionDefinition() {
|
|
18054
|
+
if (!this.isCanonical)
|
|
18055
|
+
return undefined;
|
|
18056
|
+
if (this._def !== null)
|
|
18057
|
+
return this._def;
|
|
18058
|
+
return undefined;
|
|
18059
|
+
}
|
|
18060
|
+
bind(_scope) {
|
|
18061
|
+
debugger;
|
|
18062
|
+
}
|
|
18063
|
+
//
|
|
18064
|
+
// AUTO-CANONICAL OPERATIONS
|
|
18065
|
+
//
|
|
18066
|
+
// The operations are automatically done on the canonical form of the
|
|
18067
|
+
// expression
|
|
18068
|
+
//
|
|
18069
|
+
get value() {
|
|
18070
|
+
if (!this.isCanonical)
|
|
18071
|
+
return this.canonical.value ?? this.canonical;
|
|
18072
|
+
if (!this.isPure)
|
|
18073
|
+
return undefined;
|
|
18074
|
+
// Use cached value if the function is pure
|
|
18075
|
+
if (this._value)
|
|
18076
|
+
return this._value;
|
|
18077
|
+
this._value = this.evaluate();
|
|
18078
|
+
return this._value;
|
|
18079
|
+
}
|
|
18080
|
+
get numericValue() {
|
|
18081
|
+
if (this._numericValue)
|
|
18082
|
+
return this._numericValue;
|
|
18083
|
+
if (!this.isCanonical)
|
|
18084
|
+
return this.canonical.numericValue;
|
|
18085
|
+
if (!this.isPure)
|
|
18086
|
+
this._numericValue = undefined;
|
|
18087
|
+
else {
|
|
18088
|
+
const v = this.N();
|
|
18089
|
+
this._numericValue = v === this ? undefined : v;
|
|
18090
|
+
}
|
|
18091
|
+
return this._numericValue;
|
|
17920
18092
|
}
|
|
17921
18093
|
get domain() {
|
|
17922
|
-
if (this.
|
|
17923
|
-
this.
|
|
18094
|
+
if (!this.isCanonical)
|
|
18095
|
+
return this.canonical.domain;
|
|
17924
18096
|
console.assert(this._codomain);
|
|
17925
18097
|
return this._codomain;
|
|
17926
18098
|
}
|
|
18099
|
+
/** `isEqual` is mathematical equality */
|
|
18100
|
+
isEqual(rhs) {
|
|
18101
|
+
if (!this.isCanonical)
|
|
18102
|
+
return this.canonical.isEqual(rhs);
|
|
18103
|
+
rhs = rhs.canonical.numericValue ?? rhs.canonical;
|
|
18104
|
+
if (rhs.isNumber && this.isNumber) {
|
|
18105
|
+
const ce = this.engine;
|
|
18106
|
+
// In general, it is impossible to always prove equality
|
|
18107
|
+
// (Richardson's theorem) but this works often...
|
|
18108
|
+
const diff = ce.add([this, ce.negate(rhs)]).N();
|
|
18109
|
+
if (diff.isZero)
|
|
18110
|
+
return true;
|
|
18111
|
+
const v = diff.asFloat;
|
|
18112
|
+
if (v !== null && ce.chop(v) === 0)
|
|
18113
|
+
return true;
|
|
18114
|
+
return (this.value ?? this.evaluate()).isSame(rhs);
|
|
18115
|
+
}
|
|
18116
|
+
if (this.domain.isRelationalOperator && rhs.domain.isRelationalOperator) {
|
|
18117
|
+
return this.isSame(rhs);
|
|
18118
|
+
}
|
|
18119
|
+
return this.isSame(rhs);
|
|
18120
|
+
}
|
|
17927
18121
|
isLess(rhs) {
|
|
18122
|
+
if (!this.isCanonical)
|
|
18123
|
+
return this.canonical.isLess(rhs);
|
|
17928
18124
|
if (rhs.isZero) {
|
|
17929
18125
|
const s = this.sgn;
|
|
17930
18126
|
if (s === null)
|
|
@@ -17933,9 +18129,15 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
17933
18129
|
return s < 0;
|
|
17934
18130
|
}
|
|
17935
18131
|
// @todo: use this.functionDefinition.range
|
|
17936
|
-
|
|
18132
|
+
const ce = this.engine;
|
|
18133
|
+
rhs = rhs.canonical.numericValue ?? rhs.canonical;
|
|
18134
|
+
const diff = ce.add([this, ce.negate(rhs)]).N();
|
|
18135
|
+
const v = diff.asFloat;
|
|
18136
|
+
return v === null ? undefined : v < 0;
|
|
17937
18137
|
}
|
|
17938
18138
|
isLessEqual(rhs) {
|
|
18139
|
+
if (!this.isCanonical)
|
|
18140
|
+
return this.canonical.isLess(rhs);
|
|
17939
18141
|
if (rhs.isZero) {
|
|
17940
18142
|
const s = this.sgn;
|
|
17941
18143
|
if (s === null)
|
|
@@ -17943,10 +18145,16 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
17943
18145
|
if (s !== undefined)
|
|
17944
18146
|
return s <= 0;
|
|
17945
18147
|
}
|
|
17946
|
-
return undefined;
|
|
17947
18148
|
// @todo: use this.functionDefinition.range
|
|
18149
|
+
const ce = this.engine;
|
|
18150
|
+
rhs = rhs.canonical.numericValue ?? rhs.canonical;
|
|
18151
|
+
const diff = ce.add([this, ce.negate(rhs)]).N();
|
|
18152
|
+
const v = diff.asFloat;
|
|
18153
|
+
return v === null ? undefined : v <= 0 || ce.chop(v) === 0;
|
|
17948
18154
|
}
|
|
17949
18155
|
isGreater(rhs) {
|
|
18156
|
+
if (!this.isCanonical)
|
|
18157
|
+
return this.canonical.isLess(rhs);
|
|
17950
18158
|
if (rhs.isZero) {
|
|
17951
18159
|
const s = this.sgn;
|
|
17952
18160
|
if (s === null)
|
|
@@ -17954,10 +18162,16 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
17954
18162
|
if (s !== undefined)
|
|
17955
18163
|
return s > 0;
|
|
17956
18164
|
}
|
|
17957
|
-
return undefined;
|
|
17958
18165
|
// @todo: use this.functionDefinition.range
|
|
18166
|
+
const ce = this.engine;
|
|
18167
|
+
rhs = rhs.canonical.numericValue ?? rhs.canonical;
|
|
18168
|
+
const diff = ce.add([this, ce.negate(rhs)]).N();
|
|
18169
|
+
const v = diff.asFloat;
|
|
18170
|
+
return v === null ? undefined : v > 0;
|
|
17959
18171
|
}
|
|
17960
18172
|
isGreaterEqual(rhs) {
|
|
18173
|
+
if (!this.isCanonical)
|
|
18174
|
+
return this.canonical.isLess(rhs);
|
|
17961
18175
|
if (rhs.isZero) {
|
|
17962
18176
|
const s = this.sgn;
|
|
17963
18177
|
if (s === null)
|
|
@@ -17965,8 +18179,12 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
17965
18179
|
if (s !== undefined)
|
|
17966
18180
|
return s >= 0;
|
|
17967
18181
|
}
|
|
17968
|
-
return undefined;
|
|
17969
18182
|
// @todo: use this.functionDefinition.range
|
|
18183
|
+
const ce = this.engine;
|
|
18184
|
+
rhs = rhs.canonical.numericValue ?? rhs.canonical;
|
|
18185
|
+
const diff = ce.add([this, ce.negate(rhs)]).N();
|
|
18186
|
+
const v = diff.asFloat;
|
|
18187
|
+
return v === null ? undefined : v >= 0 || ce.chop(v) === 0;
|
|
17970
18188
|
}
|
|
17971
18189
|
get isZero() {
|
|
17972
18190
|
const s = this.sgn;
|
|
@@ -17987,12 +18205,10 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
17987
18205
|
// @todo: use this.functionDefinition.range
|
|
17988
18206
|
}
|
|
17989
18207
|
get isOne() {
|
|
17990
|
-
return
|
|
17991
|
-
// @todo: use this.functionDefinition.range
|
|
18208
|
+
return this.isEqual(this.engine.number(1));
|
|
17992
18209
|
}
|
|
17993
18210
|
get isNegativeOne() {
|
|
17994
|
-
return
|
|
17995
|
-
// @todo: use this.functionDefinition.range
|
|
18211
|
+
return this.isEqual(this.engine.number(-1));
|
|
17996
18212
|
}
|
|
17997
18213
|
// x > 0
|
|
17998
18214
|
get isPositive() {
|
|
@@ -18000,9 +18216,8 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
18000
18216
|
if (s === null)
|
|
18001
18217
|
return false;
|
|
18002
18218
|
if (typeof s === 'number')
|
|
18003
|
-
return s
|
|
18219
|
+
return s > 0;
|
|
18004
18220
|
return undefined;
|
|
18005
|
-
// @todo: use this.functionDefinition.range
|
|
18006
18221
|
}
|
|
18007
18222
|
// x <= 0
|
|
18008
18223
|
get isNonPositive() {
|
|
@@ -18012,7 +18227,6 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
18012
18227
|
if (typeof s === 'number')
|
|
18013
18228
|
return s <= 0;
|
|
18014
18229
|
return undefined;
|
|
18015
|
-
// @todo: use this.functionDefinition.range
|
|
18016
18230
|
}
|
|
18017
18231
|
// x < 0
|
|
18018
18232
|
get isNegative() {
|
|
@@ -18022,7 +18236,6 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
18022
18236
|
if (typeof s === 'number')
|
|
18023
18237
|
return s < 0;
|
|
18024
18238
|
return undefined;
|
|
18025
|
-
// @todo: use this.functionDefinition.range
|
|
18026
18239
|
}
|
|
18027
18240
|
// x >= 0
|
|
18028
18241
|
get isNonNegative() {
|
|
@@ -18032,7 +18245,6 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
18032
18245
|
if (typeof s === 'number')
|
|
18033
18246
|
return s >= 0;
|
|
18034
18247
|
return undefined;
|
|
18035
|
-
// @todo: use this.functionDefinition.range
|
|
18036
18248
|
}
|
|
18037
18249
|
get isNumber() {
|
|
18038
18250
|
return this.domain.isCompatible('Number');
|
|
@@ -18046,124 +18258,21 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
18046
18258
|
get isAlgebraic() {
|
|
18047
18259
|
return this.domain.isCompatible('AlgebraicNumber');
|
|
18048
18260
|
}
|
|
18049
|
-
get isReal() {
|
|
18050
|
-
return this.domain.isCompatible('RealNumber');
|
|
18051
|
-
}
|
|
18052
|
-
get isExtendedReal() {
|
|
18053
|
-
return this.domain.isCompatible('ExtendedRealNumber');
|
|
18054
|
-
}
|
|
18055
|
-
get isComplex() {
|
|
18056
|
-
return this.domain.isCompatible('ComplexNumber');
|
|
18057
|
-
}
|
|
18058
|
-
get isImaginary() {
|
|
18059
|
-
return this.domain.isCompatible('ImaginaryNumber');
|
|
18060
|
-
}
|
|
18061
|
-
get json() {
|
|
18062
|
-
// If this expression is canonical, apply some transformations to the
|
|
18063
|
-
// JSON serialization to "reverse" some of the effects of canonicalization.
|
|
18064
|
-
if (this._isCanonical)
|
|
18065
|
-
return serializeJsonCanonicalFunction(this.engine, this._head, this._ops, { latex: this._latex, wikidata: this._wikidata });
|
|
18066
|
-
return serializeJsonFunction(this.engine, this._head, this._ops, {
|
|
18067
|
-
latex: this._latex,
|
|
18068
|
-
wikidata: this._wikidata,
|
|
18069
|
-
});
|
|
18070
|
-
}
|
|
18071
|
-
has(x) {
|
|
18072
|
-
if (typeof this._head === 'string') {
|
|
18073
|
-
if (typeof x === 'string') {
|
|
18074
|
-
if (this._head === x)
|
|
18075
|
-
return true;
|
|
18076
|
-
}
|
|
18077
|
-
else if (x.includes(this._head))
|
|
18078
|
-
return true;
|
|
18079
|
-
}
|
|
18080
|
-
for (const arg of this._ops)
|
|
18081
|
-
if (arg.has(x))
|
|
18082
|
-
return true;
|
|
18083
|
-
return false;
|
|
18084
|
-
}
|
|
18085
|
-
/** `isSame` is structural/symbolic equality */
|
|
18086
|
-
isSame(rhs) {
|
|
18087
|
-
if (this === rhs)
|
|
18088
|
-
return true;
|
|
18089
|
-
if (!(rhs instanceof BoxedFunction))
|
|
18090
|
-
return false;
|
|
18091
|
-
// Number of arguments must match
|
|
18092
|
-
if (this.nops !== rhs.nops)
|
|
18093
|
-
return false;
|
|
18094
|
-
// Head must match
|
|
18095
|
-
if (typeof this.head === 'string') {
|
|
18096
|
-
if (this.head !== rhs.head)
|
|
18097
|
-
return false;
|
|
18098
|
-
}
|
|
18099
|
-
else {
|
|
18100
|
-
if (typeof rhs.head === 'string')
|
|
18101
|
-
return false;
|
|
18102
|
-
else if (!rhs.head || !this.head.isSame(rhs.head))
|
|
18103
|
-
return false;
|
|
18104
|
-
}
|
|
18105
|
-
// Each argument must match
|
|
18106
|
-
const lhsTail = this._ops;
|
|
18107
|
-
const rhsTail = rhs._ops;
|
|
18108
|
-
for (let i = 0; i < lhsTail.length; i++)
|
|
18109
|
-
if (!lhsTail[i].isSame(rhsTail[i]))
|
|
18110
|
-
return false;
|
|
18111
|
-
return true;
|
|
18261
|
+
get isReal() {
|
|
18262
|
+
return this.domain.isCompatible('RealNumber');
|
|
18112
18263
|
}
|
|
18113
|
-
|
|
18114
|
-
|
|
18115
|
-
return null;
|
|
18116
|
-
let result = {};
|
|
18117
|
-
// Head must match
|
|
18118
|
-
if (typeof this.head === 'string') {
|
|
18119
|
-
if (this.head !== rhs.head)
|
|
18120
|
-
return null;
|
|
18121
|
-
}
|
|
18122
|
-
else {
|
|
18123
|
-
if (typeof rhs.head === 'string')
|
|
18124
|
-
return null;
|
|
18125
|
-
else {
|
|
18126
|
-
if (!rhs.head)
|
|
18127
|
-
return null;
|
|
18128
|
-
const m = this.head.match(rhs.head, options);
|
|
18129
|
-
if (m === null)
|
|
18130
|
-
return null;
|
|
18131
|
-
result = { ...result, ...m };
|
|
18132
|
-
}
|
|
18133
|
-
}
|
|
18134
|
-
// Each argument must match
|
|
18135
|
-
const lhsTail = this._ops;
|
|
18136
|
-
const rhsTail = rhs._ops;
|
|
18137
|
-
for (let i = 0; i < lhsTail.length; i++) {
|
|
18138
|
-
const m = lhsTail[i].match(rhsTail[i], options);
|
|
18139
|
-
if (m === null)
|
|
18140
|
-
return null;
|
|
18141
|
-
result = { ...result, ...m };
|
|
18142
|
-
}
|
|
18143
|
-
return result;
|
|
18264
|
+
get isExtendedReal() {
|
|
18265
|
+
return this.domain.isCompatible('ExtendedRealNumber');
|
|
18144
18266
|
}
|
|
18145
|
-
|
|
18146
|
-
|
|
18147
|
-
|
|
18148
|
-
|
|
18149
|
-
|
|
18150
|
-
if (rhs.isNumber && this.isNumber) {
|
|
18151
|
-
const ce = this.engine;
|
|
18152
|
-
// In general, it is impossible to always prove equality
|
|
18153
|
-
// (Richardson's theorem) but this works often...
|
|
18154
|
-
const diff = ce.add([this, ce.negate(rhs)]).N();
|
|
18155
|
-
if (diff.isZero)
|
|
18156
|
-
return true;
|
|
18157
|
-
if (diff.asFloat !== null && ce.chop(diff.asFloat) === 0)
|
|
18158
|
-
return true;
|
|
18159
|
-
return this.evaluate().isSame(rhs.evaluate());
|
|
18160
|
-
}
|
|
18161
|
-
if (this.domain.isRelationalOperator && rhs.domain.isRelationalOperator) {
|
|
18162
|
-
return this.evaluate().isSame(rhs.evaluate());
|
|
18163
|
-
}
|
|
18164
|
-
return this.isSame(rhs);
|
|
18267
|
+
get isComplex() {
|
|
18268
|
+
return this.domain.isCompatible('ComplexNumber');
|
|
18269
|
+
}
|
|
18270
|
+
get isImaginary() {
|
|
18271
|
+
return this.domain.isCompatible('ImaginaryNumber');
|
|
18165
18272
|
}
|
|
18166
18273
|
get sgn() {
|
|
18274
|
+
if (!this.isCanonical)
|
|
18275
|
+
return this.canonical.sgn;
|
|
18167
18276
|
// @todo: if there is a this.functionDefinition.range, use it
|
|
18168
18277
|
// @todo if inconclusive, and there is a this.def._sgn, call it
|
|
18169
18278
|
// @todo: add sgn() function to FunctionDefinition
|
|
@@ -18241,81 +18350,14 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
18241
18350
|
return +1;
|
|
18242
18351
|
}
|
|
18243
18352
|
// @todo: trig functions, geometric functions
|
|
18244
|
-
|
|
18245
|
-
|
|
18246
|
-
|
|
18247
|
-
|
|
18248
|
-
|
|
18249
|
-
|
|
18250
|
-
|
|
18251
|
-
|
|
18252
|
-
return this._isCanonical;
|
|
18253
|
-
}
|
|
18254
|
-
set isCanonical(val) {
|
|
18255
|
-
this._isCanonical = val;
|
|
18256
|
-
}
|
|
18257
|
-
apply(fn, head) {
|
|
18258
|
-
const newHead = head ?? this.head;
|
|
18259
|
-
let opsChanged = false;
|
|
18260
|
-
const ops = [];
|
|
18261
|
-
for (const arg of this._ops) {
|
|
18262
|
-
const newArg = fn(arg);
|
|
18263
|
-
if (arg !== newArg)
|
|
18264
|
-
opsChanged = true;
|
|
18265
|
-
ops.push(this.engine.box(newArg));
|
|
18266
|
-
}
|
|
18267
|
-
if (!opsChanged && this.head === newHead)
|
|
18268
|
-
return this;
|
|
18269
|
-
return this.engine.fn(newHead, ops);
|
|
18270
|
-
}
|
|
18271
|
-
get canonical() {
|
|
18272
|
-
if (this.isCanonical || !this.isValid)
|
|
18273
|
-
return this;
|
|
18274
|
-
// 1/ If no definition (i.e. function `g`...), apply canonical to each op
|
|
18275
|
-
const def = this.functionDefinition;
|
|
18276
|
-
if (!def) {
|
|
18277
|
-
const tail = this._ops.map((x) => x.canonical);
|
|
18278
|
-
if (tail.length === this._ops.length &&
|
|
18279
|
-
tail.every((x, i) => this._ops[i] === x)) {
|
|
18280
|
-
// We were already canonical! No need to create a new expression
|
|
18281
|
-
this._isCanonical = true;
|
|
18282
|
-
return this;
|
|
18283
|
-
}
|
|
18284
|
-
return this.engine._fn(this._head, tail);
|
|
18285
|
-
}
|
|
18286
|
-
//
|
|
18287
|
-
// 2/ Get the canonical form of the arguments, accounting for `Hold`,
|
|
18288
|
-
// `ReleaseHold`, `Sequence` and `Symbol`
|
|
18289
|
-
//
|
|
18290
|
-
let tail = canonicalHoldMap(def.name, this._ops, def.hold, def.associative);
|
|
18291
|
-
//
|
|
18292
|
-
// 3/ Apply `canonical` handler
|
|
18293
|
-
//
|
|
18294
|
-
const sig = def.signature;
|
|
18295
|
-
if (sig?.canonical)
|
|
18296
|
-
return sig.canonical(this.engine, tail);
|
|
18297
|
-
//
|
|
18298
|
-
// 4/ Apply `idempotent` and `involution`
|
|
18299
|
-
//
|
|
18300
|
-
if (tail.length === 1 && tail[0].head === this._head) {
|
|
18301
|
-
// f(f(x)) -> x
|
|
18302
|
-
if (def.involution)
|
|
18303
|
-
return tail[0].op1;
|
|
18304
|
-
// f(f(x)) -> f(x)
|
|
18305
|
-
if (def.idempotent)
|
|
18306
|
-
tail = tail[0].ops;
|
|
18307
|
-
}
|
|
18308
|
-
//
|
|
18309
|
-
// 5/ Sort the arguments
|
|
18310
|
-
//
|
|
18311
|
-
if (tail.length > 1 && def.commutative === true)
|
|
18312
|
-
tail = tail.sort(order);
|
|
18313
|
-
if (tail.length === this._ops.length &&
|
|
18314
|
-
tail.every((x, i) => this._ops[i] === x)) {
|
|
18315
|
-
this._isCanonical = true;
|
|
18316
|
-
return this;
|
|
18317
|
-
}
|
|
18318
|
-
return this.engine._fn(this._head, tail);
|
|
18353
|
+
const v = (this.numericValue ?? this.N()).asSmallInteger;
|
|
18354
|
+
if (v === null)
|
|
18355
|
+
return undefined;
|
|
18356
|
+
if (v === 0)
|
|
18357
|
+
return 0;
|
|
18358
|
+
if (v < 0)
|
|
18359
|
+
return -1;
|
|
18360
|
+
return +1;
|
|
18319
18361
|
}
|
|
18320
18362
|
simplify(options) {
|
|
18321
18363
|
//
|
|
@@ -18483,14 +18525,75 @@ class BoxedFunction extends AbstractBoxedExpression {
|
|
|
18483
18525
|
// @todo
|
|
18484
18526
|
return null;
|
|
18485
18527
|
}
|
|
18486
|
-
|
|
18487
|
-
|
|
18528
|
+
}
|
|
18529
|
+
function makeCanonicalFunction(ce, head, ops, options) {
|
|
18530
|
+
options ?? (options = {});
|
|
18531
|
+
options.canonical = true;
|
|
18532
|
+
//
|
|
18533
|
+
// Canonicalize the arguments and flatten any sequence
|
|
18534
|
+
//
|
|
18535
|
+
ops = ops.map((x) => x.canonical);
|
|
18536
|
+
ops = flattenSequence(ops);
|
|
18537
|
+
//
|
|
18538
|
+
// Is the head an expression? For example, `['InverseFunction', 'Sin']`
|
|
18539
|
+
//
|
|
18540
|
+
if (typeof head !== 'string')
|
|
18541
|
+
head = head.evaluate().symbol ?? head;
|
|
18542
|
+
if (typeof head !== 'string')
|
|
18543
|
+
return new BoxedFunction(ce, head, ops, options);
|
|
18544
|
+
if (ce.context === null)
|
|
18545
|
+
return new BoxedFunction(ce, head, ops, options);
|
|
18546
|
+
const def = ce.lookupFunction(head, ce.context);
|
|
18547
|
+
if (!def)
|
|
18548
|
+
return new BoxedFunction(ce, head, ops, options);
|
|
18549
|
+
// f(a, f(b, c), d) -> f(a, b, c, d)
|
|
18550
|
+
if (def.associative)
|
|
18551
|
+
ops = flattenOps(ops, head) ?? ops;
|
|
18552
|
+
// Scoped function automatically create a new scope
|
|
18553
|
+
// @todo: this needs to be done when evaluating, not here...
|
|
18554
|
+
if (def.scoped)
|
|
18555
|
+
ce.pushScope();
|
|
18556
|
+
// Apply Sequence, Symbol
|
|
18557
|
+
// this._ops = normalizeList(this._ops, this._def.hold);
|
|
18558
|
+
const sig = def.signature;
|
|
18559
|
+
ops = validateSignature(ce, sig, ops) ?? ops;
|
|
18560
|
+
if (!ops.every((x) => x.isValid)) {
|
|
18561
|
+
if (def.scoped)
|
|
18562
|
+
ce.popScope();
|
|
18563
|
+
return new BoxedFunction(ce, head, ops, { ...options, def });
|
|
18488
18564
|
}
|
|
18489
|
-
|
|
18490
|
-
|
|
18491
|
-
|
|
18492
|
-
|
|
18565
|
+
//
|
|
18566
|
+
// 3/ Apply `canonical` handler
|
|
18567
|
+
//
|
|
18568
|
+
if (sig.canonical) {
|
|
18569
|
+
const fn = sig.canonical(ce, ops);
|
|
18570
|
+
if (fn.isValid && !fn.isCanonical)
|
|
18571
|
+
debugger;
|
|
18572
|
+
console.assert(!fn.isValid || fn.isCanonical);
|
|
18573
|
+
return fn;
|
|
18574
|
+
}
|
|
18575
|
+
//
|
|
18576
|
+
// 4/ No handler, apply idempotent and involution
|
|
18577
|
+
//
|
|
18578
|
+
//
|
|
18579
|
+
// 4/ Apply `idempotent` and `involution`
|
|
18580
|
+
//
|
|
18581
|
+
if (ops.length === 1 && ops[0].head === head) {
|
|
18582
|
+
// f(f(x)) -> x
|
|
18583
|
+
if (def.involution)
|
|
18584
|
+
return ops[0].op1;
|
|
18585
|
+
// f(f(x)) -> f(x)
|
|
18586
|
+
if (def.idempotent)
|
|
18587
|
+
ops = ops[0].ops;
|
|
18493
18588
|
}
|
|
18589
|
+
//
|
|
18590
|
+
// 5/ Sort the arguments
|
|
18591
|
+
//
|
|
18592
|
+
if (ops.length > 1 && def.commutative === true)
|
|
18593
|
+
ops = ops.sort(order);
|
|
18594
|
+
if (def.scoped)
|
|
18595
|
+
ce.popScope();
|
|
18596
|
+
return new BoxedFunction(ce, head, ops, { ...options, def });
|
|
18494
18597
|
}
|
|
18495
18598
|
function lambda(ce, fn, args) {
|
|
18496
18599
|
// 'fn' is a lambda expression.
|
|
@@ -18503,9 +18606,7 @@ function lambda(ce, fn, args) {
|
|
|
18503
18606
|
subs[`_${n++}`] = op;
|
|
18504
18607
|
subs['_'] = subs['_1'];
|
|
18505
18608
|
// Substitute the arguments in the lambda expression
|
|
18506
|
-
|
|
18507
|
-
result.bind(ce.context);
|
|
18508
|
-
return result;
|
|
18609
|
+
return fn.subs(subs);
|
|
18509
18610
|
}
|
|
18510
18611
|
// export function ungroup(expr: BoxedExpression): BoxedExpression {
|
|
18511
18612
|
// if (!expr.ops) return expr;
|
|
@@ -18548,20 +18649,9 @@ function holdMap(head, xs, skip, associative, f) {
|
|
|
18548
18649
|
else
|
|
18549
18650
|
result.push(xs[i]);
|
|
18550
18651
|
if (y) {
|
|
18551
|
-
|
|
18552
|
-
|
|
18553
|
-
|
|
18554
|
-
}
|
|
18555
|
-
else if (y.domain.literal === 'Symbol') {
|
|
18556
|
-
const x = f(y.evaluate());
|
|
18557
|
-
if (x !== null)
|
|
18558
|
-
result.push(x);
|
|
18559
|
-
}
|
|
18560
|
-
else {
|
|
18561
|
-
const x = f(y);
|
|
18562
|
-
if (x !== null)
|
|
18563
|
-
result.push(x);
|
|
18564
|
-
}
|
|
18652
|
+
const x = f(y);
|
|
18653
|
+
if (x !== null)
|
|
18654
|
+
result.push(x);
|
|
18565
18655
|
}
|
|
18566
18656
|
}
|
|
18567
18657
|
}
|
|
@@ -18581,37 +18671,6 @@ function flattenSequence(xs) {
|
|
|
18581
18671
|
}
|
|
18582
18672
|
return ys;
|
|
18583
18673
|
}
|
|
18584
|
-
// Like `HoldMap` but preserves `Hold` and `ReleaseHold`
|
|
18585
|
-
function canonicalHoldMap(head, xs, skip, associative) {
|
|
18586
|
-
if (xs.length === 0)
|
|
18587
|
-
return [];
|
|
18588
|
-
// f(a, f(b, c), d) -> f(a, b, c, d)
|
|
18589
|
-
if (associative)
|
|
18590
|
-
xs = flattenOps(xs, head) ?? xs;
|
|
18591
|
-
//
|
|
18592
|
-
// Apply the hold as necessary
|
|
18593
|
-
//
|
|
18594
|
-
const result = [];
|
|
18595
|
-
for (let i = 0; i < xs.length; i++) {
|
|
18596
|
-
const x = xs[i];
|
|
18597
|
-
if (x.head === 'Hold' ||
|
|
18598
|
-
x.head === 'ReleaseHold' ||
|
|
18599
|
-
!applicable(skip, xs.length - 1, i)) {
|
|
18600
|
-
result.push(x);
|
|
18601
|
-
}
|
|
18602
|
-
else if (x.head === 'Sequence') {
|
|
18603
|
-
if (x.ops)
|
|
18604
|
-
result.push(...x.ops.map((x) => x.canonical));
|
|
18605
|
-
}
|
|
18606
|
-
else if (x.head === 'Symbol' || x.domain.literal === 'Symbol')
|
|
18607
|
-
result.push(x.evaluate());
|
|
18608
|
-
else
|
|
18609
|
-
result.push(x.canonical);
|
|
18610
|
-
}
|
|
18611
|
-
if (associative)
|
|
18612
|
-
return flattenOps(result, head) ?? result;
|
|
18613
|
-
return result;
|
|
18614
|
-
}
|
|
18615
18674
|
function applicable(skip, count, index) {
|
|
18616
18675
|
if (skip === 'all')
|
|
18617
18676
|
return false;
|
|
@@ -18627,24 +18686,6 @@ function applicable(skip, count, index) {
|
|
|
18627
18686
|
return index === count;
|
|
18628
18687
|
return false;
|
|
18629
18688
|
}
|
|
18630
|
-
function normalizeList(xs, skip) {
|
|
18631
|
-
// Fold 'Sequence'
|
|
18632
|
-
const result = [];
|
|
18633
|
-
for (let i = 0; i < xs.length; i++) {
|
|
18634
|
-
if (applicable(skip, xs.length - 1, i)) {
|
|
18635
|
-
const x = xs[i];
|
|
18636
|
-
if (x.head === 'Sequence')
|
|
18637
|
-
result.push(...(x.ops ?? []));
|
|
18638
|
-
else if (x.head === 'Symbol')
|
|
18639
|
-
result.push(x.evaluate());
|
|
18640
|
-
else
|
|
18641
|
-
result.push(x);
|
|
18642
|
-
}
|
|
18643
|
-
else
|
|
18644
|
-
result.push(xs[i]);
|
|
18645
|
-
}
|
|
18646
|
-
return result;
|
|
18647
|
-
}
|
|
18648
18689
|
/** Return `null` if the `ops` match the sig. Otherwise, return an array
|
|
18649
18690
|
* of expressions indicating the mismatched arguments.
|
|
18650
18691
|
*
|
|
@@ -18974,6 +19015,12 @@ class BoxedNumber extends AbstractBoxedExpression {
|
|
|
18974
19015
|
set isCanonical(val) {
|
|
18975
19016
|
this._isCanonical = val;
|
|
18976
19017
|
}
|
|
19018
|
+
get complexity() {
|
|
19019
|
+
return 1;
|
|
19020
|
+
}
|
|
19021
|
+
get value() {
|
|
19022
|
+
return this;
|
|
19023
|
+
}
|
|
18977
19024
|
get numericValue() {
|
|
18978
19025
|
if (!Array.isArray(this._value))
|
|
18979
19026
|
return this;
|
|
@@ -19007,8 +19054,7 @@ class BoxedNumber extends AbstractBoxedExpression {
|
|
|
19007
19054
|
return Number.POSITIVE_INFINITY;
|
|
19008
19055
|
return Number.NEGATIVE_INFINITY;
|
|
19009
19056
|
}
|
|
19010
|
-
|
|
19011
|
-
return this._value.toNumber();
|
|
19057
|
+
return this._value.toNumber();
|
|
19012
19058
|
}
|
|
19013
19059
|
if (Array.isArray(this._value))
|
|
19014
19060
|
return this._value[0] / this._value[1];
|
|
@@ -19644,7 +19690,7 @@ function box(ce, expr) {
|
|
|
19644
19690
|
if ('fn' in expr) {
|
|
19645
19691
|
if (typeof expr.fn[0] === 'string')
|
|
19646
19692
|
return boxFunction(ce, expr.fn[0], expr.fn.slice(1), metadata);
|
|
19647
|
-
return new BoxedFunction(ce, box(ce, expr.fn[0]), expr.fn.slice(1).map((x) => box(ce, x)), metadata);
|
|
19693
|
+
return new BoxedFunction(ce, box(ce, expr.fn[0]), expr.fn.slice(1).map((x) => box(ce, x)), { metadata });
|
|
19648
19694
|
}
|
|
19649
19695
|
if ('str' in expr)
|
|
19650
19696
|
return new BoxedString(ce, expr.str, metadata);
|
|
@@ -19672,7 +19718,7 @@ function boxNumber(ce, num, metadata) {
|
|
|
19672
19718
|
if (Array.isArray(num)) {
|
|
19673
19719
|
if (num.length !== 2)
|
|
19674
19720
|
throw new Error('Array argument to boxNumber() should be two integers');
|
|
19675
|
-
|
|
19721
|
+
let [n, d] = num;
|
|
19676
19722
|
if (typeof n !== 'number' || typeof d !== 'number')
|
|
19677
19723
|
throw new Error('Array argument to boxNumber() should be two integers');
|
|
19678
19724
|
if (!Number.isInteger(n) || !Number.isInteger(d))
|
|
@@ -19822,7 +19868,9 @@ function boxFunction(ce, head, ops, metadata) {
|
|
|
19822
19868
|
// Hold
|
|
19823
19869
|
//
|
|
19824
19870
|
if (head === 'Hold') {
|
|
19825
|
-
const result = new BoxedFunction(ce, 'Hold', [boxHold(ce, ops[0])],
|
|
19871
|
+
const result = new BoxedFunction(ce, 'Hold', [boxHold(ce, ops[0])], {
|
|
19872
|
+
metadata,
|
|
19873
|
+
});
|
|
19826
19874
|
// Hold is always canonical
|
|
19827
19875
|
result.isCanonical = true;
|
|
19828
19876
|
return result;
|
|
@@ -19859,7 +19907,9 @@ function boxFunction(ce, head, ops, metadata) {
|
|
|
19859
19907
|
];
|
|
19860
19908
|
if (n !== null && d !== null)
|
|
19861
19909
|
return ce.number([n, d], metadata);
|
|
19862
|
-
return new BoxedFunction(ce, 'Rational', [ops[0], ops[1]],
|
|
19910
|
+
return new BoxedFunction(ce, 'Rational', [ops[0], ops[1]], {
|
|
19911
|
+
metadata,
|
|
19912
|
+
});
|
|
19863
19913
|
}
|
|
19864
19914
|
}
|
|
19865
19915
|
else {
|
|
@@ -19869,7 +19919,9 @@ function boxFunction(ce, head, ops, metadata) {
|
|
|
19869
19919
|
if (n?.isInteger() && d?.isInteger()) {
|
|
19870
19920
|
if (isInMachineRange(n) && isInMachineRange(d))
|
|
19871
19921
|
return ce.number([n.toNumber(), d.toNumber()], metadata);
|
|
19872
|
-
return new BoxedFunction(ce, 'Rational', [ce.box(op1), ce.box(op2)],
|
|
19922
|
+
return new BoxedFunction(ce, 'Rational', [ce.box(op1), ce.box(op2)], {
|
|
19923
|
+
metadata,
|
|
19924
|
+
});
|
|
19873
19925
|
}
|
|
19874
19926
|
}
|
|
19875
19927
|
head = 'Divide';
|
|
@@ -19927,14 +19979,16 @@ function boxFunction(ce, head, ops, metadata) {
|
|
|
19927
19979
|
return ce.error('expected-argument', "'Single");
|
|
19928
19980
|
if (ops.length > 1)
|
|
19929
19981
|
return ce.error('unexpected-argument', "'Single");
|
|
19930
|
-
return new BoxedFunction(ce, 'Tuple', [ce.box(ops[0])], metadata);
|
|
19982
|
+
return new BoxedFunction(ce, 'Tuple', [ce.box(ops[0])], { metadata });
|
|
19931
19983
|
}
|
|
19932
19984
|
if (head === 'Pair') {
|
|
19933
19985
|
if (ops.length < 2)
|
|
19934
19986
|
return ce.error('expected-argument', "'Pair");
|
|
19935
19987
|
if (ops.length > 2)
|
|
19936
19988
|
return ce.error('unexpected-argument', "'Pair");
|
|
19937
|
-
return new BoxedFunction(ce, 'Tuple', [ce.box(ops[0]), ce.box(ops[1])],
|
|
19989
|
+
return new BoxedFunction(ce, 'Tuple', [ce.box(ops[0]), ce.box(ops[1])], {
|
|
19990
|
+
metadata,
|
|
19991
|
+
});
|
|
19938
19992
|
}
|
|
19939
19993
|
// KeyValuePair is not normalized to Tuple
|
|
19940
19994
|
if (head === 'KeyValuePair') {
|
|
@@ -19942,14 +19996,14 @@ function boxFunction(ce, head, ops, metadata) {
|
|
|
19942
19996
|
return ce.error('expected-argument', "'KeyValuePair");
|
|
19943
19997
|
if (ops.length > 2)
|
|
19944
19998
|
return ce.error('unexpected-argument', "'KeyValuePair");
|
|
19945
|
-
return new BoxedFunction(ce, 'KeyValuePair', [ce.box(ops[0]), ce.box(ops[1])], metadata);
|
|
19999
|
+
return new BoxedFunction(ce, 'KeyValuePair', [ce.box(ops[0]), ce.box(ops[1])], { metadata });
|
|
19946
20000
|
}
|
|
19947
20001
|
if (head === 'Triple') {
|
|
19948
20002
|
if (ops.length < 3)
|
|
19949
20003
|
return ce.error('expected-argument', "'Triple");
|
|
19950
20004
|
if (ops.length > 3)
|
|
19951
20005
|
return ce.error('unexpected-argument', "'Triple");
|
|
19952
|
-
return new BoxedFunction(ce, 'Tuple', ops.map((x) => ce.box(x)), metadata);
|
|
20006
|
+
return new BoxedFunction(ce, 'Tuple', ops.map((x) => ce.box(x)), { metadata });
|
|
19953
20007
|
}
|
|
19954
20008
|
//
|
|
19955
20009
|
// Dictionary
|
|
@@ -19978,7 +20032,7 @@ function boxFunction(ce, head, ops, metadata) {
|
|
|
19978
20032
|
}
|
|
19979
20033
|
return new BoxedDictionary(ce, dict, metadata);
|
|
19980
20034
|
}
|
|
19981
|
-
return new BoxedFunction(ce, head, ops.map((x) => box(ce, x)), metadata);
|
|
20035
|
+
return new BoxedFunction(ce, head, ops.map((x) => box(ce, x)), { metadata });
|
|
19982
20036
|
}
|
|
19983
20037
|
function asString(expr) {
|
|
19984
20038
|
if (typeof expr === 'string')
|
|
@@ -20789,10 +20843,14 @@ function square(ce, base) {
|
|
|
20789
20843
|
function processPower(ce, base, exponent, mode) {
|
|
20790
20844
|
if (mode !== 'simplify' && base.isLiteral && exponent.isLiteral) {
|
|
20791
20845
|
if (mode === 'N' || !base.isInteger) {
|
|
20792
|
-
if (base.complexValue)
|
|
20846
|
+
if (base.complexValue) {
|
|
20793
20847
|
return ce.number(base.complexValue.pow(exponent.complexValue ?? exponent.asFloat ?? NaN));
|
|
20794
|
-
|
|
20795
|
-
|
|
20848
|
+
}
|
|
20849
|
+
if (exponent.complexValue) {
|
|
20850
|
+
const b = base.asFloat ?? base.decimalValue?.toNumber() ?? null;
|
|
20851
|
+
if (b !== null)
|
|
20852
|
+
return ce.number(ce.complex(b).pow(exponent.complexValue));
|
|
20853
|
+
}
|
|
20796
20854
|
if (base.decimalValue) {
|
|
20797
20855
|
return ce.number(base.decimalValue.pow(exponent.decimalValue ?? exponent.asFloat));
|
|
20798
20856
|
}
|
|
@@ -20929,15 +20987,25 @@ function evalMultiply(ce, ops, mode = 'evaluate') {
|
|
|
20929
20987
|
product.addTerm(arg);
|
|
20930
20988
|
}
|
|
20931
20989
|
}
|
|
20932
|
-
if (
|
|
20933
|
-
|
|
20990
|
+
if (complexProduct.im !== 0) {
|
|
20991
|
+
if (!complexAllowed(ce))
|
|
20992
|
+
return ce._NAN;
|
|
20993
|
+
// We have an imaginary number: fold Decimal into machine numbers
|
|
20994
|
+
machineProduct *= decimalProduct.toNumber();
|
|
20995
|
+
decimalProduct = ce._DECIMAL_ONE;
|
|
20996
|
+
numer *= decimalNumer.toNumber();
|
|
20997
|
+
denom *= decimalDenom.toNumber();
|
|
20998
|
+
decimalNumer = ce._DECIMAL_ONE;
|
|
20999
|
+
decimalDenom = ce._DECIMAL_ONE;
|
|
21000
|
+
}
|
|
20934
21001
|
if (decimalDenom.eq(ce._DECIMAL_ONE) && isInMachineRange(decimalNumer)) {
|
|
20935
21002
|
numer = denom * decimalNumer.toNumber();
|
|
20936
21003
|
decimalNumer = ce._DECIMAL_ONE;
|
|
20937
21004
|
}
|
|
20938
|
-
if (
|
|
20939
|
-
|
|
20940
|
-
|
|
21005
|
+
if (complexProduct.im === 0 &&
|
|
21006
|
+
(preferDecimal(ce) ||
|
|
21007
|
+
!decimalProduct.eq(ce._DECIMAL_ONE) ||
|
|
21008
|
+
!(decimalNumer.eq(ce._DECIMAL_ONE) && decimalDenom.eq(ce._DECIMAL_ONE)))) {
|
|
20941
21009
|
// Fold into decimal
|
|
20942
21010
|
let d = decimalProduct.mul(machineProduct);
|
|
20943
21011
|
if (mode === 'N') {
|
|
@@ -21179,7 +21247,7 @@ function canonicalDivide(ce, op1, op2) {
|
|
|
21179
21247
|
return canonicalNegate(op1);
|
|
21180
21248
|
const [n, d] = [op1.asSmallInteger, op2.asSmallInteger];
|
|
21181
21249
|
if (n !== null && d !== null && d !== 0)
|
|
21182
|
-
return ce.number([n, d]);
|
|
21250
|
+
return ce.number(reducedRational$1([n, d]));
|
|
21183
21251
|
if (op1.isInteger && op2.isInteger) {
|
|
21184
21252
|
// eslint-disable-next-line prefer-const
|
|
21185
21253
|
let [nSign, dn] = makePositive(op1);
|
|
@@ -21476,7 +21544,7 @@ const ARITHMETIC_LIBRARY = [
|
|
|
21476
21544
|
wikidata: 'Q204037',
|
|
21477
21545
|
complexity: 4000,
|
|
21478
21546
|
signature: {
|
|
21479
|
-
domain: ['Function', 'Number', 'Number'
|
|
21547
|
+
domain: ['Function', 'Number', 'Number'],
|
|
21480
21548
|
N: (ce, ops) => {
|
|
21481
21549
|
if (ops[0].decimalValue)
|
|
21482
21550
|
return ce.number(ops[0].decimalValue.log());
|
|
@@ -21494,7 +21562,7 @@ const ARITHMETIC_LIBRARY = [
|
|
|
21494
21562
|
wikidata: 'Q11197',
|
|
21495
21563
|
complexity: 4100,
|
|
21496
21564
|
signature: {
|
|
21497
|
-
domain: ['Function', 'Number', 'Number', 'Number'],
|
|
21565
|
+
domain: ['Function', 'Number', ['Maybe', 'Number'], 'Number'],
|
|
21498
21566
|
N: (ce, ops) => {
|
|
21499
21567
|
const exponent = ops[0];
|
|
21500
21568
|
const base = ops[1] ?? ce.number(10);
|
|
@@ -21572,7 +21640,7 @@ const ARITHMETIC_LIBRARY = [
|
|
|
21572
21640
|
let result = undefined;
|
|
21573
21641
|
const rest = [];
|
|
21574
21642
|
for (const op of ops) {
|
|
21575
|
-
if (!op.isNumber || op.
|
|
21643
|
+
if (!op.isNumber || op.numericValue === undefined)
|
|
21576
21644
|
rest.push(op);
|
|
21577
21645
|
else if (!result || op.isGreater(result))
|
|
21578
21646
|
result = op;
|
|
@@ -21602,7 +21670,7 @@ const ARITHMETIC_LIBRARY = [
|
|
|
21602
21670
|
let result = undefined;
|
|
21603
21671
|
const rest = [];
|
|
21604
21672
|
for (const op of ops) {
|
|
21605
|
-
if (!op.isNumber || op.
|
|
21673
|
+
if (!op.isNumber || op.numericValue === undefined)
|
|
21606
21674
|
rest.push(op);
|
|
21607
21675
|
else if (!result || op.isLess(result))
|
|
21608
21676
|
result = op;
|
|
@@ -21737,11 +21805,13 @@ const ARITHMETIC_LIBRARY = [
|
|
|
21737
21805
|
return ce.number([n, d]);
|
|
21738
21806
|
return undefined;
|
|
21739
21807
|
}
|
|
21808
|
+
//
|
|
21740
21809
|
// If there is a single argument, i.e. `['Rational', 'Pi']`
|
|
21741
21810
|
// the function evaluates to a rational expression of the argument
|
|
21742
|
-
|
|
21811
|
+
//
|
|
21812
|
+
const f = ops[0].N().asFloat ?? null;
|
|
21743
21813
|
if (f === null)
|
|
21744
|
-
return
|
|
21814
|
+
return undefined;
|
|
21745
21815
|
const r = rationalize(f);
|
|
21746
21816
|
if (typeof r === 'number')
|
|
21747
21817
|
return ce.number(r);
|
|
@@ -21944,10 +22014,8 @@ const ARITHMETIC_LIBRARY = [
|
|
|
21944
22014
|
}
|
|
21945
22015
|
// Maybe a compound symbol
|
|
21946
22016
|
let sub = op2.string ?? op2.symbol;
|
|
21947
|
-
if (!sub)
|
|
21948
|
-
|
|
21949
|
-
sub = op2.asSmallInteger.toString();
|
|
21950
|
-
}
|
|
22017
|
+
if (!sub && op2.isLiteral && op2.asSmallInteger !== null)
|
|
22018
|
+
sub = op2.asSmallInteger.toString();
|
|
21951
22019
|
if (sub)
|
|
21952
22020
|
return ce.symbol(op1.symbol + '_' + sub);
|
|
21953
22021
|
}
|
|
@@ -22656,29 +22724,22 @@ const CORE_LIBRARY = [
|
|
|
22656
22724
|
threadable: true,
|
|
22657
22725
|
hold: 'all',
|
|
22658
22726
|
signature: {
|
|
22659
|
-
domain: ['Function', ['Sequence', 'Anything'], '
|
|
22660
|
-
|
|
22727
|
+
domain: ['Function', ['Sequence', 'Anything'], 'Anything'],
|
|
22728
|
+
canonical: (ce, ops) => {
|
|
22661
22729
|
if (ops.length === 0)
|
|
22662
22730
|
return ce.symbol('Nothing');
|
|
22663
|
-
const
|
|
22664
|
-
|
|
22665
|
-
.
|
|
22666
|
-
|
|
22667
|
-
|
|
22668
|
-
return symName;
|
|
22669
|
-
const stringValue = arg.string;
|
|
22670
|
-
if (stringValue !== null)
|
|
22671
|
-
return stringValue;
|
|
22672
|
-
const numValue = arg.smallIntegerValue;
|
|
22673
|
-
if (numValue !== null)
|
|
22674
|
-
return numValue.toString();
|
|
22675
|
-
return '';
|
|
22676
|
-
})
|
|
22731
|
+
const arg = ops
|
|
22732
|
+
.map((x) => x.symbol ??
|
|
22733
|
+
x.string ??
|
|
22734
|
+
(x.isLiteral ? x.asSmallInteger?.toString() : null) ??
|
|
22735
|
+
'')
|
|
22677
22736
|
.join('');
|
|
22678
22737
|
if (arg.length > 0)
|
|
22679
22738
|
return ce.symbol(arg);
|
|
22680
22739
|
return ce.symbol('Nothing');
|
|
22681
22740
|
},
|
|
22741
|
+
// Note: a `["Symbol"]` expression is never evaluated, it gets
|
|
22742
|
+
// transformed into something else (a symbol) during canonicalization
|
|
22682
22743
|
},
|
|
22683
22744
|
},
|
|
22684
22745
|
{
|
|
@@ -24622,7 +24683,7 @@ class BoxedSymbolDefinitionImpl {
|
|
|
24622
24683
|
this._domain = null;
|
|
24623
24684
|
}
|
|
24624
24685
|
bind() {
|
|
24625
|
-
this._value =
|
|
24686
|
+
this._value = null;
|
|
24626
24687
|
// this._domain = this._domain?._purge();
|
|
24627
24688
|
const def = this._def;
|
|
24628
24689
|
const ce = this._engine;
|
|
@@ -24650,10 +24711,10 @@ class BoxedSymbolDefinitionImpl {
|
|
|
24650
24711
|
// unit: def.unit ? ce.box(def.unit) : undefined,
|
|
24651
24712
|
});
|
|
24652
24713
|
//
|
|
24653
|
-
// 1/ Is it a number?
|
|
24714
|
+
// 1/ Is it defined as a simple machine number?
|
|
24654
24715
|
//
|
|
24655
24716
|
if ('value' in def && typeof def.value === 'number') {
|
|
24656
|
-
// If the
|
|
24717
|
+
// If the definition entry is provided as a number, assume it's a
|
|
24657
24718
|
// variable, and infer its domain based on its value.
|
|
24658
24719
|
const value = ce.number(def.value);
|
|
24659
24720
|
let domain;
|
|
@@ -24672,12 +24733,15 @@ class BoxedSymbolDefinitionImpl {
|
|
|
24672
24733
|
//
|
|
24673
24734
|
// 2/ It's a full definition with no value or a non-numeric value
|
|
24674
24735
|
//
|
|
24675
|
-
let value;
|
|
24676
|
-
if (def.
|
|
24677
|
-
value =
|
|
24678
|
-
|
|
24679
|
-
|
|
24680
|
-
|
|
24736
|
+
let value = undefined;
|
|
24737
|
+
if (isLatexString(def.value))
|
|
24738
|
+
value = ce.parse(def.value);
|
|
24739
|
+
else if (typeof def.value === 'function')
|
|
24740
|
+
value = ce.box(def.value(ce) ?? 'Undefined');
|
|
24741
|
+
else if (def.value)
|
|
24742
|
+
value = ce.box(def.value);
|
|
24743
|
+
if (!value && def.hold === false)
|
|
24744
|
+
throw new Error(`Symbol definition "${def.name}": Expected a value when "hold=false" `);
|
|
24681
24745
|
value = value?.canonical;
|
|
24682
24746
|
//
|
|
24683
24747
|
// If there is a domain specified in the definition, and it is compatible
|
|
@@ -24695,38 +24759,27 @@ class BoxedSymbolDefinitionImpl {
|
|
|
24695
24759
|
domain = defDomain;
|
|
24696
24760
|
else
|
|
24697
24761
|
domain = value?.domain ?? ce.defaultDomain;
|
|
24698
|
-
if (!value) {
|
|
24699
|
-
this._value = undefined;
|
|
24700
|
-
this._domain = domain;
|
|
24701
|
-
this.setProps(domainToFlags(domain));
|
|
24702
|
-
this.setProps(result);
|
|
24703
|
-
return;
|
|
24704
|
-
}
|
|
24705
24762
|
this._value = value;
|
|
24706
24763
|
this._domain = domain;
|
|
24707
|
-
|
|
24764
|
+
if (value)
|
|
24765
|
+
this.setProps(valueToFlags(value));
|
|
24708
24766
|
this.setProps(domainToFlags(domain));
|
|
24709
24767
|
this.setProps(result);
|
|
24710
24768
|
}
|
|
24711
24769
|
get value() {
|
|
24712
24770
|
if (this._value === null)
|
|
24713
24771
|
this.bind();
|
|
24714
|
-
if (this._value === undefined) {
|
|
24715
|
-
if (isLatexString(this._def.value))
|
|
24716
|
-
this._value = this._engine.parse(this._def.value);
|
|
24717
|
-
else if (typeof this._def.value === 'function')
|
|
24718
|
-
this._value = this._engine.box(this._def.value(this._engine) ?? 'Undefined');
|
|
24719
|
-
else if (this._def.value)
|
|
24720
|
-
this._value = this._engine.box(this._def.value);
|
|
24721
|
-
}
|
|
24722
24772
|
return this._value ?? undefined;
|
|
24723
24773
|
}
|
|
24724
24774
|
set value(val) {
|
|
24775
|
+
// Need to bind first to check, e.g. `this.constant`
|
|
24776
|
+
if (this._value === null)
|
|
24777
|
+
this.bind();
|
|
24725
24778
|
if (this.constant)
|
|
24726
24779
|
throw new Error(`The value of the constant "${this.name}" cannot be changed`);
|
|
24727
24780
|
if (typeof val === 'number')
|
|
24728
24781
|
val = this._engine.box(val);
|
|
24729
|
-
this._value = val;
|
|
24782
|
+
this._value = val ?? null;
|
|
24730
24783
|
if (val)
|
|
24731
24784
|
this.setProps(valueToFlags(val));
|
|
24732
24785
|
}
|
|
@@ -25766,26 +25819,26 @@ class BoxedSymbol extends AbstractBoxedExpression {
|
|
|
25766
25819
|
return;
|
|
25767
25820
|
}
|
|
25768
25821
|
get canonical() {
|
|
25769
|
-
if (this.symbolDefinition?.hold ===
|
|
25770
|
-
return
|
|
25771
|
-
|
|
25772
|
-
|
|
25773
|
-
|
|
25822
|
+
if (this.symbolDefinition?.hold === true)
|
|
25823
|
+
return this;
|
|
25824
|
+
return (this.symbolDefinition?.value?.value ??
|
|
25825
|
+
this.symbolDefinition?.value ??
|
|
25826
|
+
this);
|
|
25774
25827
|
}
|
|
25775
25828
|
get wikidata() {
|
|
25776
|
-
return this._wikidata ?? this.baseDefinition?.wikidata ??
|
|
25829
|
+
return this._wikidata ?? this.baseDefinition?.wikidata ?? undefined;
|
|
25777
25830
|
}
|
|
25778
25831
|
get description() {
|
|
25779
25832
|
if (!this.baseDefinition)
|
|
25780
|
-
return
|
|
25833
|
+
return undefined;
|
|
25781
25834
|
if (!this.baseDefinition.description)
|
|
25782
|
-
return
|
|
25835
|
+
return undefined;
|
|
25783
25836
|
if (typeof this.baseDefinition.description === 'string')
|
|
25784
25837
|
return [this.baseDefinition.description];
|
|
25785
25838
|
return this.baseDefinition.description;
|
|
25786
25839
|
}
|
|
25787
25840
|
get url() {
|
|
25788
|
-
return this.baseDefinition?.url ??
|
|
25841
|
+
return this.baseDefinition?.url ?? undefined;
|
|
25789
25842
|
}
|
|
25790
25843
|
get complexity() {
|
|
25791
25844
|
return 7;
|
|
@@ -25865,7 +25918,7 @@ class BoxedSymbol extends AbstractBoxedExpression {
|
|
|
25865
25918
|
}
|
|
25866
25919
|
}
|
|
25867
25920
|
get value() {
|
|
25868
|
-
return this.symbolDefinition?.value;
|
|
25921
|
+
return this.symbolDefinition?.value ?? this;
|
|
25869
25922
|
}
|
|
25870
25923
|
set value(value) {
|
|
25871
25924
|
// Symbols starting with `_` are wildcards and never have an associated
|
|
@@ -25912,7 +25965,7 @@ class BoxedSymbol extends AbstractBoxedExpression {
|
|
|
25912
25965
|
}
|
|
25913
25966
|
}
|
|
25914
25967
|
get numericValue() {
|
|
25915
|
-
return this.symbolDefinition?.value?.numericValue;
|
|
25968
|
+
return this.symbolDefinition?.value?.numericValue ?? undefined;
|
|
25916
25969
|
}
|
|
25917
25970
|
get domain() {
|
|
25918
25971
|
if (this.functionDefinition)
|
|
@@ -25949,7 +26002,7 @@ class BoxedSymbol extends AbstractBoxedExpression {
|
|
|
25949
26002
|
get explicitDomain() {
|
|
25950
26003
|
if (this.functionDefinition)
|
|
25951
26004
|
return this.engine.domain('Function');
|
|
25952
|
-
return this.symbolDefinition?.domain ??
|
|
26005
|
+
return this.symbolDefinition?.domain ?? undefined;
|
|
25953
26006
|
}
|
|
25954
26007
|
get json() {
|
|
25955
26008
|
return serializeJsonSymbol(this.engine, this._name, {
|
|
@@ -25960,17 +26013,23 @@ class BoxedSymbol extends AbstractBoxedExpression {
|
|
|
25960
26013
|
get sgn() {
|
|
25961
26014
|
// If available, use the value associated with this symbol.
|
|
25962
26015
|
// Note that `null` is an acceptable and valid value
|
|
25963
|
-
const
|
|
25964
|
-
if (
|
|
25965
|
-
|
|
26016
|
+
const v = this.numericValue;
|
|
26017
|
+
if (v && v !== this) {
|
|
26018
|
+
const s = v.sgn;
|
|
26019
|
+
if (s !== undefined)
|
|
26020
|
+
return s;
|
|
26021
|
+
}
|
|
25966
26022
|
// We didn't get a definitive answer from the value
|
|
25967
26023
|
// of this symbol. Check flags.
|
|
25968
|
-
|
|
25969
|
-
|
|
25970
|
-
|
|
25971
|
-
|
|
25972
|
-
|
|
25973
|
-
|
|
26024
|
+
const def = this.symbolDefinition;
|
|
26025
|
+
if (def) {
|
|
26026
|
+
if (def.zero === true)
|
|
26027
|
+
return 0;
|
|
26028
|
+
if (def.positive === true)
|
|
26029
|
+
return 1;
|
|
26030
|
+
if (def.negative === true)
|
|
26031
|
+
return -1;
|
|
26032
|
+
}
|
|
25974
26033
|
return undefined;
|
|
25975
26034
|
}
|
|
25976
26035
|
has(x) {
|
|
@@ -25993,15 +26052,22 @@ class BoxedSymbol extends AbstractBoxedExpression {
|
|
|
25993
26052
|
return null;
|
|
25994
26053
|
}
|
|
25995
26054
|
isEqual(rhs) {
|
|
26055
|
+
if (!this.isCanonical)
|
|
26056
|
+
return this.canonical.isEqual(rhs);
|
|
26057
|
+
rhs = rhs.canonical;
|
|
26058
|
+
// Boxed Identity
|
|
25996
26059
|
if (this === rhs)
|
|
25997
26060
|
return true;
|
|
25998
26061
|
// Idempotency ('x' = 'x')
|
|
25999
26062
|
if (rhs.symbol !== null)
|
|
26000
26063
|
return rhs.symbol === this._name;
|
|
26001
26064
|
// Mathematical/numeric equality
|
|
26002
|
-
const
|
|
26003
|
-
if (
|
|
26004
|
-
|
|
26065
|
+
const lhsVal = this.symbolDefinition?.value?.numericValue;
|
|
26066
|
+
if (lhsVal) {
|
|
26067
|
+
const rhsVal = rhs.numericValue;
|
|
26068
|
+
if (rhsVal)
|
|
26069
|
+
return lhsVal.isEqual(rhsVal);
|
|
26070
|
+
}
|
|
26005
26071
|
if (rhs.isZero) {
|
|
26006
26072
|
if (this.isZero)
|
|
26007
26073
|
return true;
|
|
@@ -26012,6 +26078,8 @@ class BoxedSymbol extends AbstractBoxedExpression {
|
|
|
26012
26078
|
return false;
|
|
26013
26079
|
// @todo could test other contradictory properties: prime vs composite, etc...
|
|
26014
26080
|
// Direct assumptions
|
|
26081
|
+
if (this.engine.ask(['Equal', this, rhs]).length > 0)
|
|
26082
|
+
return true;
|
|
26015
26083
|
if (this.engine.ask(['NotEqual', this, rhs]).length > 0)
|
|
26016
26084
|
return false;
|
|
26017
26085
|
//@todo: could use range
|
|
@@ -26982,15 +27050,22 @@ class ComputeEngine {
|
|
|
26982
27050
|
return this.divide(ops[0] ?? this.error('missing'), ops[1] ?? this.error('missing'), metadata);
|
|
26983
27051
|
if (head === 'Power')
|
|
26984
27052
|
return this.power(ops[0] ?? this.error('missing'), ops[1] ?? this.error('missing'), metadata);
|
|
26985
|
-
|
|
26986
|
-
return result.canonical;
|
|
27053
|
+
return makeCanonicalFunction(this, head, ops, { metadata });
|
|
26987
27054
|
}
|
|
26988
27055
|
/** @internal */
|
|
26989
27056
|
_fn(head, ops, metadata) {
|
|
26990
27057
|
// if (!ops.every((x) => x.isCanonical)) debugger;
|
|
26991
|
-
|
|
26992
|
-
|
|
26993
|
-
|
|
27058
|
+
// return makeCanonicalFunction(this, head, ops, {
|
|
27059
|
+
// metadata,
|
|
27060
|
+
// canonical: true,
|
|
27061
|
+
// });
|
|
27062
|
+
return new BoxedFunction(this, head, ops, {
|
|
27063
|
+
metadata,
|
|
27064
|
+
canonical: true,
|
|
27065
|
+
def: typeof head === 'string' && this.context
|
|
27066
|
+
? this.lookupFunction(head, this.context)
|
|
27067
|
+
: undefined,
|
|
27068
|
+
});
|
|
26994
27069
|
}
|
|
26995
27070
|
error(message, where) {
|
|
26996
27071
|
if (where && Array.isArray(where) && where[0] === 'Latex') {
|
|
@@ -27321,6 +27396,6 @@ class ComputeEngine {
|
|
|
27321
27396
|
}
|
|
27322
27397
|
|
|
27323
27398
|
// This file is the root of the `compute-engine` package
|
|
27324
|
-
const version = '0.
|
|
27399
|
+
const version = '0.8.0';
|
|
27325
27400
|
|
|
27326
27401
|
export { ComputeEngine, getVars, isEnvironmentEntry, isFunctionEntry, isInfixEntry, isMatchfixEntry, isPostfixEntry, isPrefixEntry, isSymbolEntry, version };
|