@cortex-js/compute-engine 0.31.0 → 0.32.1
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 +1843 -249
- package/dist/compute-engine.min.esm.js +38 -38
- package/dist/compute-engine.min.umd.js +38 -38
- package/dist/compute-engine.umd.js +1843 -249
- package/dist/math-json.esm.js +2 -2
- package/dist/math-json.min.esm.js +2 -2
- package/dist/math-json.min.umd.js +2 -2
- package/dist/math-json.umd.js +2 -2
- package/dist/types/common/ansi-codes.d.ts +1 -1
- package/dist/types/common/configuration-change.d.ts +1 -1
- package/dist/types/common/fuzzy-string-match.d.ts +1 -1
- package/dist/types/common/grapheme-splitter.d.ts +1 -1
- package/dist/types/common/interruptible.d.ts +1 -1
- package/dist/types/common/one-of.d.ts +1 -1
- package/dist/types/common/signals.d.ts +1 -1
- package/dist/types/common/type/ast-nodes.d.ts +1 -1
- package/dist/types/common/type/boxed-type.d.ts +1 -1
- package/dist/types/common/type/lexer.d.ts +1 -1
- package/dist/types/common/type/parse.d.ts +1 -1
- package/dist/types/common/type/parser.d.ts +1 -1
- package/dist/types/common/type/primitive.d.ts +1 -1
- package/dist/types/common/type/serialize.d.ts +1 -1
- package/dist/types/common/type/subtype.d.ts +1 -1
- package/dist/types/common/type/type-builder.d.ts +1 -1
- package/dist/types/common/type/types.d.ts +1 -1
- package/dist/types/common/type/utils.d.ts +1 -1
- package/dist/types/common/utils.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 +1 -1
- package/dist/types/compute-engine/boxed-expression/apply.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/arithmetic-add.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/arithmetic-mul-div.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/arithmetic-power.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/ascii-math.d.ts +1 -1
- 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-function.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/boxed-number.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/boxed-operator-definition.d.ts +1 -1
- 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.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/boxed-tensor.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/boxed-value-definition.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/cache.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/canonical-utils.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/canonical.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/compare.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/expand.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/expression-map.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/factor.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/flatten.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/hold.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/match.d.ts +23 -1
- package/dist/types/compute-engine/boxed-expression/negate.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/numerics.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/order.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/polynomials.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/product.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/rules.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/serialize.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/sgn.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/simplify.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/solve.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/terms.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/trigonometry.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/utils.d.ts +1 -1
- package/dist/types/compute-engine/boxed-expression/validate.d.ts +1 -1
- package/dist/types/compute-engine/collection-utils.d.ts +1 -1
- package/dist/types/compute-engine/compilation/base-compiler.d.ts +1 -1
- package/dist/types/compute-engine/compilation/javascript-target.d.ts +1 -1
- package/dist/types/compute-engine/compilation/types.d.ts +1 -1
- package/dist/types/compute-engine/cost-function.d.ts +1 -1
- package/dist/types/compute-engine/function-utils.d.ts +1 -1
- package/dist/types/compute-engine/global-types.d.ts +1 -1
- package/dist/types/compute-engine/index.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-complex.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-linear-algebra.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-relational-operators.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-statistics.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/parse-symbol.d.ts +1 -1
- package/dist/types/compute-engine/latex-syntax/parse.d.ts +14 -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/latex-syntax/types.d.ts +75 -24
- package/dist/types/compute-engine/latex-syntax/utils.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/combinatorics.d.ts +1 -1
- package/dist/types/compute-engine/library/complex.d.ts +1 -1
- package/dist/types/compute-engine/library/control-structures.d.ts +1 -1
- package/dist/types/compute-engine/library/core.d.ts +1 -1
- package/dist/types/compute-engine/library/invisible-operator.d.ts +1 -1
- package/dist/types/compute-engine/library/library.d.ts +1 -1
- package/dist/types/compute-engine/library/linear-algebra.d.ts +1 -1
- package/dist/types/compute-engine/library/logic-analysis.d.ts +64 -0
- package/dist/types/compute-engine/library/logic-utils.d.ts +58 -0
- package/dist/types/compute-engine/library/logic.d.ts +2 -1
- package/dist/types/compute-engine/library/number-theory.d.ts +1 -1
- package/dist/types/compute-engine/library/polynomials.d.ts +1 -1
- package/dist/types/compute-engine/library/random-expression.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/statistics.d.ts +1 -1
- package/dist/types/compute-engine/library/trigonometry.d.ts +1 -1
- package/dist/types/compute-engine/library/utils.d.ts +1 -1
- package/dist/types/compute-engine/numeric-value/big-numeric-value.d.ts +1 -1
- package/dist/types/compute-engine/numeric-value/exact-numeric-value.d.ts +1 -1
- package/dist/types/compute-engine/numeric-value/machine-numeric-value.d.ts +1 -1
- package/dist/types/compute-engine/numeric-value/types.d.ts +1 -1
- package/dist/types/compute-engine/numerics/bigint.d.ts +1 -1
- package/dist/types/compute-engine/numerics/expression.d.ts +1 -1
- package/dist/types/compute-engine/numerics/interval.d.ts +1 -1
- package/dist/types/compute-engine/numerics/monte-carlo.d.ts +1 -1
- package/dist/types/compute-engine/numerics/numeric-bigint.d.ts +1 -1
- package/dist/types/compute-engine/numerics/numeric-bignum.d.ts +1 -1
- package/dist/types/compute-engine/numerics/numeric-complex.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/numerics/rationals.d.ts +1 -1
- package/dist/types/compute-engine/numerics/richardson.d.ts +1 -1
- package/dist/types/compute-engine/numerics/special-functions.d.ts +1 -1
- package/dist/types/compute-engine/numerics/statistics.d.ts +1 -1
- package/dist/types/compute-engine/numerics/strings.d.ts +1 -1
- package/dist/types/compute-engine/numerics/types.d.ts +1 -1
- package/dist/types/compute-engine/symbolic/antiderivative.d.ts +1 -1
- package/dist/types/compute-engine/symbolic/derivative.d.ts +1 -1
- package/dist/types/compute-engine/symbolic/distribute.d.ts +1 -1
- package/dist/types/compute-engine/symbolic/simplify-product.d.ts +6 -0
- package/dist/types/compute-engine/symbolic/simplify-rules.d.ts +1 -1
- package/dist/types/compute-engine/symbolic/simplify-sum.d.ts +6 -0
- package/dist/types/compute-engine/tensor/tensor-fields.d.ts +1 -1
- package/dist/types/compute-engine/tensor/tensors.d.ts +1 -1
- package/dist/types/compute-engine/types.d.ts +1 -1
- package/dist/types/compute-engine.d.ts +1 -1
- package/dist/types/math-json/symbols.d.ts +1 -1
- package/dist/types/math-json/types.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
|
-
/** Compute Engine 0.
|
|
1
|
+
/** Compute Engine 0.32.1 */
|
|
2
2
|
|
|
3
3
|
// node_modules/complex-esm/dist/src/complex.js
|
|
4
4
|
var cosh = Math.cosh || function(x) {
|
|
@@ -7841,7 +7841,11 @@ function serializePower(serializer, expr) {
|
|
|
7841
7841
|
if (denom === 2) {
|
|
7842
7842
|
return serializer.serialize(["Divide", "1", ["Sqrt", base]]);
|
|
7843
7843
|
}
|
|
7844
|
-
return serializer.serialize([
|
|
7844
|
+
return serializer.serialize([
|
|
7845
|
+
"Divide",
|
|
7846
|
+
"1",
|
|
7847
|
+
["Root", base, operand(exp2, 2)]
|
|
7848
|
+
]);
|
|
7845
7849
|
}
|
|
7846
7850
|
if (denom === 2) {
|
|
7847
7851
|
return `${serializer.serialize(["Sqrt", base])}^{${serializer.serialize(
|
|
@@ -7855,13 +7859,20 @@ function serializePower(serializer, expr) {
|
|
|
7855
7859
|
}
|
|
7856
7860
|
}
|
|
7857
7861
|
}
|
|
7862
|
+
const wrapNegativeBase = (latex) => latex.startsWith("-") ? serializer.wrapString(latex, "normal") : latex;
|
|
7858
7863
|
if (operator(base) === "Power") {
|
|
7859
7864
|
const baseBody = operand(base, 1);
|
|
7860
7865
|
const baseExponent = operand(base, 2);
|
|
7866
|
+
const baseBodyLatex = wrapNegativeBase(serializer.wrapShort(baseBody));
|
|
7867
|
+
const baseExponentLatex = serializer.wrapShort(baseExponent);
|
|
7861
7868
|
return `
|
|
7862
|
-
${
|
|
7869
|
+
${baseBodyLatex}^{${supsub("^", baseExponentLatex, serializer.serialize(exp2))}}`;
|
|
7863
7870
|
}
|
|
7864
|
-
return supsub(
|
|
7871
|
+
return supsub(
|
|
7872
|
+
"^",
|
|
7873
|
+
wrapNegativeBase(serializer.wrapShort(base)),
|
|
7874
|
+
serializer.serialize(exp2)
|
|
7875
|
+
);
|
|
7865
7876
|
}
|
|
7866
7877
|
var DEFINITIONS_ARITHMETIC = [
|
|
7867
7878
|
// Constants
|
|
@@ -8142,8 +8153,9 @@ var DEFINITIONS_ARITHMETIC = [
|
|
|
8142
8153
|
},
|
|
8143
8154
|
{
|
|
8144
8155
|
name: "GCD",
|
|
8145
|
-
latexTrigger: ["\\gcd"]
|
|
8156
|
+
latexTrigger: ["\\gcd"],
|
|
8146
8157
|
// command from amsmath package
|
|
8158
|
+
kind: "function"
|
|
8147
8159
|
},
|
|
8148
8160
|
{
|
|
8149
8161
|
symbolTrigger: "gcd",
|
|
@@ -8201,9 +8213,14 @@ var DEFINITIONS_ARITHMETIC = [
|
|
|
8201
8213
|
},
|
|
8202
8214
|
{
|
|
8203
8215
|
name: "LCM",
|
|
8204
|
-
|
|
8216
|
+
latexTrigger: ["\\lcm"],
|
|
8205
8217
|
kind: "function"
|
|
8206
8218
|
},
|
|
8219
|
+
{
|
|
8220
|
+
symbolTrigger: "lcm",
|
|
8221
|
+
kind: "function",
|
|
8222
|
+
parse: "LCM"
|
|
8223
|
+
},
|
|
8207
8224
|
{
|
|
8208
8225
|
symbolTrigger: "LCM",
|
|
8209
8226
|
kind: "function",
|
|
@@ -8477,7 +8494,11 @@ var DEFINITIONS_ARITHMETIC = [
|
|
|
8477
8494
|
{
|
|
8478
8495
|
name: "Square",
|
|
8479
8496
|
precedence: 720,
|
|
8480
|
-
serialize: (serializer, expr) =>
|
|
8497
|
+
serialize: (serializer, expr) => {
|
|
8498
|
+
const base = serializer.wrapShort(operand(expr, 1));
|
|
8499
|
+
const wrapped = base.startsWith("-") ? serializer.wrapString(base, "normal") : base;
|
|
8500
|
+
return wrapped + "^2";
|
|
8501
|
+
}
|
|
8481
8502
|
},
|
|
8482
8503
|
{
|
|
8483
8504
|
latexTrigger: ["\\sum"],
|
|
@@ -10587,40 +10608,43 @@ var DEFINITIONS_LOGIC = [
|
|
|
10587
10608
|
parse: "False"
|
|
10588
10609
|
},
|
|
10589
10610
|
// Operators
|
|
10611
|
+
// Logic operators have lower precedence than comparisons (245)
|
|
10612
|
+
// so that `x = 1 \lor x = 2` parses as `(x = 1) \lor (x = 2)`
|
|
10613
|
+
// See https://github.com/cortex-js/compute-engine/issues/243
|
|
10590
10614
|
{
|
|
10591
10615
|
name: "And",
|
|
10592
10616
|
kind: "infix",
|
|
10593
10617
|
latexTrigger: ["\\land"],
|
|
10594
|
-
precedence:
|
|
10618
|
+
precedence: 235
|
|
10595
10619
|
// serialize: '\\land',
|
|
10596
10620
|
},
|
|
10597
|
-
{ kind: "infix", latexTrigger: ["\\wedge"], parse: "And", precedence:
|
|
10598
|
-
{ kind: "infix", latexTrigger: "\\&", parse: "And", precedence:
|
|
10621
|
+
{ kind: "infix", latexTrigger: ["\\wedge"], parse: "And", precedence: 235 },
|
|
10622
|
+
{ kind: "infix", latexTrigger: "\\&", parse: "And", precedence: 235 },
|
|
10599
10623
|
{
|
|
10600
10624
|
kind: "infix",
|
|
10601
10625
|
latexTrigger: "\\operatorname{and}",
|
|
10602
10626
|
parse: "And",
|
|
10603
|
-
precedence:
|
|
10627
|
+
precedence: 235
|
|
10604
10628
|
},
|
|
10605
10629
|
{
|
|
10606
10630
|
name: "Or",
|
|
10607
10631
|
kind: "infix",
|
|
10608
10632
|
latexTrigger: ["\\lor"],
|
|
10609
|
-
precedence:
|
|
10633
|
+
precedence: 230
|
|
10610
10634
|
},
|
|
10611
|
-
{ kind: "infix", latexTrigger: ["\\vee"], parse: "Or", precedence:
|
|
10612
|
-
{ kind: "infix", latexTrigger: "\\parallel", parse: "Or", precedence:
|
|
10635
|
+
{ kind: "infix", latexTrigger: ["\\vee"], parse: "Or", precedence: 230 },
|
|
10636
|
+
{ kind: "infix", latexTrigger: "\\parallel", parse: "Or", precedence: 230 },
|
|
10613
10637
|
{
|
|
10614
10638
|
kind: "infix",
|
|
10615
10639
|
latexTrigger: "\\operatorname{or}",
|
|
10616
10640
|
parse: "Or",
|
|
10617
|
-
precedence:
|
|
10641
|
+
precedence: 230
|
|
10618
10642
|
},
|
|
10619
10643
|
{
|
|
10620
10644
|
name: "Xor",
|
|
10621
10645
|
kind: "infix",
|
|
10622
10646
|
latexTrigger: ["\\veebar"],
|
|
10623
|
-
precedence:
|
|
10647
|
+
precedence: 232
|
|
10624
10648
|
},
|
|
10625
10649
|
// Possible alt: \oplus ⊕ U+2295
|
|
10626
10650
|
{
|
|
@@ -10639,7 +10663,7 @@ var DEFINITIONS_LOGIC = [
|
|
|
10639
10663
|
name: "Nand",
|
|
10640
10664
|
kind: "infix",
|
|
10641
10665
|
latexTrigger: ["\\barwedge"],
|
|
10642
|
-
precedence:
|
|
10666
|
+
precedence: 232
|
|
10643
10667
|
// serialize: '\\mid',
|
|
10644
10668
|
},
|
|
10645
10669
|
{
|
|
@@ -10647,7 +10671,7 @@ var DEFINITIONS_LOGIC = [
|
|
|
10647
10671
|
kind: "infix",
|
|
10648
10672
|
latexTrigger: ["\u22BD"],
|
|
10649
10673
|
// bar vee
|
|
10650
|
-
precedence:
|
|
10674
|
+
precedence: 232
|
|
10651
10675
|
// serialize: '\\downarrow',
|
|
10652
10676
|
},
|
|
10653
10677
|
// Functions
|
|
@@ -10743,7 +10767,7 @@ var DEFINITIONS_LOGIC = [
|
|
|
10743
10767
|
latexTrigger: ["\\forall"],
|
|
10744
10768
|
precedence: 200,
|
|
10745
10769
|
// Has to be lower than COMPARISON_PRECEDENCE
|
|
10746
|
-
serialize: "\\forall",
|
|
10770
|
+
serialize: serializeQuantifier("\\forall"),
|
|
10747
10771
|
parse: parseQuantifier("ForAll")
|
|
10748
10772
|
},
|
|
10749
10773
|
{
|
|
@@ -10752,7 +10776,7 @@ var DEFINITIONS_LOGIC = [
|
|
|
10752
10776
|
latexTrigger: ["\\exists"],
|
|
10753
10777
|
precedence: 200,
|
|
10754
10778
|
// Has to be lower than COMPARISON_PRECEDENCE,
|
|
10755
|
-
serialize: "\\exists",
|
|
10779
|
+
serialize: serializeQuantifier("\\exists"),
|
|
10756
10780
|
parse: parseQuantifier("Exists")
|
|
10757
10781
|
},
|
|
10758
10782
|
{
|
|
@@ -10761,7 +10785,7 @@ var DEFINITIONS_LOGIC = [
|
|
|
10761
10785
|
latexTrigger: ["\\exists", "!"],
|
|
10762
10786
|
precedence: 200,
|
|
10763
10787
|
// Has to be lower than COMPARISON_PRECEDENCE,
|
|
10764
|
-
serialize: "\\exists!",
|
|
10788
|
+
serialize: serializeQuantifier("\\exists!"),
|
|
10765
10789
|
parse: parseQuantifier("ExistsUnique")
|
|
10766
10790
|
},
|
|
10767
10791
|
{
|
|
@@ -10770,7 +10794,7 @@ var DEFINITIONS_LOGIC = [
|
|
|
10770
10794
|
latexTrigger: ["\\lnot", "\\forall"],
|
|
10771
10795
|
precedence: 200,
|
|
10772
10796
|
// Has to be lower than COMPARISON_PRECEDENCE
|
|
10773
|
-
serialize: "\\lnot\\forall",
|
|
10797
|
+
serialize: serializeQuantifier("\\lnot\\forall"),
|
|
10774
10798
|
parse: parseQuantifier("NotForAll")
|
|
10775
10799
|
},
|
|
10776
10800
|
{
|
|
@@ -10779,7 +10803,7 @@ var DEFINITIONS_LOGIC = [
|
|
|
10779
10803
|
latexTrigger: ["\\lnot", "\\exists"],
|
|
10780
10804
|
precedence: 200,
|
|
10781
10805
|
// Has to be lower than COMPARISON_PRECEDENCE,
|
|
10782
|
-
serialize: "\\lnot\\exists",
|
|
10806
|
+
serialize: serializeQuantifier("\\lnot\\exists"),
|
|
10783
10807
|
parse: parseQuantifier("NotExists")
|
|
10784
10808
|
},
|
|
10785
10809
|
{
|
|
@@ -10840,19 +10864,53 @@ var DEFINITIONS_LOGIC = [
|
|
|
10840
10864
|
if (!DEFINITIONS_INEQUALITIES.some((x) => x.name === h)) return null;
|
|
10841
10865
|
return ["Boole", body];
|
|
10842
10866
|
}
|
|
10867
|
+
},
|
|
10868
|
+
// Predicate application in First-Order Logic.
|
|
10869
|
+
// ["Predicate", "P", "x", "y"] serializes to "P(x, y)"
|
|
10870
|
+
{
|
|
10871
|
+
name: "Predicate",
|
|
10872
|
+
serialize: (serializer, expr) => {
|
|
10873
|
+
const args = operands(expr);
|
|
10874
|
+
if (args.length === 0) return "";
|
|
10875
|
+
const pred = args[0];
|
|
10876
|
+
const predStr = typeof pred === "string" ? pred : serializer.serialize(pred);
|
|
10877
|
+
if (args.length === 1) return predStr;
|
|
10878
|
+
const argStrs = args.slice(1).map((arg) => serializer.serialize(arg));
|
|
10879
|
+
return `${predStr}(${argStrs.join(", ")})`;
|
|
10880
|
+
}
|
|
10843
10881
|
}
|
|
10844
10882
|
];
|
|
10883
|
+
function serializeQuantifier(quantifierSymbol) {
|
|
10884
|
+
return (serializer, expr) => {
|
|
10885
|
+
const args = operands(expr);
|
|
10886
|
+
if (args.length === 0) return quantifierSymbol;
|
|
10887
|
+
if (args.length === 1)
|
|
10888
|
+
return `${quantifierSymbol} ${serializer.serialize(args[0])}`;
|
|
10889
|
+
const boundVar = serializer.serialize(args[0]);
|
|
10890
|
+
const body = serializer.serialize(args[1]);
|
|
10891
|
+
return `${quantifierSymbol} ${boundVar}, ${body}`;
|
|
10892
|
+
};
|
|
10893
|
+
}
|
|
10894
|
+
function tightBindingCondition(p, terminator) {
|
|
10895
|
+
return p.peek === "\\to" || p.peek === "\\rightarrow" || p.peek === "\\implies" || p.peek === "\\Rightarrow" || p.peek === "\\iff" || p.peek === "\\Leftrightarrow" || p.peek === "\\land" || p.peek === "\\wedge" || p.peek === "\\lor" || p.peek === "\\vee" || (terminator.condition?.(p) ?? false);
|
|
10896
|
+
}
|
|
10845
10897
|
function parseQuantifier(kind) {
|
|
10846
10898
|
return (parser, terminator) => {
|
|
10847
10899
|
const index = parser.index;
|
|
10900
|
+
const useTightBinding = parser.options.quantifierScope !== "loose";
|
|
10848
10901
|
const symbol2 = parser.parseSymbol(terminator);
|
|
10849
10902
|
if (symbol2) {
|
|
10850
10903
|
parser.skipSpace();
|
|
10851
10904
|
if (parser.match(",") || parser.match("\\mid") || parser.match(".") || parser.match(":") || parser.match("\\colon")) {
|
|
10852
|
-
const
|
|
10905
|
+
const bodyTerminator = useTightBinding ? { ...terminator, condition: (p) => tightBindingCondition(p, terminator) } : terminator;
|
|
10906
|
+
parser.enterQuantifierScope();
|
|
10907
|
+
const body2 = parser.parseExpression(bodyTerminator);
|
|
10908
|
+
parser.exitQuantifierScope();
|
|
10853
10909
|
return [kind, symbol2, missingIfEmpty(body2)];
|
|
10854
10910
|
}
|
|
10911
|
+
parser.enterQuantifierScope();
|
|
10855
10912
|
const body = parser.parseEnclosure();
|
|
10913
|
+
parser.exitQuantifierScope();
|
|
10856
10914
|
if (body) return [kind, symbol2, missingIfEmpty(body)];
|
|
10857
10915
|
}
|
|
10858
10916
|
parser.index = index;
|
|
@@ -10860,11 +10918,16 @@ function parseQuantifier(kind) {
|
|
|
10860
10918
|
if (condition === null) return null;
|
|
10861
10919
|
parser.skipSpace();
|
|
10862
10920
|
if (parser.matchAny([",", "\\mid", ":", "\\colon"])) {
|
|
10863
|
-
const
|
|
10921
|
+
const bodyTerminator = useTightBinding ? { ...terminator, condition: (p) => tightBindingCondition(p, terminator) } : terminator;
|
|
10922
|
+
parser.enterQuantifierScope();
|
|
10923
|
+
const body = parser.parseExpression(bodyTerminator);
|
|
10924
|
+
parser.exitQuantifierScope();
|
|
10864
10925
|
return [kind, condition, missingIfEmpty(body)];
|
|
10865
10926
|
}
|
|
10866
10927
|
if (parser.match("(")) {
|
|
10928
|
+
parser.enterQuantifierScope();
|
|
10867
10929
|
const body = parser.parseExpression(terminator);
|
|
10930
|
+
parser.exitQuantifierScope();
|
|
10868
10931
|
if (!parser.match(")")) return null;
|
|
10869
10932
|
return [kind, condition, missingIfEmpty(body)];
|
|
10870
10933
|
}
|
|
@@ -11353,7 +11416,7 @@ function parseTrig(op) {
|
|
|
11353
11416
|
"\\ch": "Cosh",
|
|
11354
11417
|
// Non-standard
|
|
11355
11418
|
"\\cos": "Cos",
|
|
11356
|
-
"\\cosh": "
|
|
11419
|
+
"\\cosh": "Cosh",
|
|
11357
11420
|
"\\cosec": "Csc",
|
|
11358
11421
|
// Non-standard
|
|
11359
11422
|
"\\cot": "Cot",
|
|
@@ -13265,8 +13328,41 @@ function parseInvalidSymbol(parser) {
|
|
|
13265
13328
|
return parser.error(["invalid-symbol", { str: validateSymbol(id) }], start);
|
|
13266
13329
|
}
|
|
13267
13330
|
function parseSymbol(parser) {
|
|
13268
|
-
if (/^[a-zA-Z]$/.test(parser.peek) || /^\p{XIDS}$/u.test(parser.peek))
|
|
13269
|
-
|
|
13331
|
+
if (/^[a-zA-Z]$/.test(parser.peek) || /^\p{XIDS}$/u.test(parser.peek)) {
|
|
13332
|
+
let id2 = parser.nextToken();
|
|
13333
|
+
while (!parser.atEnd) {
|
|
13334
|
+
const currentPeek = parser.peek;
|
|
13335
|
+
if (currentPeek !== "_") break;
|
|
13336
|
+
const underscoreIndex = parser.index;
|
|
13337
|
+
parser.nextToken();
|
|
13338
|
+
const hasBrace = parser.match("<{>");
|
|
13339
|
+
if (hasBrace) {
|
|
13340
|
+
const firstToken = parser.peek;
|
|
13341
|
+
if (firstToken === "(" || firstToken === "\\lparen" || firstToken === "\\left") {
|
|
13342
|
+
parser.index = underscoreIndex;
|
|
13343
|
+
break;
|
|
13344
|
+
}
|
|
13345
|
+
const sub2 = parseSymbolBody(parser);
|
|
13346
|
+
const hasOperators = sub2 !== null && /plus|minus|times|ast/.test(sub2);
|
|
13347
|
+
if (sub2 === null || sub2.includes(",") || hasOperators || parser.peek !== "<}>") {
|
|
13348
|
+
parser.index = underscoreIndex;
|
|
13349
|
+
break;
|
|
13350
|
+
}
|
|
13351
|
+
parser.match("<}>");
|
|
13352
|
+
id2 += "_" + sub2;
|
|
13353
|
+
} else {
|
|
13354
|
+
const subToken = parser.peek;
|
|
13355
|
+
if (/^[a-zA-Z0-9]$/.test(subToken) || /^\p{XIDS}$/u.test(subToken)) {
|
|
13356
|
+
parser.nextToken();
|
|
13357
|
+
id2 += "_" + subToken;
|
|
13358
|
+
} else {
|
|
13359
|
+
parser.index = underscoreIndex;
|
|
13360
|
+
break;
|
|
13361
|
+
}
|
|
13362
|
+
}
|
|
13363
|
+
}
|
|
13364
|
+
return id2;
|
|
13365
|
+
}
|
|
13270
13366
|
let id = matchPrefixedSymbol(parser);
|
|
13271
13367
|
if (!id) {
|
|
13272
13368
|
id = "";
|
|
@@ -13366,6 +13462,18 @@ var _Parser = class {
|
|
|
13366
13462
|
throw new Error(`Symbol ${id} already declared as a different type`);
|
|
13367
13463
|
this.symbolTable.ids[id] = type2;
|
|
13368
13464
|
}
|
|
13465
|
+
// Track whether we're inside a quantifier body (ForAll, Exists, etc.)
|
|
13466
|
+
// When true, single uppercase letters followed by () are parsed as predicates
|
|
13467
|
+
_quantifierScopeDepth = 0;
|
|
13468
|
+
get inQuantifierScope() {
|
|
13469
|
+
return this._quantifierScopeDepth > 0;
|
|
13470
|
+
}
|
|
13471
|
+
enterQuantifierScope() {
|
|
13472
|
+
this._quantifierScopeDepth++;
|
|
13473
|
+
}
|
|
13474
|
+
exitQuantifierScope() {
|
|
13475
|
+
if (this._quantifierScopeDepth > 0) this._quantifierScopeDepth--;
|
|
13476
|
+
}
|
|
13369
13477
|
get index() {
|
|
13370
13478
|
return this._index;
|
|
13371
13479
|
}
|
|
@@ -14251,9 +14359,10 @@ var _Parser = class {
|
|
|
14251
14359
|
this.skipSpace();
|
|
14252
14360
|
let body = this.parseExpression();
|
|
14253
14361
|
this.skipSpace();
|
|
14254
|
-
|
|
14255
|
-
|
|
14256
|
-
|
|
14362
|
+
const boundary = this._boundaries[this._boundaries.length - 1]?.tokens;
|
|
14363
|
+
const matchedBoundary = this.matchBoundary();
|
|
14364
|
+
const sameTrigger = typeof def.openTrigger === "string" && typeof def.closeTrigger === "string" && def.openTrigger === def.closeTrigger || Array.isArray(def.openTrigger) && Array.isArray(def.closeTrigger) && def.openTrigger.length === def.closeTrigger.length && def.openTrigger.every((tok, i) => tok === def.closeTrigger[i]);
|
|
14365
|
+
if (matchedBoundary && isEmptySequence(body) && sameTrigger && boundary) {
|
|
14257
14366
|
this.index = bodyStart;
|
|
14258
14367
|
this.skipSpace();
|
|
14259
14368
|
body = this.parseExpression();
|
|
@@ -14263,6 +14372,18 @@ var _Parser = class {
|
|
|
14263
14372
|
if (!this.atEnd) continue;
|
|
14264
14373
|
return null;
|
|
14265
14374
|
}
|
|
14375
|
+
} else if (!matchedBoundary) {
|
|
14376
|
+
const boundary2 = this._boundaries[this._boundaries.length - 1].tokens;
|
|
14377
|
+
this.removeBoundary();
|
|
14378
|
+
this.index = bodyStart;
|
|
14379
|
+
this.skipSpace();
|
|
14380
|
+
body = this.parseExpression();
|
|
14381
|
+
this.skipSpace();
|
|
14382
|
+
if (!this.matchAll(boundary2)) {
|
|
14383
|
+
this.index = start;
|
|
14384
|
+
if (!this.atEnd) continue;
|
|
14385
|
+
return null;
|
|
14386
|
+
}
|
|
14266
14387
|
}
|
|
14267
14388
|
const result = def.parse(this, body ?? "Nothing");
|
|
14268
14389
|
if (result !== null) return result;
|
|
@@ -14311,12 +14432,16 @@ var _Parser = class {
|
|
|
14311
14432
|
break;
|
|
14312
14433
|
}
|
|
14313
14434
|
}
|
|
14435
|
+
let isPredicate = false;
|
|
14314
14436
|
if (fn === null) {
|
|
14315
14437
|
this.index = start;
|
|
14316
14438
|
fn = parseSymbol(this);
|
|
14317
14439
|
if (!this.isFunctionOperator(fn)) {
|
|
14318
|
-
this.
|
|
14319
|
-
|
|
14440
|
+
if (!this.looksLikePredicate(fn)) {
|
|
14441
|
+
this.index = start;
|
|
14442
|
+
return null;
|
|
14443
|
+
}
|
|
14444
|
+
isPredicate = true;
|
|
14320
14445
|
}
|
|
14321
14446
|
}
|
|
14322
14447
|
do {
|
|
@@ -14326,6 +14451,10 @@ var _Parser = class {
|
|
|
14326
14451
|
} while (true);
|
|
14327
14452
|
const args = this.parseArguments("enclosure", until);
|
|
14328
14453
|
if (args === null) return fn;
|
|
14454
|
+
if (isPredicate && typeof fn === "string") {
|
|
14455
|
+
if (this.inQuantifierScope || fn === "D" || fn === "N")
|
|
14456
|
+
return ["Predicate", fn, ...args];
|
|
14457
|
+
}
|
|
14329
14458
|
return typeof fn === "string" ? [fn, ...args] : ["Apply", fn, ...args];
|
|
14330
14459
|
}
|
|
14331
14460
|
parseSymbol(until) {
|
|
@@ -14714,9 +14843,24 @@ var _Parser = class {
|
|
|
14714
14843
|
}
|
|
14715
14844
|
isFunctionOperator(id) {
|
|
14716
14845
|
if (id === null) return false;
|
|
14846
|
+
if (id === "D" || id === "N") return false;
|
|
14717
14847
|
if (this.getSymbolType(id).matches("function")) return true;
|
|
14718
14848
|
return false;
|
|
14719
14849
|
}
|
|
14850
|
+
/**
|
|
14851
|
+
* Check if a symbol looks like a predicate in First-Order Logic.
|
|
14852
|
+
* A predicate is typically a single uppercase letter (P, Q, R, etc.)
|
|
14853
|
+
* followed by parentheses containing arguments.
|
|
14854
|
+
*
|
|
14855
|
+
* This enables automatic inference of predicates without explicit declaration,
|
|
14856
|
+
* so `\forall x. P(x)` works without having to declare `P` as a function.
|
|
14857
|
+
*/
|
|
14858
|
+
looksLikePredicate(id) {
|
|
14859
|
+
if (id === null || typeof id !== "string") return false;
|
|
14860
|
+
if (!/^[A-Z]$/.test(id)) return false;
|
|
14861
|
+
this.skipSpace();
|
|
14862
|
+
return this.peek === "(" || this.peek === "\\left";
|
|
14863
|
+
}
|
|
14720
14864
|
/** Return all defs of the specified kind.
|
|
14721
14865
|
* The defs at the end of the dictionary have priority, since they may
|
|
14722
14866
|
* override previous definitions. (For example, there is a core definition
|
|
@@ -18599,7 +18743,10 @@ function polynomialDegree(expr, variable) {
|
|
|
18599
18743
|
if (op === "Power") {
|
|
18600
18744
|
const baseDeg = polynomialDegree(expr.op1, variable);
|
|
18601
18745
|
if (baseDeg < 0) return -1;
|
|
18602
|
-
if (baseDeg === 0)
|
|
18746
|
+
if (baseDeg === 0) {
|
|
18747
|
+
if (expr.op2.has(variable)) return -1;
|
|
18748
|
+
return 0;
|
|
18749
|
+
}
|
|
18603
18750
|
const exp2 = asSmallInteger(expr.op2);
|
|
18604
18751
|
if (exp2 === null || exp2 < 0) return -1;
|
|
18605
18752
|
return baseDeg * exp2;
|
|
@@ -21638,8 +21785,6 @@ function canonicalLimits(ops, { engine: ce }) {
|
|
|
21638
21785
|
}
|
|
21639
21786
|
if (index.operator === "Hold") index = index.op1;
|
|
21640
21787
|
if (!index.symbol) index = ce.typeError("symbol", index.type, index);
|
|
21641
|
-
if (lower.symbol !== "Nothing") lower = checkType(ce, lower, "number");
|
|
21642
|
-
if (upper.symbol !== "Nothing") upper = checkType(ce, upper, "number");
|
|
21643
21788
|
return ce._fn("Limits", [index, lower, upper]);
|
|
21644
21789
|
}
|
|
21645
21790
|
return null;
|
|
@@ -22518,10 +22663,6 @@ function serializeScientificNotationNumber(valString, options, expMultiple = 1)
|
|
|
22518
22663
|
fractionalPart = options.decimalSeparator + fractionalPart;
|
|
22519
22664
|
wholePart = insertWholeGroupSeparator(wholePart, options);
|
|
22520
22665
|
if (!expString) return wholePart + fractionalPart;
|
|
22521
|
-
if (!fractionalPart) {
|
|
22522
|
-
if (wholePart === "1") return expString;
|
|
22523
|
-
if (wholePart === "-1") return "-" + expString;
|
|
22524
|
-
}
|
|
22525
22666
|
return wholePart + fractionalPart + options.exponentProduct + expString;
|
|
22526
22667
|
}
|
|
22527
22668
|
function serializeAutoNotationNumber(valString, options) {
|
|
@@ -23028,7 +23169,8 @@ var OPERATORS = {
|
|
|
23028
23169
|
Negate: [
|
|
23029
23170
|
(expr, serialize) => {
|
|
23030
23171
|
const base = serialize(expr.op1, 14);
|
|
23031
|
-
|
|
23172
|
+
const op = expr.op1?.operator;
|
|
23173
|
+
if (op === "Power" || op === "Square") return `-(${base})`;
|
|
23032
23174
|
return `-${base}`;
|
|
23033
23175
|
},
|
|
23034
23176
|
14
|
|
@@ -23249,11 +23391,11 @@ function bigOp(expr, op, serialize) {
|
|
|
23249
23391
|
const b = fn.op1 ?? fn;
|
|
23250
23392
|
if (b.operator === "Block") body = serialize(b.op1 ?? b);
|
|
23251
23393
|
else body = serialize(b);
|
|
23252
|
-
} else if (fn
|
|
23394
|
+
} else if (fn) {
|
|
23253
23395
|
args = [];
|
|
23254
23396
|
body = serialize(fn);
|
|
23255
23397
|
} else {
|
|
23256
|
-
return
|
|
23398
|
+
return `${op}()`;
|
|
23257
23399
|
}
|
|
23258
23400
|
let result = op;
|
|
23259
23401
|
for (const limit2 of limits) {
|
|
@@ -25369,7 +25511,7 @@ var ARITHMETIC_LIBRARY = [
|
|
|
25369
25511
|
description: "Rounds a number up to the next largest integer",
|
|
25370
25512
|
complexity: 1250,
|
|
25371
25513
|
broadcastable: true,
|
|
25372
|
-
signature: "(
|
|
25514
|
+
signature: "(number) -> integer",
|
|
25373
25515
|
sgn: ([x]) => {
|
|
25374
25516
|
if (x.isLessEqual(-1)) return "negative";
|
|
25375
25517
|
if (x.isPositive) return "positive";
|
|
@@ -26411,38 +26553,29 @@ var ARITHMETIC_LIBRARY = [
|
|
|
26411
26553
|
signature: "((number+) -> number, (tuple<integer>|tuple<integer, integer>)+) -> number",
|
|
26412
26554
|
canonical: ([body, ...bounds], { scope }) => canonicalBigop("Product", body, bounds, scope),
|
|
26413
26555
|
evaluate: (ops, options) => {
|
|
26414
|
-
const fn = (acc, x) => {
|
|
26415
|
-
x = x.evaluate(options);
|
|
26416
|
-
return x.isNumberLiteral ? acc.mul(x.numericValue) : null;
|
|
26417
|
-
};
|
|
26418
26556
|
const result = run(
|
|
26419
26557
|
reduceBigOp(
|
|
26420
26558
|
ops[0],
|
|
26421
26559
|
ops.slice(1),
|
|
26422
|
-
|
|
26423
|
-
options.engine.
|
|
26560
|
+
(acc, x) => acc.mul(x.evaluate(options)),
|
|
26561
|
+
options.engine.One
|
|
26424
26562
|
),
|
|
26425
26563
|
options.engine._timeRemaining
|
|
26426
26564
|
);
|
|
26427
|
-
return options.engine.
|
|
26565
|
+
return result?.evaluate() ?? options.engine.NaN;
|
|
26428
26566
|
},
|
|
26429
26567
|
evaluateAsync: async (ops, options) => {
|
|
26430
|
-
const fn = (acc, x) => {
|
|
26431
|
-
x = x.evaluate(options);
|
|
26432
|
-
if (!x.isNumberLiteral) return null;
|
|
26433
|
-
return acc.mul(x.numericValue);
|
|
26434
|
-
};
|
|
26435
26568
|
const result = await runAsync(
|
|
26436
26569
|
reduceBigOp(
|
|
26437
26570
|
ops[0],
|
|
26438
26571
|
ops.slice(1),
|
|
26439
|
-
|
|
26440
|
-
options.engine.
|
|
26572
|
+
(acc, x) => acc.mul(x.evaluate(options)),
|
|
26573
|
+
options.engine.One
|
|
26441
26574
|
),
|
|
26442
26575
|
options.engine._timeRemaining,
|
|
26443
26576
|
options.signal
|
|
26444
26577
|
);
|
|
26445
|
-
return options.engine.
|
|
26578
|
+
return result?.evaluate() ?? options.engine.NaN;
|
|
26446
26579
|
}
|
|
26447
26580
|
},
|
|
26448
26581
|
Sum: {
|
|
@@ -26454,36 +26587,31 @@ var ARITHMETIC_LIBRARY = [
|
|
|
26454
26587
|
lazy: true,
|
|
26455
26588
|
signature: "((number) -> number, bounds:tuple+) -> number",
|
|
26456
26589
|
canonical: ([body, ...bounds], { scope }) => canonicalBigop("Sum", body, bounds, scope),
|
|
26457
|
-
evaluate: ([
|
|
26458
|
-
run(
|
|
26590
|
+
evaluate: ([body, ...indexes], { engine }) => {
|
|
26591
|
+
const result = run(
|
|
26459
26592
|
reduceBigOp(
|
|
26460
|
-
|
|
26593
|
+
body,
|
|
26461
26594
|
indexes,
|
|
26462
|
-
(acc, x) =>
|
|
26463
|
-
|
|
26464
|
-
return x.isNumberLiteral ? acc.add(x.numericValue) : null;
|
|
26465
|
-
},
|
|
26466
|
-
engine._numericValue(0)
|
|
26595
|
+
(acc, x) => acc.add(x.evaluate()),
|
|
26596
|
+
engine.Zero
|
|
26467
26597
|
),
|
|
26468
26598
|
engine._timeRemaining
|
|
26469
|
-
)
|
|
26470
|
-
|
|
26471
|
-
|
|
26472
|
-
|
|
26599
|
+
);
|
|
26600
|
+
return result?.evaluate() ?? engine.NaN;
|
|
26601
|
+
},
|
|
26602
|
+
evaluateAsync: async (xs, { engine, signal }) => {
|
|
26603
|
+
const result = await runAsync(
|
|
26473
26604
|
reduceBigOp(
|
|
26474
26605
|
xs[0],
|
|
26475
26606
|
xs.slice(1),
|
|
26476
|
-
(acc, x) =>
|
|
26477
|
-
|
|
26478
|
-
if (!x.isNumberLiteral) return null;
|
|
26479
|
-
return acc.add(x.numericValue);
|
|
26480
|
-
},
|
|
26481
|
-
engine._numericValue(0)
|
|
26607
|
+
(acc, x) => acc.add(x.evaluate()),
|
|
26608
|
+
engine.Zero
|
|
26482
26609
|
),
|
|
26483
26610
|
engine._timeRemaining,
|
|
26484
26611
|
signal
|
|
26485
|
-
)
|
|
26486
|
-
|
|
26612
|
+
);
|
|
26613
|
+
return result?.evaluate() ?? engine.NaN;
|
|
26614
|
+
}
|
|
26487
26615
|
}
|
|
26488
26616
|
}
|
|
26489
26617
|
];
|
|
@@ -26673,17 +26801,12 @@ var DERIVATIVES_TABLE = {
|
|
|
26673
26801
|
Ln: ["Divide", 1, "_"],
|
|
26674
26802
|
Log: ["Power", ["Multiply", "_", ["Ln", "10"]], -1],
|
|
26675
26803
|
Sqrt: ["Multiply", ["Power", "_", ["Negate", "Half"]], "Half"],
|
|
26676
|
-
|
|
26677
|
-
|
|
26678
|
-
|
|
26679
|
-
|
|
26680
|
-
|
|
26681
|
-
|
|
26682
|
-
["Greater", "_", 0],
|
|
26683
|
-
1,
|
|
26684
|
-
"True",
|
|
26685
|
-
["D", ["Abs", "_"], "_"]
|
|
26686
|
-
],
|
|
26804
|
+
// d/dx |x| = x/|x| = sign(x) for x ≠ 0 (undefined at x = 0)
|
|
26805
|
+
Abs: ["Sign", "_"],
|
|
26806
|
+
// Step functions: derivative is 0 almost everywhere (undefined at discontinuities)
|
|
26807
|
+
Floor: 0,
|
|
26808
|
+
Ceil: 0,
|
|
26809
|
+
Round: 0,
|
|
26687
26810
|
// https://proofwiki.org/wiki/Derivative_of_Error_Function
|
|
26688
26811
|
Erf: [
|
|
26689
26812
|
"Multiply",
|
|
@@ -26692,51 +26815,36 @@ var DERIVATIVES_TABLE = {
|
|
|
26692
26815
|
],
|
|
26693
26816
|
// https://proofwiki.org/wiki/Derivative_of_Gamma_Function
|
|
26694
26817
|
// https://en.wikipedia.org/wiki/Gamma_function
|
|
26818
|
+
// d/dx Γ(x) = Γ(x)·ψ(x) where ψ is the digamma function
|
|
26695
26819
|
Gamma: ["Multiply", ["Gamma", "_"], ["Digamma", "_"]],
|
|
26696
|
-
|
|
26697
|
-
"Add",
|
|
26698
|
-
["Multiply", ["Digamma", "_"], ["Gamma", "_"]],
|
|
26699
|
-
["Multiply", ["Power", "_", -1], ["Gamma", "_"]]
|
|
26700
|
-
],
|
|
26701
|
-
Zeta: ["Multiply", ["Multiply", -1, ["Zeta", "_"]], ["Digamma", "_"]],
|
|
26702
|
-
PolyGamma: [
|
|
26703
|
-
"Add",
|
|
26704
|
-
["Multiply", ["PolyGamma", "_"], ["Gamma", "_"]],
|
|
26705
|
-
["Multiply", ["Power", "_", -1], ["Gamma", "_"]]
|
|
26706
|
-
],
|
|
26707
|
-
Beta: [
|
|
26708
|
-
"Multiply",
|
|
26709
|
-
[
|
|
26710
|
-
"Add",
|
|
26711
|
-
["Multiply", ["Beta", "_"], ["Digamma", "_"]],
|
|
26712
|
-
["Multiply", ["Power", "_", -1], ["Beta", "_"]]
|
|
26713
|
-
],
|
|
26714
|
-
["Beta", "_"]
|
|
26715
|
-
],
|
|
26820
|
+
// d/dx erfc(x) = -d/dx erf(x) = -2/√π * e^(-x²)
|
|
26716
26821
|
Erfc: [
|
|
26717
|
-
"
|
|
26718
|
-
["Negate", ["
|
|
26719
|
-
["Exp", ["Negate", ["Power", "_", 2]]],
|
|
26720
|
-
["Power", "_", -1]
|
|
26822
|
+
"Negate",
|
|
26823
|
+
["Multiply", ["Divide", 2, ["Sqrt", "Pi"]], ["Exp", ["Negate", ["Square", "_"]]]]
|
|
26721
26824
|
],
|
|
26722
|
-
|
|
26825
|
+
// d/dx ln(Γ(x)) = ψ(x) (digamma function)
|
|
26826
|
+
LogGamma: ["Digamma", "_"],
|
|
26827
|
+
// Note: LambertW derivative d/dx W(x) = W(x)/(x·(1+W(x))) is mathematically correct
|
|
26828
|
+
// but omitted because LambertW lacks a type signature, causing type errors.
|
|
26829
|
+
//
|
|
26830
|
+
// d/dx S(x) = sin(πx²/2) where S is the Fresnel sine integral
|
|
26831
|
+
FresnelS: ["Sin", ["Multiply", ["Divide", "Pi", 2], ["Square", "_"]]],
|
|
26832
|
+
// d/dx C(x) = cos(πx²/2) where C is the Fresnel cosine integral
|
|
26833
|
+
FresnelC: ["Cos", ["Multiply", ["Divide", "Pi", 2], ["Square", "_"]]],
|
|
26834
|
+
// d/dx erfi(x) = (2/√π)·e^(x²) where erfi is the imaginary error function
|
|
26835
|
+
Erfi: [
|
|
26723
26836
|
"Multiply",
|
|
26724
|
-
["
|
|
26725
|
-
[
|
|
26726
|
-
|
|
26727
|
-
|
|
26728
|
-
|
|
26729
|
-
|
|
26730
|
-
|
|
26731
|
-
|
|
26732
|
-
|
|
26733
|
-
|
|
26734
|
-
|
|
26735
|
-
BesselI: ["Multiply", ["BesselI", "_"], ["BesselK", "_"]],
|
|
26736
|
-
BesselK: ["Multiply", ["BesselI", "_"], ["BesselK", "_"]],
|
|
26737
|
-
FresnelS: ["Multiply", ["FresnelS", "_"], ["FresnelC", "_"]],
|
|
26738
|
-
FresnelC: ["Multiply", ["FresnelS", "_"], ["FresnelC", "_"]],
|
|
26739
|
-
Erfi: ["Multiply", ["Erfi", "_"], ["Erf", "_"]]
|
|
26837
|
+
["Divide", 2, ["Sqrt", "Pi"]],
|
|
26838
|
+
["Exp", ["Square", "_"]]
|
|
26839
|
+
]
|
|
26840
|
+
// Note: Bessel functions (BesselJ, BesselY, BesselI, BesselK) and Airy functions
|
|
26841
|
+
// (AiryAi, AiryBi) have been omitted because their derivatives involve functions
|
|
26842
|
+
// of different orders or related derivative functions that are not in the standard
|
|
26843
|
+
// function set. For example, d/dx J_n(x) = (J_{n-1}(x) - J_{n+1}(x))/2.
|
|
26844
|
+
//
|
|
26845
|
+
// Similarly, Zeta, Digamma, PolyGamma, and Beta derivatives are omitted because
|
|
26846
|
+
// they either don't have simple closed forms or involve additional functions not
|
|
26847
|
+
// in the standard set (trigamma function, etc.).
|
|
26740
26848
|
};
|
|
26741
26849
|
function derivative(fn, order2) {
|
|
26742
26850
|
if (order2 === 0) return fn;
|
|
@@ -26789,6 +26897,15 @@ function differentiate(expr, v) {
|
|
|
26789
26897
|
if (terms.some((term) => term === void 0)) return void 0;
|
|
26790
26898
|
return simplifyDerivative(add3(...terms));
|
|
26791
26899
|
}
|
|
26900
|
+
if (expr.operator === "Root") {
|
|
26901
|
+
const [base, n] = expr.ops;
|
|
26902
|
+
if (!base.has(v)) return ce.Zero;
|
|
26903
|
+
const exponent = ce.One.div(n);
|
|
26904
|
+
const basePrime = differentiate(base, v) ?? ce._fn("D", [base, ce.symbol(v)]);
|
|
26905
|
+
const newExponent = exponent.sub(ce.One);
|
|
26906
|
+
const power = ce.function("Power", [base, newExponent], { structural: true });
|
|
26907
|
+
return simplifyDerivative(exponent.mul(power).mul(basePrime));
|
|
26908
|
+
}
|
|
26792
26909
|
if (expr.operator === "Power") {
|
|
26793
26910
|
const [base, exponent] = expr.ops;
|
|
26794
26911
|
const baseHasV = base.has(v);
|
|
@@ -26825,7 +26942,7 @@ function differentiate(expr, v) {
|
|
|
26825
26942
|
);
|
|
26826
26943
|
}
|
|
26827
26944
|
const h = DERIVATIVES_TABLE[expr.operator];
|
|
26828
|
-
if (
|
|
26945
|
+
if (h === void 0) {
|
|
26829
26946
|
if (expr.nops > 1) return void 0;
|
|
26830
26947
|
const fPrime = ce._fn("Derivative", [ce.symbol(expr.operator), ce.One]);
|
|
26831
26948
|
if (!fPrime.isValid) return void 0;
|
|
@@ -27406,6 +27523,14 @@ var UNIVARIATE_ROOTS = [
|
|
|
27406
27523
|
// Handle ax = 0
|
|
27407
27524
|
condition: filter
|
|
27408
27525
|
},
|
|
27526
|
+
// -ax + b = 0 => x = b/a
|
|
27527
|
+
// This handles cases where the coefficient is negative and represented as Negate(Multiply(...))
|
|
27528
|
+
{
|
|
27529
|
+
match: ["Add", ["Negate", ["Multiply", "_x", "__a"]], "__b"],
|
|
27530
|
+
replace: ["Divide", "__b", "__a"],
|
|
27531
|
+
useVariations: true,
|
|
27532
|
+
condition: filter
|
|
27533
|
+
},
|
|
27409
27534
|
// ax^n + b = 0
|
|
27410
27535
|
{
|
|
27411
27536
|
match: ["Add", ["Multiply", "_a", ["Power", "_x", "_n"]], "__b"],
|
|
@@ -27541,27 +27666,140 @@ var UNIVARIATE_ROOTS = [
|
|
|
27541
27666
|
replace: ["Divide", ["Negate", ["Add", "__b", "__c"], "__a"]],
|
|
27542
27667
|
condition: filter
|
|
27543
27668
|
},
|
|
27544
|
-
//
|
|
27545
|
-
//
|
|
27669
|
+
//
|
|
27670
|
+
// Square root equations: ax + b√x + c = 0
|
|
27671
|
+
// Using substitution u = √x, this becomes au² + bu + c = 0
|
|
27672
|
+
// Solving: u = (-b ± √(b² - 4ac)) / 2a
|
|
27673
|
+
// Then x = u² = ((-b ± √(b² - 4ac)) / 2a)²
|
|
27674
|
+
//
|
|
27675
|
+
// ax + b√x + c = 0 (plus root)
|
|
27676
|
+
{
|
|
27677
|
+
match: ["Add", ["Multiply", "_x", "__a"], ["Multiply", "__b", ["Sqrt", "_x"]], "___c"],
|
|
27678
|
+
replace: [
|
|
27679
|
+
"Power",
|
|
27680
|
+
[
|
|
27681
|
+
"Divide",
|
|
27682
|
+
["Add", ["Negate", "__b"], ["Sqrt", ["Subtract", ["Square", "__b"], ["Multiply", 4, "__a", "___c"]]]],
|
|
27683
|
+
["Multiply", 2, "__a"]
|
|
27684
|
+
],
|
|
27685
|
+
2
|
|
27686
|
+
],
|
|
27687
|
+
useVariations: true,
|
|
27688
|
+
condition: filter
|
|
27689
|
+
},
|
|
27690
|
+
// ax + b√x + c = 0 (minus root)
|
|
27691
|
+
{
|
|
27692
|
+
match: ["Add", ["Multiply", "_x", "__a"], ["Multiply", "__b", ["Sqrt", "_x"]], "___c"],
|
|
27693
|
+
replace: [
|
|
27694
|
+
"Power",
|
|
27695
|
+
[
|
|
27696
|
+
"Divide",
|
|
27697
|
+
["Subtract", ["Negate", "__b"], ["Sqrt", ["Subtract", ["Square", "__b"], ["Multiply", 4, "__a", "___c"]]]],
|
|
27698
|
+
["Multiply", 2, "__a"]
|
|
27699
|
+
],
|
|
27700
|
+
2
|
|
27701
|
+
],
|
|
27702
|
+
useVariations: true,
|
|
27703
|
+
condition: filter
|
|
27704
|
+
},
|
|
27705
|
+
// Handle negated coefficient: ax - b√x + c = 0
|
|
27706
|
+
// This handles the Negate(Multiply(...)) pattern
|
|
27707
|
+
{
|
|
27708
|
+
match: ["Add", ["Multiply", "_x", "__a"], ["Negate", ["Multiply", "__b", ["Sqrt", "_x"]]], "___c"],
|
|
27709
|
+
replace: [
|
|
27710
|
+
"Power",
|
|
27711
|
+
[
|
|
27712
|
+
"Divide",
|
|
27713
|
+
["Add", "__b", ["Sqrt", ["Add", ["Square", "__b"], ["Multiply", 4, "__a", "___c"]]]],
|
|
27714
|
+
["Multiply", 2, "__a"]
|
|
27715
|
+
],
|
|
27716
|
+
2
|
|
27717
|
+
],
|
|
27718
|
+
useVariations: true,
|
|
27719
|
+
condition: filter
|
|
27720
|
+
},
|
|
27721
|
+
// ax - b√x + c = 0 (minus root)
|
|
27722
|
+
{
|
|
27723
|
+
match: ["Add", ["Multiply", "_x", "__a"], ["Negate", ["Multiply", "__b", ["Sqrt", "_x"]]], "___c"],
|
|
27724
|
+
replace: [
|
|
27725
|
+
"Power",
|
|
27726
|
+
[
|
|
27727
|
+
"Divide",
|
|
27728
|
+
["Subtract", "__b", ["Sqrt", ["Add", ["Square", "__b"], ["Multiply", 4, "__a", "___c"]]]],
|
|
27729
|
+
["Multiply", 2, "__a"]
|
|
27730
|
+
],
|
|
27731
|
+
2
|
|
27732
|
+
],
|
|
27733
|
+
useVariations: true,
|
|
27734
|
+
condition: filter
|
|
27735
|
+
},
|
|
27736
|
+
//
|
|
27737
|
+
// Additional solve rules
|
|
27738
|
+
//
|
|
27739
|
+
// a√x + b = 0 => x = (b/a)² (only valid when -b/a ≥ 0)
|
|
27740
|
+
{
|
|
27741
|
+
match: ["Add", ["Multiply", "__a", ["Sqrt", "_x"]], "__b"],
|
|
27742
|
+
replace: ["Square", ["Divide", ["Negate", "__b"], "__a"]],
|
|
27743
|
+
useVariations: true,
|
|
27744
|
+
condition: (sub2) => {
|
|
27745
|
+
if (!filter(sub2)) return false;
|
|
27746
|
+
const a = sub2.__a;
|
|
27747
|
+
const b = sub2.__b;
|
|
27748
|
+
if (!a || !b) return false;
|
|
27749
|
+
const ratio = b.div(a);
|
|
27750
|
+
return ratio.isNonPositive ?? true;
|
|
27751
|
+
}
|
|
27752
|
+
},
|
|
27753
|
+
// a·ln(x) + b = 0 => x = e^(-b/a)
|
|
27546
27754
|
{
|
|
27547
|
-
match: "
|
|
27548
|
-
replace: "
|
|
27755
|
+
match: ["Add", ["Multiply", "__a", ["Ln", "_x"]], "__b"],
|
|
27756
|
+
replace: ["Exp", ["Divide", ["Negate", "__b"], "__a"]],
|
|
27549
27757
|
useVariations: true,
|
|
27550
27758
|
condition: filter
|
|
27551
27759
|
},
|
|
27552
|
-
//
|
|
27760
|
+
// ln(x) + b = 0 => x = e^(-b)
|
|
27553
27761
|
{
|
|
27554
|
-
match: "
|
|
27555
|
-
replace: "
|
|
27762
|
+
match: ["Add", ["Ln", "_x"], "__b"],
|
|
27763
|
+
replace: ["Exp", ["Negate", "__b"]],
|
|
27556
27764
|
useVariations: true,
|
|
27557
27765
|
condition: filter
|
|
27558
27766
|
}
|
|
27559
27767
|
];
|
|
27768
|
+
function clearDenominators(expr, variable) {
|
|
27769
|
+
if (expr.operator !== "Add") return expr;
|
|
27770
|
+
const ops = expr.ops;
|
|
27771
|
+
if (!ops || ops.length === 0) return expr;
|
|
27772
|
+
const denominators = ops.map((op) => op.denominator).filter((d) => !d.is(1));
|
|
27773
|
+
if (denominators.length === 0) return expr;
|
|
27774
|
+
const lcmFactors = [];
|
|
27775
|
+
for (const denom of denominators) {
|
|
27776
|
+
let isDuplicate = false;
|
|
27777
|
+
for (const existing of lcmFactors) {
|
|
27778
|
+
if (denom.isSame(existing)) {
|
|
27779
|
+
isDuplicate = true;
|
|
27780
|
+
break;
|
|
27781
|
+
}
|
|
27782
|
+
if (denom.symbol && existing.symbol && denom.symbol === existing.symbol) {
|
|
27783
|
+
isDuplicate = true;
|
|
27784
|
+
break;
|
|
27785
|
+
}
|
|
27786
|
+
}
|
|
27787
|
+
if (!isDuplicate) {
|
|
27788
|
+
lcmFactors.push(denom);
|
|
27789
|
+
}
|
|
27790
|
+
}
|
|
27791
|
+
let lcm4 = lcmFactors[0];
|
|
27792
|
+
for (let i = 1; i < lcmFactors.length; i++) {
|
|
27793
|
+
lcm4 = lcm4.mul(lcmFactors[i]);
|
|
27794
|
+
}
|
|
27795
|
+
return expr.mul(lcm4).simplify();
|
|
27796
|
+
}
|
|
27560
27797
|
function findUnivariateRoots(expr, x) {
|
|
27561
27798
|
const ce = expr.engine;
|
|
27562
27799
|
if (expr.operator === "Equal")
|
|
27563
27800
|
expr = expr.op1.expand().sub(expr.op2.expand()).simplify();
|
|
27564
27801
|
else expr = expr.expand().simplify();
|
|
27802
|
+
expr = clearDenominators(expr);
|
|
27565
27803
|
const rules = ce.getRuleSet("solve-univariate");
|
|
27566
27804
|
let exprs = [expr.subs({ [x]: "_x" }, { canonical: false })];
|
|
27567
27805
|
ce.pushScope();
|
|
@@ -28423,40 +28661,46 @@ var INTEGRATION_RULES = [
|
|
|
28423
28661
|
],
|
|
28424
28662
|
condition: filter2
|
|
28425
28663
|
},
|
|
28426
|
-
// \arctan(ax + b) ->
|
|
28664
|
+
// \arctan(ax + b) -> (1/a) * [(ax+b)*arctan(ax+b) - (1/2)*ln(1+(ax+b)^2)]
|
|
28427
28665
|
{
|
|
28428
28666
|
match: ["Arctan", ["Add", ["Multiply", "_a", "_x"], "__b"]],
|
|
28429
28667
|
replace: [
|
|
28430
28668
|
"Divide",
|
|
28431
28669
|
[
|
|
28432
|
-
"
|
|
28670
|
+
"Subtract",
|
|
28433
28671
|
[
|
|
28434
|
-
"
|
|
28435
|
-
["
|
|
28436
|
-
["
|
|
28672
|
+
"Multiply",
|
|
28673
|
+
["Add", ["Multiply", "_a", "_x"], "__b"],
|
|
28674
|
+
["Arctan", ["Add", ["Multiply", "_a", "_x"], "__b"]]
|
|
28675
|
+
],
|
|
28676
|
+
[
|
|
28677
|
+
"Multiply",
|
|
28678
|
+
["Rational", 1, 2],
|
|
28679
|
+
["Ln", ["Add", 1, ["Power", ["Add", ["Multiply", "_a", "_x"], "__b"], 2]]]
|
|
28437
28680
|
]
|
|
28438
28681
|
],
|
|
28439
28682
|
"_a"
|
|
28440
28683
|
],
|
|
28441
28684
|
condition: filter2
|
|
28442
28685
|
},
|
|
28443
|
-
// \arccos(ax + b) ->
|
|
28686
|
+
// \arccos(ax + b) -> (1/a) * [(ax+b)*arccos(ax+b) - sqrt(1-(ax+b)^2)]
|
|
28444
28687
|
{
|
|
28445
28688
|
match: ["Arccos", ["Add", ["Multiply", "_a", "_x"], "__b"]],
|
|
28446
28689
|
replace: [
|
|
28447
28690
|
"Divide",
|
|
28448
28691
|
[
|
|
28449
|
-
"
|
|
28692
|
+
"Subtract",
|
|
28450
28693
|
[
|
|
28451
|
-
"
|
|
28694
|
+
"Multiply",
|
|
28452
28695
|
["Add", ["Multiply", "_a", "_x"], "__b"],
|
|
28696
|
+
["Arccos", ["Add", ["Multiply", "_a", "_x"], "__b"]]
|
|
28697
|
+
],
|
|
28698
|
+
[
|
|
28699
|
+
"Sqrt",
|
|
28453
28700
|
[
|
|
28454
|
-
"
|
|
28455
|
-
|
|
28456
|
-
|
|
28457
|
-
["Power", ["Add", ["Multiply", "_a", "_x"], "__b"], 2],
|
|
28458
|
-
1
|
|
28459
|
-
]
|
|
28701
|
+
"Subtract",
|
|
28702
|
+
1,
|
|
28703
|
+
["Power", ["Add", ["Multiply", "_a", "_x"], "__b"], 2]
|
|
28460
28704
|
]
|
|
28461
28705
|
]
|
|
28462
28706
|
],
|
|
@@ -28464,23 +28708,24 @@ var INTEGRATION_RULES = [
|
|
|
28464
28708
|
],
|
|
28465
28709
|
condition: filter2
|
|
28466
28710
|
},
|
|
28467
|
-
// \arcsin(ax + b) ->
|
|
28711
|
+
// \arcsin(ax + b) -> (1/a) * [(ax+b)*arcsin(ax+b) + sqrt(1-(ax+b)^2)]
|
|
28468
28712
|
{
|
|
28469
28713
|
match: ["Arcsin", ["Add", ["Multiply", "_a", "_x"], "__b"]],
|
|
28470
28714
|
replace: [
|
|
28471
28715
|
"Divide",
|
|
28472
28716
|
[
|
|
28473
|
-
"
|
|
28717
|
+
"Add",
|
|
28474
28718
|
[
|
|
28475
|
-
"
|
|
28719
|
+
"Multiply",
|
|
28476
28720
|
["Add", ["Multiply", "_a", "_x"], "__b"],
|
|
28721
|
+
["Arcsin", ["Add", ["Multiply", "_a", "_x"], "__b"]]
|
|
28722
|
+
],
|
|
28723
|
+
[
|
|
28724
|
+
"Sqrt",
|
|
28477
28725
|
[
|
|
28478
|
-
"
|
|
28479
|
-
|
|
28480
|
-
|
|
28481
|
-
1,
|
|
28482
|
-
["Power", ["Add", ["Multiply", "_a", "_x"], "__b"], 2]
|
|
28483
|
-
]
|
|
28726
|
+
"Subtract",
|
|
28727
|
+
1,
|
|
28728
|
+
["Power", ["Add", ["Multiply", "_a", "_x"], "__b"], 2]
|
|
28484
28729
|
]
|
|
28485
28730
|
]
|
|
28486
28731
|
],
|
|
@@ -29294,6 +29539,8 @@ var CALCULUS_LIBRARY = [
|
|
|
29294
29539
|
}
|
|
29295
29540
|
f = f?.canonical;
|
|
29296
29541
|
if (f?.operator === "D") return f;
|
|
29542
|
+
if (f?.operator === "Apply" && f.op1?.operator === "Derivative")
|
|
29543
|
+
return f;
|
|
29297
29544
|
if (f && hasSymbolicTranscendental(f)) return f;
|
|
29298
29545
|
return f?.evaluate();
|
|
29299
29546
|
}
|
|
@@ -29420,7 +29667,7 @@ var CALCULUS_LIBRARY = [
|
|
|
29420
29667
|
complexity: 5e3,
|
|
29421
29668
|
broadcastable: false,
|
|
29422
29669
|
lazy: true,
|
|
29423
|
-
signature: "(index:symbol, lower:
|
|
29670
|
+
signature: "(index:symbol, lower:value, upper:value) -> tuple",
|
|
29424
29671
|
canonical: (ops, { engine }) => canonicalLimits(ops, { engine }) ?? null
|
|
29425
29672
|
}
|
|
29426
29673
|
},
|
|
@@ -30933,12 +31180,22 @@ var CORE_LIBRARY = [
|
|
|
30933
31180
|
}
|
|
30934
31181
|
if (op1.isIndexedCollection) return ce._fn("At", [op1, op2.canonical]);
|
|
30935
31182
|
if (op1.symbol) {
|
|
30936
|
-
const
|
|
30937
|
-
if (
|
|
31183
|
+
const sub3 = op2.string ?? op2.symbol ?? asSmallInteger(op2)?.toString();
|
|
31184
|
+
if (sub3) return ce.symbol(op1.symbol + "_" + sub3);
|
|
31185
|
+
if (op2.operator === "InvisibleOperator" && op2.ops) {
|
|
31186
|
+
const parts = op2.ops.map(
|
|
31187
|
+
(x) => x.symbol ?? asSmallInteger(x)?.toString()
|
|
31188
|
+
);
|
|
31189
|
+
if (parts.every((p) => p !== void 0 && p !== null)) {
|
|
31190
|
+
return ce.symbol(op1.symbol + "_" + parts.join(""));
|
|
31191
|
+
}
|
|
31192
|
+
}
|
|
30938
31193
|
}
|
|
30939
31194
|
if (op2.operator === "Sequence")
|
|
30940
31195
|
ce._fn("Subscript", [op1, ce._fn("List", op2.ops)]);
|
|
30941
|
-
|
|
31196
|
+
let sub2 = op2;
|
|
31197
|
+
if (op2.operator === "Delimiter" && op2.op1) sub2 = op2.op1.canonical;
|
|
31198
|
+
return ce._fn("Subscript", [op1, sub2]);
|
|
30942
31199
|
}
|
|
30943
31200
|
},
|
|
30944
31201
|
Symbol: {
|
|
@@ -32668,6 +32925,539 @@ function canonicalMatrix(ops, { engine: ce }) {
|
|
|
32668
32925
|
return ce._fn(operator2, [body]);
|
|
32669
32926
|
}
|
|
32670
32927
|
|
|
32928
|
+
// src/compute-engine/library/logic-utils.ts
|
|
32929
|
+
function evaluateAnd(args, { engine: ce }) {
|
|
32930
|
+
if (args.length === 0) return ce.True;
|
|
32931
|
+
const ops = [];
|
|
32932
|
+
for (const arg of args) {
|
|
32933
|
+
if (arg.symbol === "False") return ce.False;
|
|
32934
|
+
if (arg.symbol !== "True") {
|
|
32935
|
+
let duplicate = false;
|
|
32936
|
+
for (const x of ops) {
|
|
32937
|
+
if (x.isSame(arg)) {
|
|
32938
|
+
duplicate = true;
|
|
32939
|
+
} else if (arg.operator === "Not" && arg.op1.isSame(x) || x.operator === "Not" && x.op1.isSame(arg)) {
|
|
32940
|
+
return ce.False;
|
|
32941
|
+
}
|
|
32942
|
+
}
|
|
32943
|
+
if (!duplicate) ops.push(arg);
|
|
32944
|
+
}
|
|
32945
|
+
}
|
|
32946
|
+
if (ops.length === 0) return ce.True;
|
|
32947
|
+
if (ops.length === 1) return ops[0];
|
|
32948
|
+
return ce._fn("And", ops);
|
|
32949
|
+
}
|
|
32950
|
+
function evaluateOr(args, { engine: ce }) {
|
|
32951
|
+
if (args.length === 0) return ce.True;
|
|
32952
|
+
const ops = [];
|
|
32953
|
+
for (const arg of args) {
|
|
32954
|
+
if (arg.symbol === "True") return ce.True;
|
|
32955
|
+
if (arg.symbol !== "False") {
|
|
32956
|
+
let duplicate = false;
|
|
32957
|
+
for (const x of ops) {
|
|
32958
|
+
if (x.isSame(arg)) {
|
|
32959
|
+
duplicate = true;
|
|
32960
|
+
} else if (arg.operator === "Not" && arg.op1.isSame(x) || x.operator === "Not" && x.op1.isSame(arg)) {
|
|
32961
|
+
return ce.True;
|
|
32962
|
+
}
|
|
32963
|
+
}
|
|
32964
|
+
if (!duplicate) ops.push(arg);
|
|
32965
|
+
}
|
|
32966
|
+
}
|
|
32967
|
+
if (ops.length === 0) return ce.False;
|
|
32968
|
+
if (ops.length === 1) return ops[0];
|
|
32969
|
+
return ce._fn("Or", ops);
|
|
32970
|
+
}
|
|
32971
|
+
function evaluateNot(args, { engine: ce }) {
|
|
32972
|
+
const op1 = args[0]?.symbol;
|
|
32973
|
+
if (op1 === "True") return ce.False;
|
|
32974
|
+
if (op1 === "False") return ce.True;
|
|
32975
|
+
return void 0;
|
|
32976
|
+
}
|
|
32977
|
+
function evaluateEquivalent(args, { engine: ce }) {
|
|
32978
|
+
const lhs = args[0].symbol;
|
|
32979
|
+
const rhs = args[1].symbol;
|
|
32980
|
+
if (lhs === "True" && rhs === "True" || lhs === "False" && rhs === "False")
|
|
32981
|
+
return ce.True;
|
|
32982
|
+
if (lhs === "True" && rhs === "False" || lhs === "False" && rhs === "True")
|
|
32983
|
+
return ce.False;
|
|
32984
|
+
return void 0;
|
|
32985
|
+
}
|
|
32986
|
+
function evaluateImplies(args, { engine: ce }) {
|
|
32987
|
+
const lhs = args[0].symbol;
|
|
32988
|
+
const rhs = args[1].symbol;
|
|
32989
|
+
if (lhs === "True" && rhs === "True" || lhs === "False" && rhs === "False" || lhs === "False" && rhs === "True")
|
|
32990
|
+
return ce.True;
|
|
32991
|
+
if (lhs === "True" && rhs === "False") return ce.False;
|
|
32992
|
+
return void 0;
|
|
32993
|
+
}
|
|
32994
|
+
function evaluateXor(args, { engine: ce }) {
|
|
32995
|
+
if (args.length === 0) return ce.False;
|
|
32996
|
+
let trueCount = 0;
|
|
32997
|
+
const unknowns = [];
|
|
32998
|
+
for (const arg of args) {
|
|
32999
|
+
if (arg.symbol === "True") {
|
|
33000
|
+
trueCount++;
|
|
33001
|
+
} else if (arg.symbol === "False") {
|
|
33002
|
+
} else {
|
|
33003
|
+
unknowns.push(arg);
|
|
33004
|
+
}
|
|
33005
|
+
}
|
|
33006
|
+
if (unknowns.length === 0) {
|
|
33007
|
+
return trueCount % 2 === 1 ? ce.True : ce.False;
|
|
33008
|
+
}
|
|
33009
|
+
if (unknowns.length === 1 && trueCount % 2 === 1) {
|
|
33010
|
+
return ce._fn("Not", [unknowns[0]]);
|
|
33011
|
+
}
|
|
33012
|
+
if (unknowns.length === 1 && trueCount % 2 === 0) {
|
|
33013
|
+
return unknowns[0];
|
|
33014
|
+
}
|
|
33015
|
+
return void 0;
|
|
33016
|
+
}
|
|
33017
|
+
function evaluateNand(args, { engine: ce }) {
|
|
33018
|
+
if (args.length === 0) return ce.False;
|
|
33019
|
+
for (const arg of args) {
|
|
33020
|
+
if (arg.symbol === "False") return ce.True;
|
|
33021
|
+
}
|
|
33022
|
+
let allTrue = true;
|
|
33023
|
+
for (const arg of args) {
|
|
33024
|
+
if (arg.symbol !== "True") {
|
|
33025
|
+
allTrue = false;
|
|
33026
|
+
break;
|
|
33027
|
+
}
|
|
33028
|
+
}
|
|
33029
|
+
if (allTrue) return ce.False;
|
|
33030
|
+
return void 0;
|
|
33031
|
+
}
|
|
33032
|
+
function evaluateNor(args, { engine: ce }) {
|
|
33033
|
+
if (args.length === 0) return ce.True;
|
|
33034
|
+
for (const arg of args) {
|
|
33035
|
+
if (arg.symbol === "True") return ce.False;
|
|
33036
|
+
}
|
|
33037
|
+
let allFalse = true;
|
|
33038
|
+
for (const arg of args) {
|
|
33039
|
+
if (arg.symbol !== "False") {
|
|
33040
|
+
allFalse = false;
|
|
33041
|
+
break;
|
|
33042
|
+
}
|
|
33043
|
+
}
|
|
33044
|
+
if (allFalse) return ce.True;
|
|
33045
|
+
return void 0;
|
|
33046
|
+
}
|
|
33047
|
+
function toNNF(expr, ce) {
|
|
33048
|
+
const op = expr.operator;
|
|
33049
|
+
if (!op) return expr;
|
|
33050
|
+
if (expr.symbol === "True" || expr.symbol === "False") return expr;
|
|
33051
|
+
if (op === "Not") {
|
|
33052
|
+
const inner = expr.op1;
|
|
33053
|
+
if (!inner) return expr;
|
|
33054
|
+
const innerOp = inner.operator;
|
|
33055
|
+
if (innerOp === "Not") {
|
|
33056
|
+
return toNNF(inner.op1, ce);
|
|
33057
|
+
}
|
|
33058
|
+
if (innerOp === "And") {
|
|
33059
|
+
const negatedOps = inner.ops.map((x) => toNNF(ce._fn("Not", [x]), ce));
|
|
33060
|
+
return ce._fn("Or", negatedOps);
|
|
33061
|
+
}
|
|
33062
|
+
if (innerOp === "Or") {
|
|
33063
|
+
const negatedOps = inner.ops.map((x) => toNNF(ce._fn("Not", [x]), ce));
|
|
33064
|
+
return ce._fn("And", negatedOps);
|
|
33065
|
+
}
|
|
33066
|
+
if (inner.symbol === "True") return ce.False;
|
|
33067
|
+
if (inner.symbol === "False") return ce.True;
|
|
33068
|
+
if (innerOp === "Implies") {
|
|
33069
|
+
const a = inner.op1;
|
|
33070
|
+
const b = inner.op2;
|
|
33071
|
+
return toNNF(ce._fn("And", [a, ce._fn("Not", [b])]), ce);
|
|
33072
|
+
}
|
|
33073
|
+
if (innerOp === "Equivalent") {
|
|
33074
|
+
const a = inner.op1;
|
|
33075
|
+
const b = inner.op2;
|
|
33076
|
+
return toNNF(
|
|
33077
|
+
ce._fn("Or", [
|
|
33078
|
+
ce._fn("And", [a, ce._fn("Not", [b])]),
|
|
33079
|
+
ce._fn("And", [ce._fn("Not", [a]), b])
|
|
33080
|
+
]),
|
|
33081
|
+
ce
|
|
33082
|
+
);
|
|
33083
|
+
}
|
|
33084
|
+
if (innerOp === "Xor") {
|
|
33085
|
+
const ops = inner.ops;
|
|
33086
|
+
if (ops.length === 2) {
|
|
33087
|
+
const a = ops[0];
|
|
33088
|
+
const b = ops[1];
|
|
33089
|
+
return toNNF(
|
|
33090
|
+
ce._fn("Or", [
|
|
33091
|
+
ce._fn("And", [a, b]),
|
|
33092
|
+
ce._fn("And", [ce._fn("Not", [a]), ce._fn("Not", [b])])
|
|
33093
|
+
]),
|
|
33094
|
+
ce
|
|
33095
|
+
);
|
|
33096
|
+
}
|
|
33097
|
+
return toNNF(ce._fn("Not", [toNNF(inner, ce)]), ce);
|
|
33098
|
+
}
|
|
33099
|
+
if (innerOp === "Nand") {
|
|
33100
|
+
return toNNF(ce._fn("And", inner.ops), ce);
|
|
33101
|
+
}
|
|
33102
|
+
if (innerOp === "Nor") {
|
|
33103
|
+
return toNNF(ce._fn("Or", inner.ops), ce);
|
|
33104
|
+
}
|
|
33105
|
+
return expr;
|
|
33106
|
+
}
|
|
33107
|
+
if (op === "Implies") {
|
|
33108
|
+
const a = expr.op1;
|
|
33109
|
+
const b = expr.op2;
|
|
33110
|
+
return toNNF(ce._fn("Or", [ce._fn("Not", [a]), b]), ce);
|
|
33111
|
+
}
|
|
33112
|
+
if (op === "Equivalent") {
|
|
33113
|
+
const a = expr.op1;
|
|
33114
|
+
const b = expr.op2;
|
|
33115
|
+
return toNNF(
|
|
33116
|
+
ce._fn("And", [
|
|
33117
|
+
ce._fn("Or", [ce._fn("Not", [a]), b]),
|
|
33118
|
+
ce._fn("Or", [ce._fn("Not", [b]), a])
|
|
33119
|
+
]),
|
|
33120
|
+
ce
|
|
33121
|
+
);
|
|
33122
|
+
}
|
|
33123
|
+
if (op === "Xor") {
|
|
33124
|
+
const ops = expr.ops;
|
|
33125
|
+
if (ops.length === 2) {
|
|
33126
|
+
const a = ops[0];
|
|
33127
|
+
const b = ops[1];
|
|
33128
|
+
return toNNF(
|
|
33129
|
+
ce._fn("And", [
|
|
33130
|
+
ce._fn("Or", [a, b]),
|
|
33131
|
+
ce._fn("Or", [ce._fn("Not", [a]), ce._fn("Not", [b])])
|
|
33132
|
+
]),
|
|
33133
|
+
ce
|
|
33134
|
+
);
|
|
33135
|
+
}
|
|
33136
|
+
if (ops.length > 2) {
|
|
33137
|
+
const first = ce._fn("Xor", [ops[0], ops[1]]);
|
|
33138
|
+
const rest = ops.slice(2);
|
|
33139
|
+
return toNNF(ce._fn("Xor", [first, ...rest]), ce);
|
|
33140
|
+
}
|
|
33141
|
+
if (ops.length === 1) return toNNF(ops[0], ce);
|
|
33142
|
+
return ce.False;
|
|
33143
|
+
}
|
|
33144
|
+
if (op === "Nand") {
|
|
33145
|
+
const ops = expr.ops;
|
|
33146
|
+
return toNNF(ce._fn("Not", [ce._fn("And", ops)]), ce);
|
|
33147
|
+
}
|
|
33148
|
+
if (op === "Nor") {
|
|
33149
|
+
const ops = expr.ops;
|
|
33150
|
+
return toNNF(ce._fn("Not", [ce._fn("Or", ops)]), ce);
|
|
33151
|
+
}
|
|
33152
|
+
if (op === "And" || op === "Or") {
|
|
33153
|
+
const nnfOps = expr.ops.map((x) => toNNF(x, ce));
|
|
33154
|
+
return ce._fn(op, nnfOps);
|
|
33155
|
+
}
|
|
33156
|
+
return expr;
|
|
33157
|
+
}
|
|
33158
|
+
function distributeOrOverAnd(expr, ce) {
|
|
33159
|
+
const op = expr.operator;
|
|
33160
|
+
if (op !== "Or") {
|
|
33161
|
+
if (op === "And") {
|
|
33162
|
+
return ce._fn(
|
|
33163
|
+
"And",
|
|
33164
|
+
expr.ops.map((x) => distributeOrOverAnd(x, ce))
|
|
33165
|
+
);
|
|
33166
|
+
}
|
|
33167
|
+
return expr;
|
|
33168
|
+
}
|
|
33169
|
+
const orOperands = [];
|
|
33170
|
+
for (const operand2 of expr.ops) {
|
|
33171
|
+
if (operand2.operator === "Or") {
|
|
33172
|
+
orOperands.push(...operand2.ops);
|
|
33173
|
+
} else {
|
|
33174
|
+
orOperands.push(operand2);
|
|
33175
|
+
}
|
|
33176
|
+
}
|
|
33177
|
+
const andIndex = orOperands.findIndex((x) => x.operator === "And");
|
|
33178
|
+
if (andIndex === -1) {
|
|
33179
|
+
return expr;
|
|
33180
|
+
}
|
|
33181
|
+
const andExpr = orOperands[andIndex];
|
|
33182
|
+
const otherOperands = [
|
|
33183
|
+
...orOperands.slice(0, andIndex),
|
|
33184
|
+
...orOperands.slice(andIndex + 1)
|
|
33185
|
+
];
|
|
33186
|
+
const otherOr = otherOperands.length === 1 ? otherOperands[0] : ce._fn("Or", otherOperands);
|
|
33187
|
+
const distributed = ce._fn(
|
|
33188
|
+
"And",
|
|
33189
|
+
andExpr.ops.map((x) => ce._fn("Or", [x, otherOr]))
|
|
33190
|
+
);
|
|
33191
|
+
return distributeOrOverAnd(distributed, ce);
|
|
33192
|
+
}
|
|
33193
|
+
function toCNF(expr, ce) {
|
|
33194
|
+
const nnf = toNNF(expr, ce);
|
|
33195
|
+
const cnf = distributeOrOverAnd(nnf, ce);
|
|
33196
|
+
return cnf.simplify();
|
|
33197
|
+
}
|
|
33198
|
+
function distributeAndOverOr(expr, ce) {
|
|
33199
|
+
const op = expr.operator;
|
|
33200
|
+
if (op !== "And") {
|
|
33201
|
+
if (op === "Or") {
|
|
33202
|
+
return ce._fn(
|
|
33203
|
+
"Or",
|
|
33204
|
+
expr.ops.map((x) => distributeAndOverOr(x, ce))
|
|
33205
|
+
);
|
|
33206
|
+
}
|
|
33207
|
+
return expr;
|
|
33208
|
+
}
|
|
33209
|
+
const andOperands = [];
|
|
33210
|
+
for (const operand2 of expr.ops) {
|
|
33211
|
+
if (operand2.operator === "And") {
|
|
33212
|
+
andOperands.push(...operand2.ops);
|
|
33213
|
+
} else {
|
|
33214
|
+
andOperands.push(operand2);
|
|
33215
|
+
}
|
|
33216
|
+
}
|
|
33217
|
+
const orIndex = andOperands.findIndex((x) => x.operator === "Or");
|
|
33218
|
+
if (orIndex === -1) {
|
|
33219
|
+
return expr;
|
|
33220
|
+
}
|
|
33221
|
+
const orExpr = andOperands[orIndex];
|
|
33222
|
+
const otherOperands = [
|
|
33223
|
+
...andOperands.slice(0, orIndex),
|
|
33224
|
+
...andOperands.slice(orIndex + 1)
|
|
33225
|
+
];
|
|
33226
|
+
const otherAnd = otherOperands.length === 1 ? otherOperands[0] : ce._fn("And", otherOperands);
|
|
33227
|
+
const distributed = ce._fn(
|
|
33228
|
+
"Or",
|
|
33229
|
+
orExpr.ops.map((x) => ce._fn("And", [x, otherAnd]))
|
|
33230
|
+
);
|
|
33231
|
+
return distributeAndOverOr(distributed, ce);
|
|
33232
|
+
}
|
|
33233
|
+
function toDNF(expr, ce) {
|
|
33234
|
+
const nnf = toNNF(expr, ce);
|
|
33235
|
+
const dnf = distributeAndOverOr(nnf, ce);
|
|
33236
|
+
return dnf.simplify();
|
|
33237
|
+
}
|
|
33238
|
+
function extractVariables(expr) {
|
|
33239
|
+
const variables = /* @__PURE__ */ new Set();
|
|
33240
|
+
function visit(e) {
|
|
33241
|
+
if (e.symbol === "True" || e.symbol === "False") return;
|
|
33242
|
+
if (e.symbol && e.operator === "Symbol") {
|
|
33243
|
+
variables.add(e.symbol);
|
|
33244
|
+
return;
|
|
33245
|
+
}
|
|
33246
|
+
if (e.ops) {
|
|
33247
|
+
for (const op of e.ops) {
|
|
33248
|
+
visit(op);
|
|
33249
|
+
}
|
|
33250
|
+
}
|
|
33251
|
+
}
|
|
33252
|
+
visit(expr);
|
|
33253
|
+
return Array.from(variables).sort();
|
|
33254
|
+
}
|
|
33255
|
+
function evaluateWithAssignment(expr, assignment, ce) {
|
|
33256
|
+
const subs = {};
|
|
33257
|
+
for (const [variable, value] of Object.entries(assignment)) {
|
|
33258
|
+
subs[variable] = value ? ce.True : ce.False;
|
|
33259
|
+
}
|
|
33260
|
+
const substituted = expr.subs(subs).canonical;
|
|
33261
|
+
return substituted.evaluate();
|
|
33262
|
+
}
|
|
33263
|
+
function* generateAssignments(variables) {
|
|
33264
|
+
const n = variables.length;
|
|
33265
|
+
const total = 1 << n;
|
|
33266
|
+
for (let i = 0; i < total; i++) {
|
|
33267
|
+
const assignment = {};
|
|
33268
|
+
for (let j = 0; j < n; j++) {
|
|
33269
|
+
assignment[variables[j]] = (i >> n - 1 - j & 1) === 1;
|
|
33270
|
+
}
|
|
33271
|
+
yield assignment;
|
|
33272
|
+
}
|
|
33273
|
+
}
|
|
33274
|
+
|
|
33275
|
+
// src/compute-engine/library/logic-analysis.ts
|
|
33276
|
+
function extractFiniteDomain(condition, ce) {
|
|
33277
|
+
if (condition.operator !== "Element") return null;
|
|
33278
|
+
const variable = condition.op1?.symbol;
|
|
33279
|
+
if (!variable) return null;
|
|
33280
|
+
const domain = condition.op2;
|
|
33281
|
+
if (!domain) return null;
|
|
33282
|
+
if (domain.operator === "Set" || domain.operator === "List") {
|
|
33283
|
+
const values = domain.ops;
|
|
33284
|
+
if (values && values.length <= 1e3) {
|
|
33285
|
+
return { variable, values: [...values] };
|
|
33286
|
+
}
|
|
33287
|
+
return null;
|
|
33288
|
+
}
|
|
33289
|
+
if (domain.operator === "Range") {
|
|
33290
|
+
const start = asSmallInteger(domain.op1);
|
|
33291
|
+
const end = asSmallInteger(domain.op2);
|
|
33292
|
+
const step = domain.ops && domain.ops.length >= 3 ? asSmallInteger(domain.op3) : 1;
|
|
33293
|
+
if (start !== null && end !== null && step !== null && step !== 0) {
|
|
33294
|
+
const count = Math.floor((end - start) / step) + 1;
|
|
33295
|
+
if (count > 0 && count <= 1e3) {
|
|
33296
|
+
const values = [];
|
|
33297
|
+
for (let i = start; step > 0 ? i <= end : i >= end; i += step) {
|
|
33298
|
+
values.push(ce.number(i));
|
|
33299
|
+
}
|
|
33300
|
+
return { variable, values };
|
|
33301
|
+
}
|
|
33302
|
+
}
|
|
33303
|
+
return null;
|
|
33304
|
+
}
|
|
33305
|
+
if (domain.operator === "Interval") {
|
|
33306
|
+
const start = asSmallInteger(domain.op1);
|
|
33307
|
+
const end = asSmallInteger(domain.op2);
|
|
33308
|
+
if (start !== null && end !== null) {
|
|
33309
|
+
const count = end - start + 1;
|
|
33310
|
+
if (count > 0 && count <= 1e3) {
|
|
33311
|
+
const values = [];
|
|
33312
|
+
for (let i = start; i <= end; i++) {
|
|
33313
|
+
values.push(ce.number(i));
|
|
33314
|
+
}
|
|
33315
|
+
return { variable, values };
|
|
33316
|
+
}
|
|
33317
|
+
}
|
|
33318
|
+
return null;
|
|
33319
|
+
}
|
|
33320
|
+
return null;
|
|
33321
|
+
}
|
|
33322
|
+
function bodyContainsVariable(expr, variable) {
|
|
33323
|
+
if (expr.symbol === variable) return true;
|
|
33324
|
+
if (expr.ops) {
|
|
33325
|
+
for (const op of expr.ops) {
|
|
33326
|
+
if (bodyContainsVariable(op, variable)) return true;
|
|
33327
|
+
}
|
|
33328
|
+
}
|
|
33329
|
+
return false;
|
|
33330
|
+
}
|
|
33331
|
+
function collectNestedDomains(body, ce) {
|
|
33332
|
+
const canonicalBody = body.canonical;
|
|
33333
|
+
const op = canonicalBody.operator;
|
|
33334
|
+
if (op !== "ForAll" && op !== "Exists") return [];
|
|
33335
|
+
const condition = canonicalBody.op1;
|
|
33336
|
+
const innerBody = canonicalBody.op2;
|
|
33337
|
+
if (!condition || !innerBody) return [];
|
|
33338
|
+
const domain = extractFiniteDomain(condition, ce);
|
|
33339
|
+
if (!domain) return [];
|
|
33340
|
+
const innerDomains = collectNestedDomains(innerBody, ce);
|
|
33341
|
+
return [{ variable: domain.variable, values: domain.values }, ...innerDomains];
|
|
33342
|
+
}
|
|
33343
|
+
function getInnermostBody(body) {
|
|
33344
|
+
const canonicalBody = body.canonical;
|
|
33345
|
+
const op = canonicalBody.operator;
|
|
33346
|
+
if (op === "ForAll" || op === "Exists") {
|
|
33347
|
+
const innerBody = canonicalBody.op2;
|
|
33348
|
+
if (innerBody) return getInnermostBody(innerBody);
|
|
33349
|
+
}
|
|
33350
|
+
return canonicalBody;
|
|
33351
|
+
}
|
|
33352
|
+
function evaluateForAllCartesian(domains, body, ce) {
|
|
33353
|
+
const indices = domains.map(() => 0);
|
|
33354
|
+
const lengths = domains.map((d) => d.values.length);
|
|
33355
|
+
if (lengths.some((l) => l === 0)) return ce.True;
|
|
33356
|
+
while (true) {
|
|
33357
|
+
const subs = {};
|
|
33358
|
+
for (let i = 0; i < domains.length; i++) {
|
|
33359
|
+
subs[domains[i].variable] = domains[i].values[indices[i]];
|
|
33360
|
+
}
|
|
33361
|
+
const substituted = body.subs(subs).canonical;
|
|
33362
|
+
const result = substituted.evaluate();
|
|
33363
|
+
if (result.symbol === "False") {
|
|
33364
|
+
return ce.False;
|
|
33365
|
+
}
|
|
33366
|
+
if (result.symbol !== "True") {
|
|
33367
|
+
return void 0;
|
|
33368
|
+
}
|
|
33369
|
+
let dim = domains.length - 1;
|
|
33370
|
+
while (dim >= 0) {
|
|
33371
|
+
indices[dim]++;
|
|
33372
|
+
if (indices[dim] < lengths[dim]) break;
|
|
33373
|
+
indices[dim] = 0;
|
|
33374
|
+
dim--;
|
|
33375
|
+
}
|
|
33376
|
+
if (dim < 0) break;
|
|
33377
|
+
}
|
|
33378
|
+
return ce.True;
|
|
33379
|
+
}
|
|
33380
|
+
function evaluateExistsCartesian(domains, body, ce) {
|
|
33381
|
+
const indices = domains.map(() => 0);
|
|
33382
|
+
const lengths = domains.map((d) => d.values.length);
|
|
33383
|
+
if (lengths.some((l) => l === 0)) return ce.False;
|
|
33384
|
+
while (true) {
|
|
33385
|
+
const subs = {};
|
|
33386
|
+
for (let i = 0; i < domains.length; i++) {
|
|
33387
|
+
subs[domains[i].variable] = domains[i].values[indices[i]];
|
|
33388
|
+
}
|
|
33389
|
+
const substituted = body.subs(subs).canonical;
|
|
33390
|
+
const result = substituted.evaluate();
|
|
33391
|
+
if (result.symbol === "True") {
|
|
33392
|
+
return ce.True;
|
|
33393
|
+
}
|
|
33394
|
+
let dim = domains.length - 1;
|
|
33395
|
+
while (dim >= 0) {
|
|
33396
|
+
indices[dim]++;
|
|
33397
|
+
if (indices[dim] < lengths[dim]) break;
|
|
33398
|
+
indices[dim] = 0;
|
|
33399
|
+
dim--;
|
|
33400
|
+
}
|
|
33401
|
+
if (dim < 0) break;
|
|
33402
|
+
}
|
|
33403
|
+
return ce.False;
|
|
33404
|
+
}
|
|
33405
|
+
function isSatisfiable(expr, ce) {
|
|
33406
|
+
const variables = extractVariables(expr);
|
|
33407
|
+
if (variables.length === 0) {
|
|
33408
|
+
const result = expr.evaluate();
|
|
33409
|
+
return result.symbol === "True" ? ce.True : ce.False;
|
|
33410
|
+
}
|
|
33411
|
+
if (variables.length > 20) {
|
|
33412
|
+
return ce._fn("IsSatisfiable", [expr]);
|
|
33413
|
+
}
|
|
33414
|
+
for (const assignment of generateAssignments(variables)) {
|
|
33415
|
+
const result = evaluateWithAssignment(expr, assignment, ce);
|
|
33416
|
+
if (result.symbol === "True") {
|
|
33417
|
+
return ce.True;
|
|
33418
|
+
}
|
|
33419
|
+
}
|
|
33420
|
+
return ce.False;
|
|
33421
|
+
}
|
|
33422
|
+
function isTautology(expr, ce) {
|
|
33423
|
+
const variables = extractVariables(expr);
|
|
33424
|
+
if (variables.length === 0) {
|
|
33425
|
+
const result = expr.evaluate();
|
|
33426
|
+
return result.symbol === "True" ? ce.True : ce.False;
|
|
33427
|
+
}
|
|
33428
|
+
if (variables.length > 20) {
|
|
33429
|
+
return ce._fn("IsTautology", [expr]);
|
|
33430
|
+
}
|
|
33431
|
+
for (const assignment of generateAssignments(variables)) {
|
|
33432
|
+
const result = evaluateWithAssignment(expr, assignment, ce);
|
|
33433
|
+
if (result.symbol !== "True") {
|
|
33434
|
+
return ce.False;
|
|
33435
|
+
}
|
|
33436
|
+
}
|
|
33437
|
+
return ce.True;
|
|
33438
|
+
}
|
|
33439
|
+
function generateTruthTable(expr, ce) {
|
|
33440
|
+
const variables = extractVariables(expr);
|
|
33441
|
+
if (variables.length > 10) {
|
|
33442
|
+
return ce._fn("TruthTable", [expr]);
|
|
33443
|
+
}
|
|
33444
|
+
const rows = [];
|
|
33445
|
+
const header = ce._fn("List", [
|
|
33446
|
+
...variables.map((v) => ce.string(v)),
|
|
33447
|
+
ce.string("Result")
|
|
33448
|
+
]);
|
|
33449
|
+
rows.push(header);
|
|
33450
|
+
for (const assignment of generateAssignments(variables)) {
|
|
33451
|
+
const result = evaluateWithAssignment(expr, assignment, ce);
|
|
33452
|
+
const row = ce._fn("List", [
|
|
33453
|
+
...variables.map((v) => assignment[v] ? ce.True : ce.False),
|
|
33454
|
+
result
|
|
33455
|
+
]);
|
|
33456
|
+
rows.push(row);
|
|
33457
|
+
}
|
|
33458
|
+
return ce._fn("List", rows);
|
|
33459
|
+
}
|
|
33460
|
+
|
|
32671
33461
|
// src/compute-engine/library/logic.ts
|
|
32672
33462
|
var LOGIC_LIBRARY = {
|
|
32673
33463
|
True: {
|
|
@@ -32738,11 +33528,96 @@ var LOGIC_LIBRARY = {
|
|
|
32738
33528
|
signature: "(boolean, boolean) -> boolean",
|
|
32739
33529
|
evaluate: evaluateImplies
|
|
32740
33530
|
},
|
|
32741
|
-
|
|
32742
|
-
|
|
32743
|
-
|
|
32744
|
-
|
|
32745
|
-
|
|
33531
|
+
Xor: {
|
|
33532
|
+
description: "Exclusive or: true when an odd number of operands are true",
|
|
33533
|
+
wikidata: "Q498186",
|
|
33534
|
+
broadcastable: true,
|
|
33535
|
+
associative: true,
|
|
33536
|
+
commutative: true,
|
|
33537
|
+
complexity: 10200,
|
|
33538
|
+
signature: "(boolean+) -> boolean",
|
|
33539
|
+
evaluate: evaluateXor
|
|
33540
|
+
},
|
|
33541
|
+
Nand: {
|
|
33542
|
+
description: "Not-and: negation of conjunction",
|
|
33543
|
+
wikidata: "Q189550",
|
|
33544
|
+
broadcastable: true,
|
|
33545
|
+
commutative: true,
|
|
33546
|
+
complexity: 10200,
|
|
33547
|
+
signature: "(boolean+) -> boolean",
|
|
33548
|
+
evaluate: evaluateNand
|
|
33549
|
+
},
|
|
33550
|
+
Nor: {
|
|
33551
|
+
description: "Not-or: negation of disjunction",
|
|
33552
|
+
wikidata: "Q189561",
|
|
33553
|
+
broadcastable: true,
|
|
33554
|
+
commutative: true,
|
|
33555
|
+
complexity: 10200,
|
|
33556
|
+
signature: "(boolean+) -> boolean",
|
|
33557
|
+
evaluate: evaluateNor
|
|
33558
|
+
},
|
|
33559
|
+
// Quantifiers return boolean values (they are propositions)
|
|
33560
|
+
// They support evaluation over finite domains (e.g., ForAll with Element condition)
|
|
33561
|
+
// The first argument can be:
|
|
33562
|
+
// - a symbol (e.g., "x") for symbolic quantification
|
|
33563
|
+
// - an Element expression (e.g., ["Element", "x", ["Set", 1, 2, 3]]) for finite domain evaluation
|
|
33564
|
+
Exists: {
|
|
33565
|
+
signature: "(value, boolean) -> boolean",
|
|
33566
|
+
lazy: true,
|
|
33567
|
+
scoped: true,
|
|
33568
|
+
evaluate: evaluateExists
|
|
33569
|
+
},
|
|
33570
|
+
NotExists: {
|
|
33571
|
+
signature: "(value, boolean) -> boolean",
|
|
33572
|
+
lazy: true,
|
|
33573
|
+
scoped: true,
|
|
33574
|
+
evaluate: (args, options) => {
|
|
33575
|
+
const result = evaluateExists(args, options);
|
|
33576
|
+
if (result?.symbol === "True") return options.engine.False;
|
|
33577
|
+
if (result?.symbol === "False") return options.engine.True;
|
|
33578
|
+
return void 0;
|
|
33579
|
+
}
|
|
33580
|
+
},
|
|
33581
|
+
ExistsUnique: {
|
|
33582
|
+
signature: "(value, boolean) -> boolean",
|
|
33583
|
+
lazy: true,
|
|
33584
|
+
scoped: true,
|
|
33585
|
+
evaluate: evaluateExistsUnique
|
|
33586
|
+
},
|
|
33587
|
+
ForAll: {
|
|
33588
|
+
signature: "(value, boolean) -> boolean",
|
|
33589
|
+
lazy: true,
|
|
33590
|
+
scoped: true,
|
|
33591
|
+
evaluate: evaluateForAll
|
|
33592
|
+
},
|
|
33593
|
+
NotForAll: {
|
|
33594
|
+
signature: "(value, boolean) -> boolean",
|
|
33595
|
+
lazy: true,
|
|
33596
|
+
scoped: true,
|
|
33597
|
+
evaluate: (args, options) => {
|
|
33598
|
+
const result = evaluateForAll(args, options);
|
|
33599
|
+
if (result?.symbol === "True") return options.engine.False;
|
|
33600
|
+
if (result?.symbol === "False") return options.engine.True;
|
|
33601
|
+
return void 0;
|
|
33602
|
+
}
|
|
33603
|
+
},
|
|
33604
|
+
// Predicate application in First-Order Logic.
|
|
33605
|
+
// ["Predicate", "P", "x"] represents the predicate P applied to x.
|
|
33606
|
+
// This is semantically different from a function application: predicates
|
|
33607
|
+
// return boolean values and are used in logical formulas.
|
|
33608
|
+
// In LaTeX, P(x) inside a quantifier context parses to ["Predicate", "P", "x"].
|
|
33609
|
+
Predicate: {
|
|
33610
|
+
description: "Apply a predicate to arguments, returning a boolean",
|
|
33611
|
+
signature: "(symbol, value+) -> boolean",
|
|
33612
|
+
lazy: true,
|
|
33613
|
+
// Predicates remain symbolic unless explicitly defined
|
|
33614
|
+
evaluate: (args, { engine }) => {
|
|
33615
|
+
if (args.length === 0) return void 0;
|
|
33616
|
+
const pred = args[0];
|
|
33617
|
+
if (!pred.symbol) return void 0;
|
|
33618
|
+
return void 0;
|
|
33619
|
+
}
|
|
33620
|
+
},
|
|
32746
33621
|
KroneckerDelta: {
|
|
32747
33622
|
description: "Return 1 if the arguments are equal, 0 otherwise",
|
|
32748
33623
|
signature: "(value+) -> integer",
|
|
@@ -32763,82 +33638,189 @@ var LOGIC_LIBRARY = {
|
|
|
32763
33638
|
evaluate: (args, { engine: ce }) => args[0].symbol === "True" ? ce.One : ce.Zero
|
|
32764
33639
|
}
|
|
32765
33640
|
};
|
|
32766
|
-
function
|
|
32767
|
-
|
|
32768
|
-
|
|
32769
|
-
|
|
32770
|
-
|
|
32771
|
-
|
|
32772
|
-
|
|
32773
|
-
|
|
32774
|
-
|
|
32775
|
-
|
|
32776
|
-
|
|
32777
|
-
|
|
32778
|
-
|
|
32779
|
-
|
|
32780
|
-
|
|
32781
|
-
}
|
|
32782
|
-
}
|
|
32783
|
-
if (ops.length === 0) return ce.True;
|
|
32784
|
-
if (ops.length === 1) return ops[0];
|
|
32785
|
-
return ce._fn("And", ops);
|
|
33641
|
+
function simplifyLogicFunction(x) {
|
|
33642
|
+
const fn = {
|
|
33643
|
+
And: evaluateAnd,
|
|
33644
|
+
Or: evaluateOr,
|
|
33645
|
+
Not: evaluateNot,
|
|
33646
|
+
Equivalent: evaluateEquivalent,
|
|
33647
|
+
Implies: evaluateImplies,
|
|
33648
|
+
Xor: evaluateXor,
|
|
33649
|
+
Nand: evaluateNand,
|
|
33650
|
+
Nor: evaluateNor
|
|
33651
|
+
}[x.operator];
|
|
33652
|
+
if (!fn || !x.ops) return void 0;
|
|
33653
|
+
const value = fn(x.ops, { engine: x.engine });
|
|
33654
|
+
if (!value) return void 0;
|
|
33655
|
+
return { value, because: "logic" };
|
|
32786
33656
|
}
|
|
32787
|
-
function
|
|
32788
|
-
if (args.length
|
|
32789
|
-
const
|
|
32790
|
-
|
|
32791
|
-
|
|
32792
|
-
|
|
32793
|
-
|
|
32794
|
-
|
|
32795
|
-
|
|
32796
|
-
|
|
32797
|
-
|
|
32798
|
-
|
|
32799
|
-
|
|
33657
|
+
function evaluateForAll(args, { engine: ce }) {
|
|
33658
|
+
if (args.length < 2) return void 0;
|
|
33659
|
+
const condition = args[0];
|
|
33660
|
+
const body = args[1];
|
|
33661
|
+
const canonicalBody = body.canonical;
|
|
33662
|
+
if (canonicalBody.symbol === "True") return ce.True;
|
|
33663
|
+
if (canonicalBody.symbol === "False") return ce.False;
|
|
33664
|
+
const variable = condition.symbol ?? condition.op1?.symbol;
|
|
33665
|
+
if (variable && !bodyContainsVariable(canonicalBody, variable)) {
|
|
33666
|
+
return canonicalBody.evaluate();
|
|
33667
|
+
}
|
|
33668
|
+
const domain = extractFiniteDomain(condition, ce);
|
|
33669
|
+
if (domain) {
|
|
33670
|
+
const nestedDomains = collectNestedDomains(body, ce);
|
|
33671
|
+
if (nestedDomains.length > 0) {
|
|
33672
|
+
return evaluateForAllCartesian(
|
|
33673
|
+
[{ variable: domain.variable, values: domain.values }, ...nestedDomains],
|
|
33674
|
+
getInnermostBody(body),
|
|
33675
|
+
ce
|
|
33676
|
+
);
|
|
33677
|
+
}
|
|
33678
|
+
for (const value of domain.values) {
|
|
33679
|
+
const substituted = body.subs({ [domain.variable]: value }).canonical;
|
|
33680
|
+
const result = substituted.evaluate();
|
|
33681
|
+
if (result.symbol === "False") {
|
|
33682
|
+
return ce.False;
|
|
33683
|
+
}
|
|
33684
|
+
if (result.symbol !== "True") {
|
|
33685
|
+
return void 0;
|
|
32800
33686
|
}
|
|
32801
|
-
if (!duplicate) ops.push(arg);
|
|
32802
33687
|
}
|
|
33688
|
+
return ce.True;
|
|
32803
33689
|
}
|
|
32804
|
-
|
|
32805
|
-
if (
|
|
32806
|
-
|
|
32807
|
-
}
|
|
32808
|
-
function evaluateNot(args, { engine: ce }) {
|
|
32809
|
-
const op1 = args[0]?.symbol;
|
|
32810
|
-
if (op1 === "True") return ce.False;
|
|
32811
|
-
if (op1 === "False") return ce.True;
|
|
33690
|
+
const bodyEval = canonicalBody.evaluate();
|
|
33691
|
+
if (bodyEval.symbol === "True") return ce.True;
|
|
33692
|
+
if (bodyEval.symbol === "False") return ce.False;
|
|
32812
33693
|
return void 0;
|
|
32813
33694
|
}
|
|
32814
|
-
function
|
|
32815
|
-
|
|
32816
|
-
const
|
|
32817
|
-
|
|
32818
|
-
|
|
32819
|
-
if (
|
|
33695
|
+
function evaluateExists(args, { engine: ce }) {
|
|
33696
|
+
if (args.length < 2) return void 0;
|
|
33697
|
+
const condition = args[0];
|
|
33698
|
+
const body = args[1];
|
|
33699
|
+
const canonicalBody = body.canonical;
|
|
33700
|
+
if (canonicalBody.symbol === "True") return ce.True;
|
|
33701
|
+
if (canonicalBody.symbol === "False") return ce.False;
|
|
33702
|
+
const variable = condition.symbol ?? condition.op1?.symbol;
|
|
33703
|
+
if (variable && !bodyContainsVariable(canonicalBody, variable)) {
|
|
33704
|
+
return canonicalBody.evaluate();
|
|
33705
|
+
}
|
|
33706
|
+
const domain = extractFiniteDomain(condition, ce);
|
|
33707
|
+
if (domain) {
|
|
33708
|
+
const nestedDomains = collectNestedDomains(body, ce);
|
|
33709
|
+
if (nestedDomains.length > 0) {
|
|
33710
|
+
return evaluateExistsCartesian(
|
|
33711
|
+
[{ variable: domain.variable, values: domain.values }, ...nestedDomains],
|
|
33712
|
+
getInnermostBody(body),
|
|
33713
|
+
ce
|
|
33714
|
+
);
|
|
33715
|
+
}
|
|
33716
|
+
for (const value of domain.values) {
|
|
33717
|
+
const substituted = body.subs({ [domain.variable]: value }).canonical;
|
|
33718
|
+
const result = substituted.evaluate();
|
|
33719
|
+
if (result.symbol === "True") {
|
|
33720
|
+
return ce.True;
|
|
33721
|
+
}
|
|
33722
|
+
}
|
|
32820
33723
|
return ce.False;
|
|
33724
|
+
}
|
|
33725
|
+
const bodyEval = canonicalBody.evaluate();
|
|
33726
|
+
if (bodyEval.symbol === "True") return ce.True;
|
|
33727
|
+
if (bodyEval.symbol === "False") return ce.False;
|
|
32821
33728
|
return void 0;
|
|
32822
33729
|
}
|
|
32823
|
-
function
|
|
32824
|
-
|
|
32825
|
-
const
|
|
32826
|
-
|
|
32827
|
-
|
|
32828
|
-
if (
|
|
33730
|
+
function evaluateExistsUnique(args, { engine: ce }) {
|
|
33731
|
+
if (args.length < 2) return void 0;
|
|
33732
|
+
const condition = args[0];
|
|
33733
|
+
const body = args[1];
|
|
33734
|
+
const domain = extractFiniteDomain(condition, ce);
|
|
33735
|
+
if (domain) {
|
|
33736
|
+
let count = 0;
|
|
33737
|
+
for (const value of domain.values) {
|
|
33738
|
+
const substituted = body.subs({ [domain.variable]: value }).canonical;
|
|
33739
|
+
const result = substituted.evaluate();
|
|
33740
|
+
if (result.symbol === "True") {
|
|
33741
|
+
count++;
|
|
33742
|
+
if (count > 1) return ce.False;
|
|
33743
|
+
} else if (result.symbol !== "False") {
|
|
33744
|
+
return void 0;
|
|
33745
|
+
}
|
|
33746
|
+
}
|
|
33747
|
+
return count === 1 ? ce.True : ce.False;
|
|
33748
|
+
}
|
|
32829
33749
|
return void 0;
|
|
32830
33750
|
}
|
|
32831
|
-
|
|
32832
|
-
|
|
32833
|
-
|
|
32834
|
-
|
|
32835
|
-
|
|
32836
|
-
|
|
32837
|
-
|
|
32838
|
-
|
|
32839
|
-
|
|
32840
|
-
|
|
32841
|
-
}
|
|
33751
|
+
var LOGIC_FUNCTION_LIBRARY = {
|
|
33752
|
+
/**
|
|
33753
|
+
* Convert a boolean expression to Conjunctive Normal Form (CNF).
|
|
33754
|
+
* CNF is a conjunction (And) of disjunctions (Or) of literals.
|
|
33755
|
+
* A literal is either a variable or its negation.
|
|
33756
|
+
*
|
|
33757
|
+
* Example: (A ∨ B) ∧ (¬A ∨ C)
|
|
33758
|
+
*/
|
|
33759
|
+
ToCNF: {
|
|
33760
|
+
signature: "(boolean) -> boolean",
|
|
33761
|
+
evaluate: ([expr], { engine: ce }) => {
|
|
33762
|
+
if (!expr) return void 0;
|
|
33763
|
+
return toCNF(expr.evaluate(), ce);
|
|
33764
|
+
}
|
|
33765
|
+
},
|
|
33766
|
+
/**
|
|
33767
|
+
* Convert a boolean expression to Disjunctive Normal Form (DNF).
|
|
33768
|
+
* DNF is a disjunction (Or) of conjunctions (And) of literals.
|
|
33769
|
+
* A literal is either a variable or its negation.
|
|
33770
|
+
*
|
|
33771
|
+
* Example: (A ∧ B) ∨ (¬A ∧ C)
|
|
33772
|
+
*/
|
|
33773
|
+
ToDNF: {
|
|
33774
|
+
signature: "(boolean) -> boolean",
|
|
33775
|
+
evaluate: ([expr], { engine: ce }) => {
|
|
33776
|
+
if (!expr) return void 0;
|
|
33777
|
+
return toDNF(expr.evaluate(), ce);
|
|
33778
|
+
}
|
|
33779
|
+
},
|
|
33780
|
+
/**
|
|
33781
|
+
* Check if a boolean expression is satisfiable.
|
|
33782
|
+
* Returns True if there exists an assignment of truth values to variables
|
|
33783
|
+
* that makes the expression true.
|
|
33784
|
+
*/
|
|
33785
|
+
IsSatisfiable: {
|
|
33786
|
+
signature: "(boolean) -> boolean",
|
|
33787
|
+
evaluate: ([expr], { engine: ce }) => {
|
|
33788
|
+
if (!expr) return void 0;
|
|
33789
|
+
return isSatisfiable(expr, ce);
|
|
33790
|
+
}
|
|
33791
|
+
},
|
|
33792
|
+
/**
|
|
33793
|
+
* Check if a boolean expression is a tautology.
|
|
33794
|
+
* Returns True if the expression is true for all possible assignments
|
|
33795
|
+
* of truth values to variables.
|
|
33796
|
+
*/
|
|
33797
|
+
IsTautology: {
|
|
33798
|
+
signature: "(boolean) -> boolean",
|
|
33799
|
+
evaluate: ([expr], { engine: ce }) => {
|
|
33800
|
+
if (!expr) return void 0;
|
|
33801
|
+
return isTautology(expr, ce);
|
|
33802
|
+
}
|
|
33803
|
+
},
|
|
33804
|
+
/**
|
|
33805
|
+
* Generate a truth table for a boolean expression.
|
|
33806
|
+
* Returns a List of Lists, where each inner list contains the variable
|
|
33807
|
+
* assignments followed by the result.
|
|
33808
|
+
*
|
|
33809
|
+
* Example: TruthTable(["And", "A", "B"]) returns:
|
|
33810
|
+
* [["List", "A", "B", "Result"],
|
|
33811
|
+
* ["List", False, False, False],
|
|
33812
|
+
* ["List", False, True, False],
|
|
33813
|
+
* ["List", True, False, False],
|
|
33814
|
+
* ["List", True, True, True]]
|
|
33815
|
+
*/
|
|
33816
|
+
TruthTable: {
|
|
33817
|
+
signature: "(boolean) -> list",
|
|
33818
|
+
evaluate: ([expr], { engine: ce }) => {
|
|
33819
|
+
if (!expr) return void 0;
|
|
33820
|
+
return generateTruthTable(expr, ce);
|
|
33821
|
+
}
|
|
33822
|
+
}
|
|
33823
|
+
};
|
|
32842
33824
|
|
|
32843
33825
|
// src/compute-engine/library/number-theory.ts
|
|
32844
33826
|
var NUMBER_THEORY_LIBRARY = [
|
|
@@ -35370,7 +36352,7 @@ var LIBRARIES = {
|
|
|
35370
36352
|
"domains": [],
|
|
35371
36353
|
// 'domains': getDomainsDictionary(),
|
|
35372
36354
|
"linear-algebra": LINEAR_ALGEBRA_LIBRARY,
|
|
35373
|
-
"logic": LOGIC_LIBRARY,
|
|
36355
|
+
"logic": [LOGIC_LIBRARY, LOGIC_FUNCTION_LIBRARY],
|
|
35374
36356
|
"number-theory": NUMBER_THEORY_LIBRARY,
|
|
35375
36357
|
"numeric": [],
|
|
35376
36358
|
// @todo // 'numeric': [
|
|
@@ -35666,6 +36648,64 @@ function matchOnce(expr, pattern, substitution, options) {
|
|
|
35666
36648
|
const ce = expr.engine;
|
|
35667
36649
|
let result = null;
|
|
35668
36650
|
const operator2 = pattern.operator;
|
|
36651
|
+
if (operator2 === "Divide" && expr.numericValue !== null && !expr.denominator.is(1)) {
|
|
36652
|
+
const divideExpr = ce.function(
|
|
36653
|
+
"Divide",
|
|
36654
|
+
[expr.numerator, expr.denominator],
|
|
36655
|
+
{ canonical: false, structural: true }
|
|
36656
|
+
);
|
|
36657
|
+
return matchArguments(divideExpr, pattern.ops, substitution, options);
|
|
36658
|
+
}
|
|
36659
|
+
if (operator2 === "Divide" && expr.operator === "Multiply") {
|
|
36660
|
+
const ops = expr.ops;
|
|
36661
|
+
for (let i = 0; i < ops.length; i++) {
|
|
36662
|
+
const op = ops[i];
|
|
36663
|
+
if (op.numericValue !== null && op.numerator.is(1) && !op.denominator.is(1)) {
|
|
36664
|
+
const others = ops.filter((_, j) => j !== i);
|
|
36665
|
+
const numerator = others.length === 1 ? others[0] : ce.function("Multiply", others, { canonical: false });
|
|
36666
|
+
const divideExpr = ce.function(
|
|
36667
|
+
"Divide",
|
|
36668
|
+
[numerator, op.denominator],
|
|
36669
|
+
{ canonical: false, structural: true }
|
|
36670
|
+
);
|
|
36671
|
+
const result2 = matchArguments(
|
|
36672
|
+
divideExpr,
|
|
36673
|
+
pattern.ops,
|
|
36674
|
+
substitution,
|
|
36675
|
+
options
|
|
36676
|
+
);
|
|
36677
|
+
if (result2 !== null) return result2;
|
|
36678
|
+
}
|
|
36679
|
+
}
|
|
36680
|
+
}
|
|
36681
|
+
if (operator2 === "Power" && expr.operator === "Divide" && expr.op1.is(1)) {
|
|
36682
|
+
const powerExpr = ce.function(
|
|
36683
|
+
"Power",
|
|
36684
|
+
[expr.op2, ce.number(-1)],
|
|
36685
|
+
{ canonical: false, structural: true }
|
|
36686
|
+
);
|
|
36687
|
+
const result2 = matchArguments(
|
|
36688
|
+
powerExpr,
|
|
36689
|
+
pattern.ops,
|
|
36690
|
+
substitution,
|
|
36691
|
+
options
|
|
36692
|
+
);
|
|
36693
|
+
if (result2 !== null) return result2;
|
|
36694
|
+
}
|
|
36695
|
+
if (operator2 === "Power" && expr.operator === "Root") {
|
|
36696
|
+
const powerExpr = ce.function(
|
|
36697
|
+
"Power",
|
|
36698
|
+
[expr.op1, ce.box(["Divide", 1, expr.op2], { canonical: false })],
|
|
36699
|
+
{ canonical: false, structural: true }
|
|
36700
|
+
);
|
|
36701
|
+
const result2 = matchArguments(
|
|
36702
|
+
powerExpr,
|
|
36703
|
+
pattern.ops,
|
|
36704
|
+
substitution,
|
|
36705
|
+
options
|
|
36706
|
+
);
|
|
36707
|
+
if (result2 !== null) return result2;
|
|
36708
|
+
}
|
|
35669
36709
|
if (operator2.startsWith("_")) {
|
|
35670
36710
|
result = captureWildcard(operator2, ce.box(expr.operator), substitution);
|
|
35671
36711
|
if (result !== null)
|
|
@@ -38715,12 +39755,568 @@ var BoxedSymbol = class extends _BoxedExpression {
|
|
|
38715
39755
|
}
|
|
38716
39756
|
};
|
|
38717
39757
|
|
|
39758
|
+
// src/compute-engine/symbolic/simplify-sum.ts
|
|
39759
|
+
function simplifySum(x) {
|
|
39760
|
+
if (x.operator !== "Sum") return void 0;
|
|
39761
|
+
let body = x.op1;
|
|
39762
|
+
const limits = x.op2;
|
|
39763
|
+
if (!body || !limits || limits.operator !== "Limits") return void 0;
|
|
39764
|
+
const index = limits.op1?.symbol;
|
|
39765
|
+
const lower = limits.op2;
|
|
39766
|
+
const upper = limits.op3;
|
|
39767
|
+
if (!index || !lower || !upper) return void 0;
|
|
39768
|
+
const ce = x.engine;
|
|
39769
|
+
if (body.operator === "Sum" || body.operator === "Product") {
|
|
39770
|
+
const simplifiedBody = body.simplify();
|
|
39771
|
+
if (!simplifiedBody.isSame(body)) {
|
|
39772
|
+
const newSum = ce.function("Sum", [simplifiedBody, limits]);
|
|
39773
|
+
return { value: newSum, because: "simplified nested sum/product" };
|
|
39774
|
+
}
|
|
39775
|
+
}
|
|
39776
|
+
if (lower.isNumberLiteral && upper.isNumberLiteral) {
|
|
39777
|
+
const lowerVal = lower.numericValue;
|
|
39778
|
+
const upperVal = upper.numericValue;
|
|
39779
|
+
if (typeof lowerVal === "number" && typeof upperVal === "number" && Number.isInteger(lowerVal) && Number.isInteger(upperVal)) {
|
|
39780
|
+
if (upperVal < lowerVal) {
|
|
39781
|
+
return { value: ce.Zero, because: "empty sum" };
|
|
39782
|
+
}
|
|
39783
|
+
if (upperVal === lowerVal) {
|
|
39784
|
+
return {
|
|
39785
|
+
value: body.subs({ [index]: lower }).simplify(),
|
|
39786
|
+
because: "single term sum"
|
|
39787
|
+
};
|
|
39788
|
+
}
|
|
39789
|
+
}
|
|
39790
|
+
}
|
|
39791
|
+
const bodyUnknowns = new Set(body.unknowns);
|
|
39792
|
+
if (!bodyUnknowns.has(index)) {
|
|
39793
|
+
const count = upper.sub(lower).add(ce.One).simplify();
|
|
39794
|
+
if (count.isNumberLiteral && count.numericValue !== null) {
|
|
39795
|
+
const countVal = typeof count.numericValue === "number" ? count.numericValue : count.numericValue.re;
|
|
39796
|
+
if (countVal <= 0) {
|
|
39797
|
+
return { value: ce.Zero, because: "empty sum" };
|
|
39798
|
+
}
|
|
39799
|
+
}
|
|
39800
|
+
return {
|
|
39801
|
+
value: count.mul(body.simplify()),
|
|
39802
|
+
because: "sum of constant"
|
|
39803
|
+
};
|
|
39804
|
+
}
|
|
39805
|
+
if (body.symbol === index) {
|
|
39806
|
+
const a = lower;
|
|
39807
|
+
const b = upper;
|
|
39808
|
+
const result = b.mul(b.add(ce.One)).sub(a.mul(a.sub(ce.One))).div(2);
|
|
39809
|
+
return { value: result.simplify(), because: "triangular number" };
|
|
39810
|
+
}
|
|
39811
|
+
if (body.operator === "Power" && body.op1?.symbol === index && body.op2?.is(2) && lower.is(1)) {
|
|
39812
|
+
const b = upper;
|
|
39813
|
+
const result = b.mul(b.add(ce.One)).mul(b.mul(2).add(ce.One)).div(6);
|
|
39814
|
+
return { value: result, because: "sum of squares" };
|
|
39815
|
+
}
|
|
39816
|
+
if (body.operator === "Power" && body.op1?.symbol === index && body.op2?.is(3) && lower.is(1)) {
|
|
39817
|
+
const b = upper;
|
|
39818
|
+
const triangular = b.mul(b.add(ce.One)).div(2);
|
|
39819
|
+
return { value: triangular.pow(2), because: "sum of cubes" };
|
|
39820
|
+
}
|
|
39821
|
+
if (body.operator === "Power" && body.op1?.is(-1) && body.op2?.symbol === index && lower.is(0)) {
|
|
39822
|
+
const b = upper;
|
|
39823
|
+
const result = ce.One.add(ce.number(-1).pow(b)).div(2);
|
|
39824
|
+
return { value: result, because: "alternating unit series" };
|
|
39825
|
+
}
|
|
39826
|
+
if (body.operator === "Multiply" && body.ops && lower.is(0)) {
|
|
39827
|
+
let hasAlternating = false;
|
|
39828
|
+
let hasIndex = false;
|
|
39829
|
+
for (const op of body.ops) {
|
|
39830
|
+
if (op.operator === "Power" && op.op1?.is(-1) && op.op2?.symbol === index) {
|
|
39831
|
+
hasAlternating = true;
|
|
39832
|
+
} else if (op.symbol === index) {
|
|
39833
|
+
hasIndex = true;
|
|
39834
|
+
}
|
|
39835
|
+
}
|
|
39836
|
+
if (hasAlternating && hasIndex && body.ops.length === 2) {
|
|
39837
|
+
const b = upper;
|
|
39838
|
+
const result = ce.function("Multiply", [
|
|
39839
|
+
ce.function("Power", [ce.number(-1), b]),
|
|
39840
|
+
ce.function("Floor", [
|
|
39841
|
+
ce.function("Divide", [ce.function("Add", [b, ce.One]), ce.number(2)])
|
|
39842
|
+
])
|
|
39843
|
+
]);
|
|
39844
|
+
return { value: result, because: "alternating linear series" };
|
|
39845
|
+
}
|
|
39846
|
+
}
|
|
39847
|
+
if (body.operator === "Add" && body.ops) {
|
|
39848
|
+
let constant = null;
|
|
39849
|
+
let coefficient = null;
|
|
39850
|
+
for (const term of body.ops) {
|
|
39851
|
+
const termUnknowns = new Set(term.unknowns);
|
|
39852
|
+
if (!termUnknowns.has(index)) {
|
|
39853
|
+
constant = constant ? constant.add(term) : term;
|
|
39854
|
+
} else if (term.symbol === index) {
|
|
39855
|
+
coefficient = coefficient ? coefficient.add(ce.One) : ce.One;
|
|
39856
|
+
} else if (term.operator === "Multiply" && term.ops?.some((op) => op.symbol === index)) {
|
|
39857
|
+
const coef = term.ops.filter((op) => op.symbol !== index);
|
|
39858
|
+
if (coef.length === term.ops.length - 1) {
|
|
39859
|
+
const c = coef.length === 1 ? coef[0] : ce.function("Multiply", coef);
|
|
39860
|
+
coefficient = coefficient ? coefficient.add(c) : c;
|
|
39861
|
+
}
|
|
39862
|
+
} else {
|
|
39863
|
+
constant = null;
|
|
39864
|
+
coefficient = null;
|
|
39865
|
+
break;
|
|
39866
|
+
}
|
|
39867
|
+
}
|
|
39868
|
+
if (constant !== null && coefficient !== null) {
|
|
39869
|
+
const m = lower;
|
|
39870
|
+
const b = upper;
|
|
39871
|
+
if (lower.is(0)) {
|
|
39872
|
+
const bPlus1 = ce.function("Add", [b, ce.One]);
|
|
39873
|
+
const inner = ce.function("Add", [
|
|
39874
|
+
constant,
|
|
39875
|
+
ce.function("Divide", [
|
|
39876
|
+
ce.function("Multiply", [coefficient, b]),
|
|
39877
|
+
ce.number(2)
|
|
39878
|
+
])
|
|
39879
|
+
]);
|
|
39880
|
+
const result = ce.function("Multiply", [bPlus1, inner]);
|
|
39881
|
+
return { value: result, because: "arithmetic progression" };
|
|
39882
|
+
} else {
|
|
39883
|
+
const numTerms = ce.function("Add", [
|
|
39884
|
+
ce.function("Subtract", [b, m]),
|
|
39885
|
+
ce.One
|
|
39886
|
+
]);
|
|
39887
|
+
const avgIndex = ce.function("Divide", [
|
|
39888
|
+
ce.function("Add", [m, b]),
|
|
39889
|
+
ce.number(2)
|
|
39890
|
+
]);
|
|
39891
|
+
const avgValue = ce.function("Add", [
|
|
39892
|
+
constant,
|
|
39893
|
+
ce.function("Multiply", [coefficient, avgIndex])
|
|
39894
|
+
]);
|
|
39895
|
+
const result = ce.function("Multiply", [numTerms, avgValue]);
|
|
39896
|
+
return { value: result, because: "arithmetic progression" };
|
|
39897
|
+
}
|
|
39898
|
+
}
|
|
39899
|
+
}
|
|
39900
|
+
if (body.operator === "Power" && body.op2?.symbol === index && !new Set(body.op1?.unknowns ?? []).has(index)) {
|
|
39901
|
+
const r = body.op1;
|
|
39902
|
+
const b = upper;
|
|
39903
|
+
if (lower.is(0)) {
|
|
39904
|
+
const numerator = ce.One.sub(r.pow(b.add(ce.One)));
|
|
39905
|
+
const denominator = ce.One.sub(r);
|
|
39906
|
+
return { value: numerator.div(denominator), because: "geometric series" };
|
|
39907
|
+
} else if (lower.is(1)) {
|
|
39908
|
+
const numerator = r.sub(r.pow(b.add(ce.One)));
|
|
39909
|
+
const denominator = ce.One.sub(r);
|
|
39910
|
+
return { value: numerator.div(denominator), because: "geometric series" };
|
|
39911
|
+
}
|
|
39912
|
+
}
|
|
39913
|
+
if (body.operator === "Binomial" && lower.is(0) && body.op2?.symbol === index) {
|
|
39914
|
+
const n = body.op1;
|
|
39915
|
+
if (n && upper.isSame(n)) {
|
|
39916
|
+
const result = ce.function("Power", [ce.number(2), n]);
|
|
39917
|
+
return { value: result, because: "sum of binomial coefficients" };
|
|
39918
|
+
}
|
|
39919
|
+
}
|
|
39920
|
+
if (body.operator === "Multiply" && body.ops && lower.is(0)) {
|
|
39921
|
+
let hasBinomial = false;
|
|
39922
|
+
let hasAlternating = false;
|
|
39923
|
+
let binomialN = null;
|
|
39924
|
+
for (const op of body.ops) {
|
|
39925
|
+
if (op.operator === "Binomial" && op.op2?.symbol === index) {
|
|
39926
|
+
hasBinomial = true;
|
|
39927
|
+
binomialN = op.op1 ?? null;
|
|
39928
|
+
} else if (op.operator === "Power" && op.op1?.is(-1) && op.op2?.symbol === index) {
|
|
39929
|
+
hasAlternating = true;
|
|
39930
|
+
}
|
|
39931
|
+
}
|
|
39932
|
+
if (hasBinomial && hasAlternating && binomialN && upper.isSame(binomialN)) {
|
|
39933
|
+
return { value: ce.Zero, because: "alternating binomial sum" };
|
|
39934
|
+
}
|
|
39935
|
+
let hasIndex = false;
|
|
39936
|
+
binomialN = null;
|
|
39937
|
+
hasBinomial = false;
|
|
39938
|
+
for (const op of body.ops) {
|
|
39939
|
+
if (op.symbol === index) {
|
|
39940
|
+
hasIndex = true;
|
|
39941
|
+
} else if (op.operator === "Binomial" && op.op2?.symbol === index) {
|
|
39942
|
+
hasBinomial = true;
|
|
39943
|
+
binomialN = op.op1 ?? null;
|
|
39944
|
+
}
|
|
39945
|
+
}
|
|
39946
|
+
if (hasIndex && hasBinomial && binomialN && upper.isSame(binomialN) && body.ops.length === 2) {
|
|
39947
|
+
const n = binomialN;
|
|
39948
|
+
const result = ce.function("Multiply", [
|
|
39949
|
+
n,
|
|
39950
|
+
ce.function("Power", [ce.number(2), n.sub(ce.One)])
|
|
39951
|
+
]);
|
|
39952
|
+
return { value: result, because: "weighted binomial sum" };
|
|
39953
|
+
}
|
|
39954
|
+
let hasIndexSquared = false;
|
|
39955
|
+
binomialN = null;
|
|
39956
|
+
hasBinomial = false;
|
|
39957
|
+
for (const op of body.ops) {
|
|
39958
|
+
if (op.operator === "Power" && op.op1?.symbol === index && op.op2?.is(2)) {
|
|
39959
|
+
hasIndexSquared = true;
|
|
39960
|
+
} else if (op.operator === "Binomial" && op.op2?.symbol === index) {
|
|
39961
|
+
hasBinomial = true;
|
|
39962
|
+
binomialN = op.op1 ?? null;
|
|
39963
|
+
}
|
|
39964
|
+
}
|
|
39965
|
+
if (hasIndexSquared && hasBinomial && binomialN && upper.isSame(binomialN) && body.ops.length === 2) {
|
|
39966
|
+
const n = binomialN;
|
|
39967
|
+
const result = ce.function("Multiply", [
|
|
39968
|
+
n,
|
|
39969
|
+
n.add(ce.One),
|
|
39970
|
+
ce.function("Power", [ce.number(2), n.sub(ce.number(2))])
|
|
39971
|
+
]);
|
|
39972
|
+
return { value: result, because: "weighted squared binomial sum" };
|
|
39973
|
+
}
|
|
39974
|
+
let hasIndexCubed = false;
|
|
39975
|
+
binomialN = null;
|
|
39976
|
+
hasBinomial = false;
|
|
39977
|
+
for (const op of body.ops) {
|
|
39978
|
+
if (op.operator === "Power" && op.op1?.symbol === index && op.op2?.is(3)) {
|
|
39979
|
+
hasIndexCubed = true;
|
|
39980
|
+
} else if (op.operator === "Binomial" && op.op2?.symbol === index) {
|
|
39981
|
+
hasBinomial = true;
|
|
39982
|
+
binomialN = op.op1 ?? null;
|
|
39983
|
+
}
|
|
39984
|
+
}
|
|
39985
|
+
if (hasIndexCubed && hasBinomial && binomialN && upper.isSame(binomialN) && body.ops.length === 2) {
|
|
39986
|
+
const n = binomialN;
|
|
39987
|
+
const result = ce.function("Multiply", [
|
|
39988
|
+
ce.function("Power", [n, ce.number(2)]),
|
|
39989
|
+
n.add(ce.number(3)),
|
|
39990
|
+
ce.function("Power", [ce.number(2), n.sub(ce.number(3))])
|
|
39991
|
+
]);
|
|
39992
|
+
return { value: result, because: "weighted cubed binomial sum" };
|
|
39993
|
+
}
|
|
39994
|
+
let hasAltTerm = false;
|
|
39995
|
+
let hasIndexTerm = false;
|
|
39996
|
+
binomialN = null;
|
|
39997
|
+
hasBinomial = false;
|
|
39998
|
+
for (const op of body.ops) {
|
|
39999
|
+
if (op.operator === "Power" && op.op1?.is(-1) && op.op2?.symbol === index) {
|
|
40000
|
+
hasAltTerm = true;
|
|
40001
|
+
} else if (op.symbol === index) {
|
|
40002
|
+
hasIndexTerm = true;
|
|
40003
|
+
} else if (op.operator === "Binomial" && op.op2?.symbol === index) {
|
|
40004
|
+
hasBinomial = true;
|
|
40005
|
+
binomialN = op.op1 ?? null;
|
|
40006
|
+
}
|
|
40007
|
+
}
|
|
40008
|
+
if (hasAltTerm && hasIndexTerm && hasBinomial && binomialN && upper.isSame(binomialN) && body.ops.length === 3) {
|
|
40009
|
+
return { value: ce.Zero, because: "alternating weighted binomial sum" };
|
|
40010
|
+
}
|
|
40011
|
+
}
|
|
40012
|
+
if (body.operator === "Power" && body.op1?.operator === "Binomial" && body.op2?.is(2) && lower.is(0)) {
|
|
40013
|
+
const binomial2 = body.op1;
|
|
40014
|
+
const n = binomial2.op1;
|
|
40015
|
+
const k = binomial2.op2;
|
|
40016
|
+
if (n && k?.symbol === index && upper.isSame(n)) {
|
|
40017
|
+
const result = ce.function("Binomial", [
|
|
40018
|
+
ce.function("Multiply", [ce.number(2), n]),
|
|
40019
|
+
n
|
|
40020
|
+
]);
|
|
40021
|
+
return { value: result, because: "sum of binomial squares" };
|
|
40022
|
+
}
|
|
40023
|
+
}
|
|
40024
|
+
if (body.operator === "Multiply" && body.ops?.length === 2 && lower.is(1)) {
|
|
40025
|
+
const [op1, op2] = body.ops;
|
|
40026
|
+
const isKTimesKPlus1 = op1.symbol === index && op2.operator === "Add" && op2.ops?.length === 2 && op2.ops.some((o) => o.symbol === index) && op2.ops.some((o) => o.is(1)) || op2.symbol === index && op1.operator === "Add" && op1.ops?.length === 2 && op1.ops.some((o) => o.symbol === index) && op1.ops.some((o) => o.is(1));
|
|
40027
|
+
if (isKTimesKPlus1) {
|
|
40028
|
+
const n = upper;
|
|
40029
|
+
const result = ce.function("Divide", [
|
|
40030
|
+
ce.function("Multiply", [
|
|
40031
|
+
n,
|
|
40032
|
+
ce.function("Add", [n, ce.One]),
|
|
40033
|
+
ce.function("Add", [n, ce.number(2)])
|
|
40034
|
+
]),
|
|
40035
|
+
ce.number(3)
|
|
40036
|
+
]);
|
|
40037
|
+
return { value: result, because: "sum of k*(k+1)" };
|
|
40038
|
+
}
|
|
40039
|
+
}
|
|
40040
|
+
if (body.operator === "Divide" && body.op1?.is(1) && body.op2?.operator === "Multiply") {
|
|
40041
|
+
const denom = body.op2;
|
|
40042
|
+
if (denom.ops?.length === 2) {
|
|
40043
|
+
const [d1, d2] = denom.ops;
|
|
40044
|
+
if (lower.is(1)) {
|
|
40045
|
+
const isKTimesKPlus1 = d1.symbol === index && d2.operator === "Add" && d2.ops?.length === 2 && d2.ops.some((op) => op.symbol === index) && d2.ops.some((op) => op.is(1)) || d2.symbol === index && d1.operator === "Add" && d1.ops?.length === 2 && d1.ops.some((op) => op.symbol === index) && d1.ops.some((op) => op.is(1));
|
|
40046
|
+
if (isKTimesKPlus1) {
|
|
40047
|
+
const n = upper;
|
|
40048
|
+
const result = n.div(n.add(ce.One));
|
|
40049
|
+
return { value: result, because: "partial fractions (telescoping)" };
|
|
40050
|
+
}
|
|
40051
|
+
}
|
|
40052
|
+
if (lower.is(2)) {
|
|
40053
|
+
const isKTimesKMinus1 = d1.symbol === index && d2.operator === "Add" && d2.ops?.length === 2 && d2.ops.some((op) => op.symbol === index) && d2.ops.some((op) => op.is(-1)) || d2.symbol === index && d1.operator === "Add" && d1.ops?.length === 2 && d1.ops.some((op) => op.symbol === index) && d1.ops.some((op) => op.is(-1));
|
|
40054
|
+
if (isKTimesKMinus1) {
|
|
40055
|
+
const n = upper;
|
|
40056
|
+
const result = n.sub(ce.One).div(n);
|
|
40057
|
+
return { value: result, because: "partial fractions (telescoping k*(k-1))" };
|
|
40058
|
+
}
|
|
40059
|
+
}
|
|
40060
|
+
}
|
|
40061
|
+
}
|
|
40062
|
+
if (body.operator === "Multiply" && body.ops) {
|
|
40063
|
+
const constantFactors = [];
|
|
40064
|
+
const indexFactors = [];
|
|
40065
|
+
for (const factor2 of body.ops) {
|
|
40066
|
+
const factorUnknowns = new Set(factor2.unknowns);
|
|
40067
|
+
if (factorUnknowns.has(index)) {
|
|
40068
|
+
indexFactors.push(factor2);
|
|
40069
|
+
} else {
|
|
40070
|
+
constantFactors.push(factor2);
|
|
40071
|
+
}
|
|
40072
|
+
}
|
|
40073
|
+
if (constantFactors.length > 0 && indexFactors.length > 0) {
|
|
40074
|
+
const constant = constantFactors.length === 1 ? constantFactors[0] : ce.function("Multiply", constantFactors);
|
|
40075
|
+
const indexPart = indexFactors.length === 1 ? indexFactors[0] : ce.function("Multiply", indexFactors);
|
|
40076
|
+
const newSum = ce.function("Sum", [indexPart, limits]);
|
|
40077
|
+
return {
|
|
40078
|
+
value: constant.mul(newSum),
|
|
40079
|
+
because: "factor out constant from sum"
|
|
40080
|
+
};
|
|
40081
|
+
}
|
|
40082
|
+
}
|
|
40083
|
+
return void 0;
|
|
40084
|
+
}
|
|
40085
|
+
|
|
40086
|
+
// src/compute-engine/symbolic/simplify-product.ts
|
|
40087
|
+
function simplifyProduct(x) {
|
|
40088
|
+
if (x.operator !== "Product") return void 0;
|
|
40089
|
+
let body = x.op1;
|
|
40090
|
+
const limits = x.op2;
|
|
40091
|
+
if (!body || !limits || limits.operator !== "Limits") return void 0;
|
|
40092
|
+
const index = limits.op1?.symbol;
|
|
40093
|
+
const lower = limits.op2;
|
|
40094
|
+
const upper = limits.op3;
|
|
40095
|
+
if (!index || !lower || !upper) return void 0;
|
|
40096
|
+
const ce = x.engine;
|
|
40097
|
+
if (body.operator === "Sum" || body.operator === "Product") {
|
|
40098
|
+
const simplifiedBody = body.simplify();
|
|
40099
|
+
if (!simplifiedBody.isSame(body)) {
|
|
40100
|
+
const newProduct = ce.function("Product", [simplifiedBody, limits]);
|
|
40101
|
+
return { value: newProduct, because: "simplified nested sum/product" };
|
|
40102
|
+
}
|
|
40103
|
+
}
|
|
40104
|
+
if (lower.isNumberLiteral && upper.isNumberLiteral) {
|
|
40105
|
+
const lowerVal = lower.numericValue;
|
|
40106
|
+
const upperVal = upper.numericValue;
|
|
40107
|
+
if (typeof lowerVal === "number" && typeof upperVal === "number" && Number.isInteger(lowerVal) && Number.isInteger(upperVal)) {
|
|
40108
|
+
if (upperVal < lowerVal) {
|
|
40109
|
+
return { value: ce.One, because: "empty product" };
|
|
40110
|
+
}
|
|
40111
|
+
if (upperVal === lowerVal) {
|
|
40112
|
+
return {
|
|
40113
|
+
value: body.subs({ [index]: lower }).simplify(),
|
|
40114
|
+
because: "single term product"
|
|
40115
|
+
};
|
|
40116
|
+
}
|
|
40117
|
+
}
|
|
40118
|
+
}
|
|
40119
|
+
const bodyUnknowns = new Set(body.unknowns);
|
|
40120
|
+
if (!bodyUnknowns.has(index)) {
|
|
40121
|
+
const count = upper.sub(lower).add(ce.One).simplify();
|
|
40122
|
+
if (count.isNumberLiteral && count.numericValue !== null) {
|
|
40123
|
+
const countVal = typeof count.numericValue === "number" ? count.numericValue : count.numericValue.re;
|
|
40124
|
+
if (countVal <= 0) {
|
|
40125
|
+
return { value: ce.One, because: "empty product" };
|
|
40126
|
+
}
|
|
40127
|
+
}
|
|
40128
|
+
return {
|
|
40129
|
+
value: body.simplify().pow(count),
|
|
40130
|
+
because: "product of constant"
|
|
40131
|
+
};
|
|
40132
|
+
}
|
|
40133
|
+
if (body.symbol === index && lower.is(1)) {
|
|
40134
|
+
return {
|
|
40135
|
+
value: ce.function("Factorial", [upper]),
|
|
40136
|
+
because: "factorial"
|
|
40137
|
+
};
|
|
40138
|
+
}
|
|
40139
|
+
if (body.operator === "Add" && body.ops?.length === 2 && lower.is(1)) {
|
|
40140
|
+
const [op1, op2] = body.ops;
|
|
40141
|
+
let indexTerm = null;
|
|
40142
|
+
let constTerm = null;
|
|
40143
|
+
if (op1.symbol === index && !new Set(op2.unknowns).has(index)) {
|
|
40144
|
+
indexTerm = op1;
|
|
40145
|
+
constTerm = op2;
|
|
40146
|
+
} else if (op2.symbol === index && !new Set(op1.unknowns).has(index)) {
|
|
40147
|
+
indexTerm = op2;
|
|
40148
|
+
constTerm = op1;
|
|
40149
|
+
}
|
|
40150
|
+
if (indexTerm && constTerm) {
|
|
40151
|
+
const b = upper;
|
|
40152
|
+
const c = constTerm;
|
|
40153
|
+
const result = ce.function("Divide", [
|
|
40154
|
+
ce.function("Factorial", [ce.function("Add", [b, c])]),
|
|
40155
|
+
ce.function("Factorial", [c])
|
|
40156
|
+
]);
|
|
40157
|
+
return { value: result, because: "shifted factorial" };
|
|
40158
|
+
}
|
|
40159
|
+
}
|
|
40160
|
+
if (body.operator === "Divide" && lower.is(1)) {
|
|
40161
|
+
const num = body.op1;
|
|
40162
|
+
const denom = body.op2;
|
|
40163
|
+
if (denom?.symbol === index && num?.operator === "Add" && num.ops?.length === 2 && num.ops.some((o) => o.symbol === index) && num.ops.some((o) => o.is(1))) {
|
|
40164
|
+
return { value: upper.add(ce.One), because: "telescoping product" };
|
|
40165
|
+
}
|
|
40166
|
+
}
|
|
40167
|
+
if (body.operator === "Add" && body.ops?.length === 2 && lower.is(2)) {
|
|
40168
|
+
let hasOne = false;
|
|
40169
|
+
let hasNegInvSq = false;
|
|
40170
|
+
for (const op of body.ops) {
|
|
40171
|
+
if (op.is(1)) {
|
|
40172
|
+
hasOne = true;
|
|
40173
|
+
} else if (op.operator === "Negate" && op.op1?.operator === "Power" && op.op1.op1?.symbol === index && op.op1.op2?.is(-2)) {
|
|
40174
|
+
hasNegInvSq = true;
|
|
40175
|
+
} else if (op.operator === "Power" && op.op1?.symbol === index && op.op2?.is(-2)) {
|
|
40176
|
+
} else if (op.operator === "Multiply" && op.ops?.some((o) => o.is(-1)) && op.ops?.some(
|
|
40177
|
+
(o) => o.operator === "Power" && o.op1?.symbol === index && o.op2?.is(-2)
|
|
40178
|
+
)) {
|
|
40179
|
+
hasNegInvSq = true;
|
|
40180
|
+
}
|
|
40181
|
+
}
|
|
40182
|
+
if (hasOne && hasNegInvSq) {
|
|
40183
|
+
const n = upper;
|
|
40184
|
+
const result = ce.function("Divide", [
|
|
40185
|
+
ce.function("Add", [n, ce.One]),
|
|
40186
|
+
ce.function("Multiply", [ce.number(2), n])
|
|
40187
|
+
]);
|
|
40188
|
+
return { value: result, because: "Wallis-like product" };
|
|
40189
|
+
}
|
|
40190
|
+
}
|
|
40191
|
+
if (body.operator === "Add" && body.ops?.length === 2 && lower.is(1)) {
|
|
40192
|
+
const [op1, op2] = body.ops;
|
|
40193
|
+
let hasLinearTerm = false;
|
|
40194
|
+
let coefficient = 0;
|
|
40195
|
+
let constantTerm = 0;
|
|
40196
|
+
for (const op of body.ops) {
|
|
40197
|
+
if (op.isNumberLiteral && typeof op.numericValue === "number") {
|
|
40198
|
+
constantTerm = op.numericValue;
|
|
40199
|
+
} else if (op.operator === "Multiply" && op.ops?.length === 2) {
|
|
40200
|
+
const [a, b] = op.ops;
|
|
40201
|
+
if (a.isNumberLiteral && typeof a.numericValue === "number" && b.symbol === index) {
|
|
40202
|
+
coefficient = a.numericValue;
|
|
40203
|
+
hasLinearTerm = true;
|
|
40204
|
+
} else if (b.isNumberLiteral && typeof b.numericValue === "number" && a.symbol === index) {
|
|
40205
|
+
coefficient = b.numericValue;
|
|
40206
|
+
hasLinearTerm = true;
|
|
40207
|
+
}
|
|
40208
|
+
}
|
|
40209
|
+
}
|
|
40210
|
+
if (hasLinearTerm && coefficient === 2 && constantTerm === -1) {
|
|
40211
|
+
const b = upper;
|
|
40212
|
+
const result = ce.function("Factorial2", [
|
|
40213
|
+
ce.function("Subtract", [
|
|
40214
|
+
ce.function("Multiply", [ce.number(2), b]),
|
|
40215
|
+
ce.One
|
|
40216
|
+
])
|
|
40217
|
+
]);
|
|
40218
|
+
return { value: result, because: "odd double factorial" };
|
|
40219
|
+
}
|
|
40220
|
+
}
|
|
40221
|
+
if (body.operator === "Multiply" && body.ops?.length === 2 && lower.is(1)) {
|
|
40222
|
+
const [op1, op2] = body.ops;
|
|
40223
|
+
if (op1.is(2) && op2.symbol === index || op2.is(2) && op1.symbol === index) {
|
|
40224
|
+
const b = upper;
|
|
40225
|
+
const result = ce.function("Multiply", [
|
|
40226
|
+
ce.function("Power", [ce.number(2), b]),
|
|
40227
|
+
ce.function("Factorial", [b])
|
|
40228
|
+
]);
|
|
40229
|
+
return { value: result, because: "even double factorial" };
|
|
40230
|
+
}
|
|
40231
|
+
}
|
|
40232
|
+
if (body.operator === "Add" && body.ops?.length === 2 && lower.is(0)) {
|
|
40233
|
+
let base = null;
|
|
40234
|
+
let hasIndex = false;
|
|
40235
|
+
for (const op of body.ops) {
|
|
40236
|
+
if (op.symbol === index) {
|
|
40237
|
+
hasIndex = true;
|
|
40238
|
+
} else if (!new Set(op.unknowns).has(index)) {
|
|
40239
|
+
base = op;
|
|
40240
|
+
}
|
|
40241
|
+
}
|
|
40242
|
+
if (hasIndex && base) {
|
|
40243
|
+
const n = upper.add(ce.One).simplify();
|
|
40244
|
+
const result = ce.function("Pochhammer", [base, n]);
|
|
40245
|
+
return { value: result, because: "rising factorial (Pochhammer)" };
|
|
40246
|
+
}
|
|
40247
|
+
}
|
|
40248
|
+
if (lower.is(0)) {
|
|
40249
|
+
let base = null;
|
|
40250
|
+
let hasNegIndex = false;
|
|
40251
|
+
if (body.operator === "Subtract" && body.ops?.length === 2) {
|
|
40252
|
+
const [op1, op2] = body.ops;
|
|
40253
|
+
if (op2.symbol === index && !new Set(op1.unknowns).has(index)) {
|
|
40254
|
+
base = op1;
|
|
40255
|
+
hasNegIndex = true;
|
|
40256
|
+
}
|
|
40257
|
+
} else if (body.operator === "Add" && body.ops?.length === 2) {
|
|
40258
|
+
for (const op of body.ops) {
|
|
40259
|
+
if (op.operator === "Negate" && op.op1?.symbol === index) {
|
|
40260
|
+
hasNegIndex = true;
|
|
40261
|
+
} else if (!new Set(op.unknowns).has(index)) {
|
|
40262
|
+
base = op;
|
|
40263
|
+
}
|
|
40264
|
+
}
|
|
40265
|
+
}
|
|
40266
|
+
if (hasNegIndex && base) {
|
|
40267
|
+
const n = upper.add(ce.One).simplify();
|
|
40268
|
+
const result = ce.function("Divide", [
|
|
40269
|
+
ce.function("Factorial", [base]),
|
|
40270
|
+
ce.function("Factorial", [base.sub(n)])
|
|
40271
|
+
]);
|
|
40272
|
+
return { value: result, because: "falling factorial" };
|
|
40273
|
+
}
|
|
40274
|
+
}
|
|
40275
|
+
if (body.operator === "Multiply" && body.ops) {
|
|
40276
|
+
const constantFactors = [];
|
|
40277
|
+
const indexFactors = [];
|
|
40278
|
+
for (const factor2 of body.ops) {
|
|
40279
|
+
const factorUnknowns = new Set(factor2.unknowns);
|
|
40280
|
+
if (factorUnknowns.has(index)) {
|
|
40281
|
+
indexFactors.push(factor2);
|
|
40282
|
+
} else {
|
|
40283
|
+
constantFactors.push(factor2);
|
|
40284
|
+
}
|
|
40285
|
+
}
|
|
40286
|
+
if (constantFactors.length > 0 && indexFactors.length > 0) {
|
|
40287
|
+
const constant = constantFactors.length === 1 ? constantFactors[0] : ce.function("Multiply", constantFactors);
|
|
40288
|
+
const indexPart = indexFactors.length === 1 ? indexFactors[0] : ce.function("Multiply", indexFactors);
|
|
40289
|
+
const count = upper.sub(lower).add(ce.One).simplify();
|
|
40290
|
+
const newProduct = ce.function("Product", [indexPart, limits]);
|
|
40291
|
+
return {
|
|
40292
|
+
value: constant.pow(count).mul(newProduct),
|
|
40293
|
+
because: "factor out constant from product"
|
|
40294
|
+
};
|
|
40295
|
+
}
|
|
40296
|
+
}
|
|
40297
|
+
return void 0;
|
|
40298
|
+
}
|
|
40299
|
+
|
|
38718
40300
|
// src/compute-engine/symbolic/simplify-rules.ts
|
|
38719
40301
|
var SIMPLIFY_RULES = [
|
|
38720
40302
|
// The Golden Ratio, a constant that can be simplified
|
|
38721
40303
|
"\\varphi -> \\frac{1+\\sqrt{5}}{2}",
|
|
38722
40304
|
simplifyRelationalOperator,
|
|
38723
40305
|
simplifySystemOfEquations,
|
|
40306
|
+
//
|
|
40307
|
+
// Cancel common polynomial factors in Divide expressions
|
|
40308
|
+
// e.g., (x² - 1)/(x - 1) → x + 1
|
|
40309
|
+
// Must run before expand to preserve polynomial structure
|
|
40310
|
+
//
|
|
40311
|
+
(x) => {
|
|
40312
|
+
if (x.operator !== "Divide") return void 0;
|
|
40313
|
+
const unknowns = x.unknowns;
|
|
40314
|
+
if (unknowns.length !== 1) return void 0;
|
|
40315
|
+
const variable = unknowns[0];
|
|
40316
|
+
const result = cancelCommonFactors(x, variable);
|
|
40317
|
+
if (result.isSame(x)) return void 0;
|
|
40318
|
+
return { value: result, because: "cancel common polynomial factors" };
|
|
40319
|
+
},
|
|
38724
40320
|
// Try to expand the expression:
|
|
38725
40321
|
// x*(y+z) -> x*y + x*z
|
|
38726
40322
|
// { replace: (x) => expand(x) ?? undefined, id: 'expand' },
|
|
@@ -38810,7 +40406,8 @@ var SIMPLIFY_RULES = [
|
|
|
38810
40406
|
const ce = x.engine;
|
|
38811
40407
|
if (s === void 0) return void 0;
|
|
38812
40408
|
if (s === "positive") return { value: ce.One, because: "sign positive" };
|
|
38813
|
-
if (s === "negative")
|
|
40409
|
+
if (s === "negative")
|
|
40410
|
+
return { value: ce.NegativeOne, because: "sign negative" };
|
|
38814
40411
|
if (s === "zero") return { value: ce.Zero, because: "sign zero" };
|
|
38815
40412
|
if (s === "unsigned") return { value: ce.NaN, because: "sign unsinged" };
|
|
38816
40413
|
return void 0;
|
|
@@ -38893,14 +40490,10 @@ var SIMPLIFY_RULES = [
|
|
|
38893
40490
|
because: "congruent"
|
|
38894
40491
|
};
|
|
38895
40492
|
},
|
|
38896
|
-
//
|
|
38897
|
-
|
|
38898
|
-
//
|
|
38899
|
-
|
|
38900
|
-
if (x.operator === "Max") {
|
|
38901
|
-
}
|
|
38902
|
-
return void 0;
|
|
38903
|
-
},
|
|
40493
|
+
// Sum simplification (extracted to simplify-sum.ts)
|
|
40494
|
+
simplifySum,
|
|
40495
|
+
// Product simplification (extracted to simplify-product.ts)
|
|
40496
|
+
simplifyProduct,
|
|
38904
40497
|
//
|
|
38905
40498
|
// Constructible values of trig functions
|
|
38906
40499
|
//
|
|
@@ -41126,7 +42719,8 @@ var ComputeEngine = class _ComputeEngine {
|
|
|
41126
42719
|
return BoxedType.unknown;
|
|
41127
42720
|
},
|
|
41128
42721
|
parseUnexpectedToken: (_lhs, _parser) => null,
|
|
41129
|
-
preserveLatex: false
|
|
42722
|
+
preserveLatex: false,
|
|
42723
|
+
quantifierScope: "tight"
|
|
41130
42724
|
};
|
|
41131
42725
|
const result = parse2(
|
|
41132
42726
|
asLatexString(latex) ?? latex,
|
|
@@ -41279,10 +42873,10 @@ function defToString(name, def, v) {
|
|
|
41279
42873
|
}
|
|
41280
42874
|
|
|
41281
42875
|
// src/compute-engine.ts
|
|
41282
|
-
var version = "0.
|
|
42876
|
+
var version = "0.32.1";
|
|
41283
42877
|
globalThis[Symbol.for("io.cortexjs.compute-engine")] = {
|
|
41284
42878
|
ComputeEngine: ComputeEngine.prototype.constructor,
|
|
41285
|
-
version: "0.
|
|
42879
|
+
version: "0.32.1"
|
|
41286
42880
|
};
|
|
41287
42881
|
export {
|
|
41288
42882
|
BoxedType,
|