@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
|
(function(global,factory){typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'],factory):(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ComputeEngine = {}));})(this, (function (exports) { 'use strict';
|
|
3
3
|
var ComputeEngine = (() => {
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -7869,7 +7869,11 @@ var ComputeEngine = (() => {
|
|
|
7869
7869
|
if (denom === 2) {
|
|
7870
7870
|
return serializer.serialize(["Divide", "1", ["Sqrt", base]]);
|
|
7871
7871
|
}
|
|
7872
|
-
return serializer.serialize([
|
|
7872
|
+
return serializer.serialize([
|
|
7873
|
+
"Divide",
|
|
7874
|
+
"1",
|
|
7875
|
+
["Root", base, operand(exp2, 2)]
|
|
7876
|
+
]);
|
|
7873
7877
|
}
|
|
7874
7878
|
if (denom === 2) {
|
|
7875
7879
|
return `${serializer.serialize(["Sqrt", base])}^{${serializer.serialize(
|
|
@@ -7883,13 +7887,20 @@ var ComputeEngine = (() => {
|
|
|
7883
7887
|
}
|
|
7884
7888
|
}
|
|
7885
7889
|
}
|
|
7890
|
+
const wrapNegativeBase = (latex) => latex.startsWith("-") ? serializer.wrapString(latex, "normal") : latex;
|
|
7886
7891
|
if (operator(base) === "Power") {
|
|
7887
7892
|
const baseBody = operand(base, 1);
|
|
7888
7893
|
const baseExponent = operand(base, 2);
|
|
7894
|
+
const baseBodyLatex = wrapNegativeBase(serializer.wrapShort(baseBody));
|
|
7895
|
+
const baseExponentLatex = serializer.wrapShort(baseExponent);
|
|
7889
7896
|
return `
|
|
7890
|
-
${
|
|
7897
|
+
${baseBodyLatex}^{${supsub("^", baseExponentLatex, serializer.serialize(exp2))}}`;
|
|
7891
7898
|
}
|
|
7892
|
-
return supsub(
|
|
7899
|
+
return supsub(
|
|
7900
|
+
"^",
|
|
7901
|
+
wrapNegativeBase(serializer.wrapShort(base)),
|
|
7902
|
+
serializer.serialize(exp2)
|
|
7903
|
+
);
|
|
7893
7904
|
}
|
|
7894
7905
|
var DEFINITIONS_ARITHMETIC = [
|
|
7895
7906
|
// Constants
|
|
@@ -8170,8 +8181,9 @@ var ComputeEngine = (() => {
|
|
|
8170
8181
|
},
|
|
8171
8182
|
{
|
|
8172
8183
|
name: "GCD",
|
|
8173
|
-
latexTrigger: ["\\gcd"]
|
|
8184
|
+
latexTrigger: ["\\gcd"],
|
|
8174
8185
|
// command from amsmath package
|
|
8186
|
+
kind: "function"
|
|
8175
8187
|
},
|
|
8176
8188
|
{
|
|
8177
8189
|
symbolTrigger: "gcd",
|
|
@@ -8229,9 +8241,14 @@ var ComputeEngine = (() => {
|
|
|
8229
8241
|
},
|
|
8230
8242
|
{
|
|
8231
8243
|
name: "LCM",
|
|
8232
|
-
|
|
8244
|
+
latexTrigger: ["\\lcm"],
|
|
8233
8245
|
kind: "function"
|
|
8234
8246
|
},
|
|
8247
|
+
{
|
|
8248
|
+
symbolTrigger: "lcm",
|
|
8249
|
+
kind: "function",
|
|
8250
|
+
parse: "LCM"
|
|
8251
|
+
},
|
|
8235
8252
|
{
|
|
8236
8253
|
symbolTrigger: "LCM",
|
|
8237
8254
|
kind: "function",
|
|
@@ -8505,7 +8522,11 @@ var ComputeEngine = (() => {
|
|
|
8505
8522
|
{
|
|
8506
8523
|
name: "Square",
|
|
8507
8524
|
precedence: 720,
|
|
8508
|
-
serialize: (serializer, expr) =>
|
|
8525
|
+
serialize: (serializer, expr) => {
|
|
8526
|
+
const base = serializer.wrapShort(operand(expr, 1));
|
|
8527
|
+
const wrapped = base.startsWith("-") ? serializer.wrapString(base, "normal") : base;
|
|
8528
|
+
return wrapped + "^2";
|
|
8529
|
+
}
|
|
8509
8530
|
},
|
|
8510
8531
|
{
|
|
8511
8532
|
latexTrigger: ["\\sum"],
|
|
@@ -10615,40 +10636,43 @@ var ComputeEngine = (() => {
|
|
|
10615
10636
|
parse: "False"
|
|
10616
10637
|
},
|
|
10617
10638
|
// Operators
|
|
10639
|
+
// Logic operators have lower precedence than comparisons (245)
|
|
10640
|
+
// so that `x = 1 \lor x = 2` parses as `(x = 1) \lor (x = 2)`
|
|
10641
|
+
// See https://github.com/cortex-js/compute-engine/issues/243
|
|
10618
10642
|
{
|
|
10619
10643
|
name: "And",
|
|
10620
10644
|
kind: "infix",
|
|
10621
10645
|
latexTrigger: ["\\land"],
|
|
10622
|
-
precedence:
|
|
10646
|
+
precedence: 235
|
|
10623
10647
|
// serialize: '\\land',
|
|
10624
10648
|
},
|
|
10625
|
-
{ kind: "infix", latexTrigger: ["\\wedge"], parse: "And", precedence:
|
|
10626
|
-
{ kind: "infix", latexTrigger: "\\&", parse: "And", precedence:
|
|
10649
|
+
{ kind: "infix", latexTrigger: ["\\wedge"], parse: "And", precedence: 235 },
|
|
10650
|
+
{ kind: "infix", latexTrigger: "\\&", parse: "And", precedence: 235 },
|
|
10627
10651
|
{
|
|
10628
10652
|
kind: "infix",
|
|
10629
10653
|
latexTrigger: "\\operatorname{and}",
|
|
10630
10654
|
parse: "And",
|
|
10631
|
-
precedence:
|
|
10655
|
+
precedence: 235
|
|
10632
10656
|
},
|
|
10633
10657
|
{
|
|
10634
10658
|
name: "Or",
|
|
10635
10659
|
kind: "infix",
|
|
10636
10660
|
latexTrigger: ["\\lor"],
|
|
10637
|
-
precedence:
|
|
10661
|
+
precedence: 230
|
|
10638
10662
|
},
|
|
10639
|
-
{ kind: "infix", latexTrigger: ["\\vee"], parse: "Or", precedence:
|
|
10640
|
-
{ kind: "infix", latexTrigger: "\\parallel", parse: "Or", precedence:
|
|
10663
|
+
{ kind: "infix", latexTrigger: ["\\vee"], parse: "Or", precedence: 230 },
|
|
10664
|
+
{ kind: "infix", latexTrigger: "\\parallel", parse: "Or", precedence: 230 },
|
|
10641
10665
|
{
|
|
10642
10666
|
kind: "infix",
|
|
10643
10667
|
latexTrigger: "\\operatorname{or}",
|
|
10644
10668
|
parse: "Or",
|
|
10645
|
-
precedence:
|
|
10669
|
+
precedence: 230
|
|
10646
10670
|
},
|
|
10647
10671
|
{
|
|
10648
10672
|
name: "Xor",
|
|
10649
10673
|
kind: "infix",
|
|
10650
10674
|
latexTrigger: ["\\veebar"],
|
|
10651
|
-
precedence:
|
|
10675
|
+
precedence: 232
|
|
10652
10676
|
},
|
|
10653
10677
|
// Possible alt: \oplus ⊕ U+2295
|
|
10654
10678
|
{
|
|
@@ -10667,7 +10691,7 @@ var ComputeEngine = (() => {
|
|
|
10667
10691
|
name: "Nand",
|
|
10668
10692
|
kind: "infix",
|
|
10669
10693
|
latexTrigger: ["\\barwedge"],
|
|
10670
|
-
precedence:
|
|
10694
|
+
precedence: 232
|
|
10671
10695
|
// serialize: '\\mid',
|
|
10672
10696
|
},
|
|
10673
10697
|
{
|
|
@@ -10675,7 +10699,7 @@ var ComputeEngine = (() => {
|
|
|
10675
10699
|
kind: "infix",
|
|
10676
10700
|
latexTrigger: ["\u22BD"],
|
|
10677
10701
|
// bar vee
|
|
10678
|
-
precedence:
|
|
10702
|
+
precedence: 232
|
|
10679
10703
|
// serialize: '\\downarrow',
|
|
10680
10704
|
},
|
|
10681
10705
|
// Functions
|
|
@@ -10771,7 +10795,7 @@ var ComputeEngine = (() => {
|
|
|
10771
10795
|
latexTrigger: ["\\forall"],
|
|
10772
10796
|
precedence: 200,
|
|
10773
10797
|
// Has to be lower than COMPARISON_PRECEDENCE
|
|
10774
|
-
serialize: "\\forall",
|
|
10798
|
+
serialize: serializeQuantifier("\\forall"),
|
|
10775
10799
|
parse: parseQuantifier("ForAll")
|
|
10776
10800
|
},
|
|
10777
10801
|
{
|
|
@@ -10780,7 +10804,7 @@ var ComputeEngine = (() => {
|
|
|
10780
10804
|
latexTrigger: ["\\exists"],
|
|
10781
10805
|
precedence: 200,
|
|
10782
10806
|
// Has to be lower than COMPARISON_PRECEDENCE,
|
|
10783
|
-
serialize: "\\exists",
|
|
10807
|
+
serialize: serializeQuantifier("\\exists"),
|
|
10784
10808
|
parse: parseQuantifier("Exists")
|
|
10785
10809
|
},
|
|
10786
10810
|
{
|
|
@@ -10789,7 +10813,7 @@ var ComputeEngine = (() => {
|
|
|
10789
10813
|
latexTrigger: ["\\exists", "!"],
|
|
10790
10814
|
precedence: 200,
|
|
10791
10815
|
// Has to be lower than COMPARISON_PRECEDENCE,
|
|
10792
|
-
serialize: "\\exists!",
|
|
10816
|
+
serialize: serializeQuantifier("\\exists!"),
|
|
10793
10817
|
parse: parseQuantifier("ExistsUnique")
|
|
10794
10818
|
},
|
|
10795
10819
|
{
|
|
@@ -10798,7 +10822,7 @@ var ComputeEngine = (() => {
|
|
|
10798
10822
|
latexTrigger: ["\\lnot", "\\forall"],
|
|
10799
10823
|
precedence: 200,
|
|
10800
10824
|
// Has to be lower than COMPARISON_PRECEDENCE
|
|
10801
|
-
serialize: "\\lnot\\forall",
|
|
10825
|
+
serialize: serializeQuantifier("\\lnot\\forall"),
|
|
10802
10826
|
parse: parseQuantifier("NotForAll")
|
|
10803
10827
|
},
|
|
10804
10828
|
{
|
|
@@ -10807,7 +10831,7 @@ var ComputeEngine = (() => {
|
|
|
10807
10831
|
latexTrigger: ["\\lnot", "\\exists"],
|
|
10808
10832
|
precedence: 200,
|
|
10809
10833
|
// Has to be lower than COMPARISON_PRECEDENCE,
|
|
10810
|
-
serialize: "\\lnot\\exists",
|
|
10834
|
+
serialize: serializeQuantifier("\\lnot\\exists"),
|
|
10811
10835
|
parse: parseQuantifier("NotExists")
|
|
10812
10836
|
},
|
|
10813
10837
|
{
|
|
@@ -10868,19 +10892,53 @@ var ComputeEngine = (() => {
|
|
|
10868
10892
|
if (!DEFINITIONS_INEQUALITIES.some((x) => x.name === h)) return null;
|
|
10869
10893
|
return ["Boole", body];
|
|
10870
10894
|
}
|
|
10895
|
+
},
|
|
10896
|
+
// Predicate application in First-Order Logic.
|
|
10897
|
+
// ["Predicate", "P", "x", "y"] serializes to "P(x, y)"
|
|
10898
|
+
{
|
|
10899
|
+
name: "Predicate",
|
|
10900
|
+
serialize: (serializer, expr) => {
|
|
10901
|
+
const args = operands(expr);
|
|
10902
|
+
if (args.length === 0) return "";
|
|
10903
|
+
const pred = args[0];
|
|
10904
|
+
const predStr = typeof pred === "string" ? pred : serializer.serialize(pred);
|
|
10905
|
+
if (args.length === 1) return predStr;
|
|
10906
|
+
const argStrs = args.slice(1).map((arg) => serializer.serialize(arg));
|
|
10907
|
+
return `${predStr}(${argStrs.join(", ")})`;
|
|
10908
|
+
}
|
|
10871
10909
|
}
|
|
10872
10910
|
];
|
|
10911
|
+
function serializeQuantifier(quantifierSymbol) {
|
|
10912
|
+
return (serializer, expr) => {
|
|
10913
|
+
const args = operands(expr);
|
|
10914
|
+
if (args.length === 0) return quantifierSymbol;
|
|
10915
|
+
if (args.length === 1)
|
|
10916
|
+
return `${quantifierSymbol} ${serializer.serialize(args[0])}`;
|
|
10917
|
+
const boundVar = serializer.serialize(args[0]);
|
|
10918
|
+
const body = serializer.serialize(args[1]);
|
|
10919
|
+
return `${quantifierSymbol} ${boundVar}, ${body}`;
|
|
10920
|
+
};
|
|
10921
|
+
}
|
|
10922
|
+
function tightBindingCondition(p, terminator) {
|
|
10923
|
+
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);
|
|
10924
|
+
}
|
|
10873
10925
|
function parseQuantifier(kind) {
|
|
10874
10926
|
return (parser, terminator) => {
|
|
10875
10927
|
const index = parser.index;
|
|
10928
|
+
const useTightBinding = parser.options.quantifierScope !== "loose";
|
|
10876
10929
|
const symbol2 = parser.parseSymbol(terminator);
|
|
10877
10930
|
if (symbol2) {
|
|
10878
10931
|
parser.skipSpace();
|
|
10879
10932
|
if (parser.match(",") || parser.match("\\mid") || parser.match(".") || parser.match(":") || parser.match("\\colon")) {
|
|
10880
|
-
const
|
|
10933
|
+
const bodyTerminator = useTightBinding ? { ...terminator, condition: (p) => tightBindingCondition(p, terminator) } : terminator;
|
|
10934
|
+
parser.enterQuantifierScope();
|
|
10935
|
+
const body2 = parser.parseExpression(bodyTerminator);
|
|
10936
|
+
parser.exitQuantifierScope();
|
|
10881
10937
|
return [kind, symbol2, missingIfEmpty(body2)];
|
|
10882
10938
|
}
|
|
10939
|
+
parser.enterQuantifierScope();
|
|
10883
10940
|
const body = parser.parseEnclosure();
|
|
10941
|
+
parser.exitQuantifierScope();
|
|
10884
10942
|
if (body) return [kind, symbol2, missingIfEmpty(body)];
|
|
10885
10943
|
}
|
|
10886
10944
|
parser.index = index;
|
|
@@ -10888,11 +10946,16 @@ var ComputeEngine = (() => {
|
|
|
10888
10946
|
if (condition === null) return null;
|
|
10889
10947
|
parser.skipSpace();
|
|
10890
10948
|
if (parser.matchAny([",", "\\mid", ":", "\\colon"])) {
|
|
10891
|
-
const
|
|
10949
|
+
const bodyTerminator = useTightBinding ? { ...terminator, condition: (p) => tightBindingCondition(p, terminator) } : terminator;
|
|
10950
|
+
parser.enterQuantifierScope();
|
|
10951
|
+
const body = parser.parseExpression(bodyTerminator);
|
|
10952
|
+
parser.exitQuantifierScope();
|
|
10892
10953
|
return [kind, condition, missingIfEmpty(body)];
|
|
10893
10954
|
}
|
|
10894
10955
|
if (parser.match("(")) {
|
|
10956
|
+
parser.enterQuantifierScope();
|
|
10895
10957
|
const body = parser.parseExpression(terminator);
|
|
10958
|
+
parser.exitQuantifierScope();
|
|
10896
10959
|
if (!parser.match(")")) return null;
|
|
10897
10960
|
return [kind, condition, missingIfEmpty(body)];
|
|
10898
10961
|
}
|
|
@@ -11381,7 +11444,7 @@ var ComputeEngine = (() => {
|
|
|
11381
11444
|
"\\ch": "Cosh",
|
|
11382
11445
|
// Non-standard
|
|
11383
11446
|
"\\cos": "Cos",
|
|
11384
|
-
"\\cosh": "
|
|
11447
|
+
"\\cosh": "Cosh",
|
|
11385
11448
|
"\\cosec": "Csc",
|
|
11386
11449
|
// Non-standard
|
|
11387
11450
|
"\\cot": "Cot",
|
|
@@ -13293,8 +13356,41 @@ var ComputeEngine = (() => {
|
|
|
13293
13356
|
return parser.error(["invalid-symbol", { str: validateSymbol(id) }], start);
|
|
13294
13357
|
}
|
|
13295
13358
|
function parseSymbol(parser) {
|
|
13296
|
-
if (/^[a-zA-Z]$/.test(parser.peek) || /^\p{XIDS}$/u.test(parser.peek))
|
|
13297
|
-
|
|
13359
|
+
if (/^[a-zA-Z]$/.test(parser.peek) || /^\p{XIDS}$/u.test(parser.peek)) {
|
|
13360
|
+
let id2 = parser.nextToken();
|
|
13361
|
+
while (!parser.atEnd) {
|
|
13362
|
+
const currentPeek = parser.peek;
|
|
13363
|
+
if (currentPeek !== "_") break;
|
|
13364
|
+
const underscoreIndex = parser.index;
|
|
13365
|
+
parser.nextToken();
|
|
13366
|
+
const hasBrace = parser.match("<{>");
|
|
13367
|
+
if (hasBrace) {
|
|
13368
|
+
const firstToken = parser.peek;
|
|
13369
|
+
if (firstToken === "(" || firstToken === "\\lparen" || firstToken === "\\left") {
|
|
13370
|
+
parser.index = underscoreIndex;
|
|
13371
|
+
break;
|
|
13372
|
+
}
|
|
13373
|
+
const sub2 = parseSymbolBody(parser);
|
|
13374
|
+
const hasOperators = sub2 !== null && /plus|minus|times|ast/.test(sub2);
|
|
13375
|
+
if (sub2 === null || sub2.includes(",") || hasOperators || parser.peek !== "<}>") {
|
|
13376
|
+
parser.index = underscoreIndex;
|
|
13377
|
+
break;
|
|
13378
|
+
}
|
|
13379
|
+
parser.match("<}>");
|
|
13380
|
+
id2 += "_" + sub2;
|
|
13381
|
+
} else {
|
|
13382
|
+
const subToken = parser.peek;
|
|
13383
|
+
if (/^[a-zA-Z0-9]$/.test(subToken) || /^\p{XIDS}$/u.test(subToken)) {
|
|
13384
|
+
parser.nextToken();
|
|
13385
|
+
id2 += "_" + subToken;
|
|
13386
|
+
} else {
|
|
13387
|
+
parser.index = underscoreIndex;
|
|
13388
|
+
break;
|
|
13389
|
+
}
|
|
13390
|
+
}
|
|
13391
|
+
}
|
|
13392
|
+
return id2;
|
|
13393
|
+
}
|
|
13298
13394
|
let id = matchPrefixedSymbol(parser);
|
|
13299
13395
|
if (!id) {
|
|
13300
13396
|
id = "";
|
|
@@ -13394,6 +13490,18 @@ var ComputeEngine = (() => {
|
|
|
13394
13490
|
throw new Error(`Symbol ${id} already declared as a different type`);
|
|
13395
13491
|
this.symbolTable.ids[id] = type2;
|
|
13396
13492
|
}
|
|
13493
|
+
// Track whether we're inside a quantifier body (ForAll, Exists, etc.)
|
|
13494
|
+
// When true, single uppercase letters followed by () are parsed as predicates
|
|
13495
|
+
_quantifierScopeDepth = 0;
|
|
13496
|
+
get inQuantifierScope() {
|
|
13497
|
+
return this._quantifierScopeDepth > 0;
|
|
13498
|
+
}
|
|
13499
|
+
enterQuantifierScope() {
|
|
13500
|
+
this._quantifierScopeDepth++;
|
|
13501
|
+
}
|
|
13502
|
+
exitQuantifierScope() {
|
|
13503
|
+
if (this._quantifierScopeDepth > 0) this._quantifierScopeDepth--;
|
|
13504
|
+
}
|
|
13397
13505
|
get index() {
|
|
13398
13506
|
return this._index;
|
|
13399
13507
|
}
|
|
@@ -14279,9 +14387,10 @@ var ComputeEngine = (() => {
|
|
|
14279
14387
|
this.skipSpace();
|
|
14280
14388
|
let body = this.parseExpression();
|
|
14281
14389
|
this.skipSpace();
|
|
14282
|
-
|
|
14283
|
-
|
|
14284
|
-
|
|
14390
|
+
const boundary = this._boundaries[this._boundaries.length - 1]?.tokens;
|
|
14391
|
+
const matchedBoundary = this.matchBoundary();
|
|
14392
|
+
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]);
|
|
14393
|
+
if (matchedBoundary && isEmptySequence(body) && sameTrigger && boundary) {
|
|
14285
14394
|
this.index = bodyStart;
|
|
14286
14395
|
this.skipSpace();
|
|
14287
14396
|
body = this.parseExpression();
|
|
@@ -14291,6 +14400,18 @@ var ComputeEngine = (() => {
|
|
|
14291
14400
|
if (!this.atEnd) continue;
|
|
14292
14401
|
return null;
|
|
14293
14402
|
}
|
|
14403
|
+
} else if (!matchedBoundary) {
|
|
14404
|
+
const boundary2 = this._boundaries[this._boundaries.length - 1].tokens;
|
|
14405
|
+
this.removeBoundary();
|
|
14406
|
+
this.index = bodyStart;
|
|
14407
|
+
this.skipSpace();
|
|
14408
|
+
body = this.parseExpression();
|
|
14409
|
+
this.skipSpace();
|
|
14410
|
+
if (!this.matchAll(boundary2)) {
|
|
14411
|
+
this.index = start;
|
|
14412
|
+
if (!this.atEnd) continue;
|
|
14413
|
+
return null;
|
|
14414
|
+
}
|
|
14294
14415
|
}
|
|
14295
14416
|
const result = def.parse(this, body ?? "Nothing");
|
|
14296
14417
|
if (result !== null) return result;
|
|
@@ -14339,12 +14460,16 @@ var ComputeEngine = (() => {
|
|
|
14339
14460
|
break;
|
|
14340
14461
|
}
|
|
14341
14462
|
}
|
|
14463
|
+
let isPredicate = false;
|
|
14342
14464
|
if (fn === null) {
|
|
14343
14465
|
this.index = start;
|
|
14344
14466
|
fn = parseSymbol(this);
|
|
14345
14467
|
if (!this.isFunctionOperator(fn)) {
|
|
14346
|
-
this.
|
|
14347
|
-
|
|
14468
|
+
if (!this.looksLikePredicate(fn)) {
|
|
14469
|
+
this.index = start;
|
|
14470
|
+
return null;
|
|
14471
|
+
}
|
|
14472
|
+
isPredicate = true;
|
|
14348
14473
|
}
|
|
14349
14474
|
}
|
|
14350
14475
|
do {
|
|
@@ -14354,6 +14479,10 @@ var ComputeEngine = (() => {
|
|
|
14354
14479
|
} while (true);
|
|
14355
14480
|
const args = this.parseArguments("enclosure", until);
|
|
14356
14481
|
if (args === null) return fn;
|
|
14482
|
+
if (isPredicate && typeof fn === "string") {
|
|
14483
|
+
if (this.inQuantifierScope || fn === "D" || fn === "N")
|
|
14484
|
+
return ["Predicate", fn, ...args];
|
|
14485
|
+
}
|
|
14357
14486
|
return typeof fn === "string" ? [fn, ...args] : ["Apply", fn, ...args];
|
|
14358
14487
|
}
|
|
14359
14488
|
parseSymbol(until) {
|
|
@@ -14742,9 +14871,24 @@ var ComputeEngine = (() => {
|
|
|
14742
14871
|
}
|
|
14743
14872
|
isFunctionOperator(id) {
|
|
14744
14873
|
if (id === null) return false;
|
|
14874
|
+
if (id === "D" || id === "N") return false;
|
|
14745
14875
|
if (this.getSymbolType(id).matches("function")) return true;
|
|
14746
14876
|
return false;
|
|
14747
14877
|
}
|
|
14878
|
+
/**
|
|
14879
|
+
* Check if a symbol looks like a predicate in First-Order Logic.
|
|
14880
|
+
* A predicate is typically a single uppercase letter (P, Q, R, etc.)
|
|
14881
|
+
* followed by parentheses containing arguments.
|
|
14882
|
+
*
|
|
14883
|
+
* This enables automatic inference of predicates without explicit declaration,
|
|
14884
|
+
* so `\forall x. P(x)` works without having to declare `P` as a function.
|
|
14885
|
+
*/
|
|
14886
|
+
looksLikePredicate(id) {
|
|
14887
|
+
if (id === null || typeof id !== "string") return false;
|
|
14888
|
+
if (!/^[A-Z]$/.test(id)) return false;
|
|
14889
|
+
this.skipSpace();
|
|
14890
|
+
return this.peek === "(" || this.peek === "\\left";
|
|
14891
|
+
}
|
|
14748
14892
|
/** Return all defs of the specified kind.
|
|
14749
14893
|
* The defs at the end of the dictionary have priority, since they may
|
|
14750
14894
|
* override previous definitions. (For example, there is a core definition
|
|
@@ -18627,7 +18771,10 @@ var ComputeEngine = (() => {
|
|
|
18627
18771
|
if (op === "Power") {
|
|
18628
18772
|
const baseDeg = polynomialDegree(expr.op1, variable);
|
|
18629
18773
|
if (baseDeg < 0) return -1;
|
|
18630
|
-
if (baseDeg === 0)
|
|
18774
|
+
if (baseDeg === 0) {
|
|
18775
|
+
if (expr.op2.has(variable)) return -1;
|
|
18776
|
+
return 0;
|
|
18777
|
+
}
|
|
18631
18778
|
const exp2 = asSmallInteger(expr.op2);
|
|
18632
18779
|
if (exp2 === null || exp2 < 0) return -1;
|
|
18633
18780
|
return baseDeg * exp2;
|
|
@@ -21666,8 +21813,6 @@ var ComputeEngine = (() => {
|
|
|
21666
21813
|
}
|
|
21667
21814
|
if (index.operator === "Hold") index = index.op1;
|
|
21668
21815
|
if (!index.symbol) index = ce.typeError("symbol", index.type, index);
|
|
21669
|
-
if (lower.symbol !== "Nothing") lower = checkType(ce, lower, "number");
|
|
21670
|
-
if (upper.symbol !== "Nothing") upper = checkType(ce, upper, "number");
|
|
21671
21816
|
return ce._fn("Limits", [index, lower, upper]);
|
|
21672
21817
|
}
|
|
21673
21818
|
return null;
|
|
@@ -22546,10 +22691,6 @@ var ComputeEngine = (() => {
|
|
|
22546
22691
|
fractionalPart = options.decimalSeparator + fractionalPart;
|
|
22547
22692
|
wholePart = insertWholeGroupSeparator(wholePart, options);
|
|
22548
22693
|
if (!expString) return wholePart + fractionalPart;
|
|
22549
|
-
if (!fractionalPart) {
|
|
22550
|
-
if (wholePart === "1") return expString;
|
|
22551
|
-
if (wholePart === "-1") return "-" + expString;
|
|
22552
|
-
}
|
|
22553
22694
|
return wholePart + fractionalPart + options.exponentProduct + expString;
|
|
22554
22695
|
}
|
|
22555
22696
|
function serializeAutoNotationNumber(valString, options) {
|
|
@@ -23056,7 +23197,8 @@ var ComputeEngine = (() => {
|
|
|
23056
23197
|
Negate: [
|
|
23057
23198
|
(expr, serialize) => {
|
|
23058
23199
|
const base = serialize(expr.op1, 14);
|
|
23059
|
-
|
|
23200
|
+
const op = expr.op1?.operator;
|
|
23201
|
+
if (op === "Power" || op === "Square") return `-(${base})`;
|
|
23060
23202
|
return `-${base}`;
|
|
23061
23203
|
},
|
|
23062
23204
|
14
|
|
@@ -23277,11 +23419,11 @@ var ComputeEngine = (() => {
|
|
|
23277
23419
|
const b = fn.op1 ?? fn;
|
|
23278
23420
|
if (b.operator === "Block") body = serialize(b.op1 ?? b);
|
|
23279
23421
|
else body = serialize(b);
|
|
23280
|
-
} else if (fn
|
|
23422
|
+
} else if (fn) {
|
|
23281
23423
|
args = [];
|
|
23282
23424
|
body = serialize(fn);
|
|
23283
23425
|
} else {
|
|
23284
|
-
return
|
|
23426
|
+
return `${op}()`;
|
|
23285
23427
|
}
|
|
23286
23428
|
let result = op;
|
|
23287
23429
|
for (const limit2 of limits) {
|
|
@@ -25397,7 +25539,7 @@ ${lines.join("\n")}`;
|
|
|
25397
25539
|
description: "Rounds a number up to the next largest integer",
|
|
25398
25540
|
complexity: 1250,
|
|
25399
25541
|
broadcastable: true,
|
|
25400
|
-
signature: "(
|
|
25542
|
+
signature: "(number) -> integer",
|
|
25401
25543
|
sgn: ([x]) => {
|
|
25402
25544
|
if (x.isLessEqual(-1)) return "negative";
|
|
25403
25545
|
if (x.isPositive) return "positive";
|
|
@@ -26439,38 +26581,29 @@ ${lines.join("\n")}`;
|
|
|
26439
26581
|
signature: "((number+) -> number, (tuple<integer>|tuple<integer, integer>)+) -> number",
|
|
26440
26582
|
canonical: ([body, ...bounds], { scope }) => canonicalBigop("Product", body, bounds, scope),
|
|
26441
26583
|
evaluate: (ops, options) => {
|
|
26442
|
-
const fn = (acc, x) => {
|
|
26443
|
-
x = x.evaluate(options);
|
|
26444
|
-
return x.isNumberLiteral ? acc.mul(x.numericValue) : null;
|
|
26445
|
-
};
|
|
26446
26584
|
const result = run(
|
|
26447
26585
|
reduceBigOp(
|
|
26448
26586
|
ops[0],
|
|
26449
26587
|
ops.slice(1),
|
|
26450
|
-
|
|
26451
|
-
options.engine.
|
|
26588
|
+
(acc, x) => acc.mul(x.evaluate(options)),
|
|
26589
|
+
options.engine.One
|
|
26452
26590
|
),
|
|
26453
26591
|
options.engine._timeRemaining
|
|
26454
26592
|
);
|
|
26455
|
-
return options.engine.
|
|
26593
|
+
return result?.evaluate() ?? options.engine.NaN;
|
|
26456
26594
|
},
|
|
26457
26595
|
evaluateAsync: async (ops, options) => {
|
|
26458
|
-
const fn = (acc, x) => {
|
|
26459
|
-
x = x.evaluate(options);
|
|
26460
|
-
if (!x.isNumberLiteral) return null;
|
|
26461
|
-
return acc.mul(x.numericValue);
|
|
26462
|
-
};
|
|
26463
26596
|
const result = await runAsync(
|
|
26464
26597
|
reduceBigOp(
|
|
26465
26598
|
ops[0],
|
|
26466
26599
|
ops.slice(1),
|
|
26467
|
-
|
|
26468
|
-
options.engine.
|
|
26600
|
+
(acc, x) => acc.mul(x.evaluate(options)),
|
|
26601
|
+
options.engine.One
|
|
26469
26602
|
),
|
|
26470
26603
|
options.engine._timeRemaining,
|
|
26471
26604
|
options.signal
|
|
26472
26605
|
);
|
|
26473
|
-
return options.engine.
|
|
26606
|
+
return result?.evaluate() ?? options.engine.NaN;
|
|
26474
26607
|
}
|
|
26475
26608
|
},
|
|
26476
26609
|
Sum: {
|
|
@@ -26482,36 +26615,31 @@ ${lines.join("\n")}`;
|
|
|
26482
26615
|
lazy: true,
|
|
26483
26616
|
signature: "((number) -> number, bounds:tuple+) -> number",
|
|
26484
26617
|
canonical: ([body, ...bounds], { scope }) => canonicalBigop("Sum", body, bounds, scope),
|
|
26485
|
-
evaluate: ([
|
|
26486
|
-
run(
|
|
26618
|
+
evaluate: ([body, ...indexes], { engine }) => {
|
|
26619
|
+
const result = run(
|
|
26487
26620
|
reduceBigOp(
|
|
26488
|
-
|
|
26621
|
+
body,
|
|
26489
26622
|
indexes,
|
|
26490
|
-
(acc, x) =>
|
|
26491
|
-
|
|
26492
|
-
return x.isNumberLiteral ? acc.add(x.numericValue) : null;
|
|
26493
|
-
},
|
|
26494
|
-
engine._numericValue(0)
|
|
26623
|
+
(acc, x) => acc.add(x.evaluate()),
|
|
26624
|
+
engine.Zero
|
|
26495
26625
|
),
|
|
26496
26626
|
engine._timeRemaining
|
|
26497
|
-
)
|
|
26498
|
-
|
|
26499
|
-
|
|
26500
|
-
|
|
26627
|
+
);
|
|
26628
|
+
return result?.evaluate() ?? engine.NaN;
|
|
26629
|
+
},
|
|
26630
|
+
evaluateAsync: async (xs, { engine, signal }) => {
|
|
26631
|
+
const result = await runAsync(
|
|
26501
26632
|
reduceBigOp(
|
|
26502
26633
|
xs[0],
|
|
26503
26634
|
xs.slice(1),
|
|
26504
|
-
(acc, x) =>
|
|
26505
|
-
|
|
26506
|
-
if (!x.isNumberLiteral) return null;
|
|
26507
|
-
return acc.add(x.numericValue);
|
|
26508
|
-
},
|
|
26509
|
-
engine._numericValue(0)
|
|
26635
|
+
(acc, x) => acc.add(x.evaluate()),
|
|
26636
|
+
engine.Zero
|
|
26510
26637
|
),
|
|
26511
26638
|
engine._timeRemaining,
|
|
26512
26639
|
signal
|
|
26513
|
-
)
|
|
26514
|
-
|
|
26640
|
+
);
|
|
26641
|
+
return result?.evaluate() ?? engine.NaN;
|
|
26642
|
+
}
|
|
26515
26643
|
}
|
|
26516
26644
|
}
|
|
26517
26645
|
];
|
|
@@ -26701,17 +26829,12 @@ ${lines.join("\n")}`;
|
|
|
26701
26829
|
Ln: ["Divide", 1, "_"],
|
|
26702
26830
|
Log: ["Power", ["Multiply", "_", ["Ln", "10"]], -1],
|
|
26703
26831
|
Sqrt: ["Multiply", ["Power", "_", ["Negate", "Half"]], "Half"],
|
|
26704
|
-
|
|
26705
|
-
|
|
26706
|
-
|
|
26707
|
-
|
|
26708
|
-
|
|
26709
|
-
|
|
26710
|
-
["Greater", "_", 0],
|
|
26711
|
-
1,
|
|
26712
|
-
"True",
|
|
26713
|
-
["D", ["Abs", "_"], "_"]
|
|
26714
|
-
],
|
|
26832
|
+
// d/dx |x| = x/|x| = sign(x) for x ≠ 0 (undefined at x = 0)
|
|
26833
|
+
Abs: ["Sign", "_"],
|
|
26834
|
+
// Step functions: derivative is 0 almost everywhere (undefined at discontinuities)
|
|
26835
|
+
Floor: 0,
|
|
26836
|
+
Ceil: 0,
|
|
26837
|
+
Round: 0,
|
|
26715
26838
|
// https://proofwiki.org/wiki/Derivative_of_Error_Function
|
|
26716
26839
|
Erf: [
|
|
26717
26840
|
"Multiply",
|
|
@@ -26720,51 +26843,36 @@ ${lines.join("\n")}`;
|
|
|
26720
26843
|
],
|
|
26721
26844
|
// https://proofwiki.org/wiki/Derivative_of_Gamma_Function
|
|
26722
26845
|
// https://en.wikipedia.org/wiki/Gamma_function
|
|
26846
|
+
// d/dx Γ(x) = Γ(x)·ψ(x) where ψ is the digamma function
|
|
26723
26847
|
Gamma: ["Multiply", ["Gamma", "_"], ["Digamma", "_"]],
|
|
26724
|
-
|
|
26725
|
-
"Add",
|
|
26726
|
-
["Multiply", ["Digamma", "_"], ["Gamma", "_"]],
|
|
26727
|
-
["Multiply", ["Power", "_", -1], ["Gamma", "_"]]
|
|
26728
|
-
],
|
|
26729
|
-
Zeta: ["Multiply", ["Multiply", -1, ["Zeta", "_"]], ["Digamma", "_"]],
|
|
26730
|
-
PolyGamma: [
|
|
26731
|
-
"Add",
|
|
26732
|
-
["Multiply", ["PolyGamma", "_"], ["Gamma", "_"]],
|
|
26733
|
-
["Multiply", ["Power", "_", -1], ["Gamma", "_"]]
|
|
26734
|
-
],
|
|
26735
|
-
Beta: [
|
|
26736
|
-
"Multiply",
|
|
26737
|
-
[
|
|
26738
|
-
"Add",
|
|
26739
|
-
["Multiply", ["Beta", "_"], ["Digamma", "_"]],
|
|
26740
|
-
["Multiply", ["Power", "_", -1], ["Beta", "_"]]
|
|
26741
|
-
],
|
|
26742
|
-
["Beta", "_"]
|
|
26743
|
-
],
|
|
26848
|
+
// d/dx erfc(x) = -d/dx erf(x) = -2/√π * e^(-x²)
|
|
26744
26849
|
Erfc: [
|
|
26745
|
-
"
|
|
26746
|
-
["Negate", ["
|
|
26747
|
-
["Exp", ["Negate", ["Power", "_", 2]]],
|
|
26748
|
-
["Power", "_", -1]
|
|
26850
|
+
"Negate",
|
|
26851
|
+
["Multiply", ["Divide", 2, ["Sqrt", "Pi"]], ["Exp", ["Negate", ["Square", "_"]]]]
|
|
26749
26852
|
],
|
|
26750
|
-
|
|
26853
|
+
// d/dx ln(Γ(x)) = ψ(x) (digamma function)
|
|
26854
|
+
LogGamma: ["Digamma", "_"],
|
|
26855
|
+
// Note: LambertW derivative d/dx W(x) = W(x)/(x·(1+W(x))) is mathematically correct
|
|
26856
|
+
// but omitted because LambertW lacks a type signature, causing type errors.
|
|
26857
|
+
//
|
|
26858
|
+
// d/dx S(x) = sin(πx²/2) where S is the Fresnel sine integral
|
|
26859
|
+
FresnelS: ["Sin", ["Multiply", ["Divide", "Pi", 2], ["Square", "_"]]],
|
|
26860
|
+
// d/dx C(x) = cos(πx²/2) where C is the Fresnel cosine integral
|
|
26861
|
+
FresnelC: ["Cos", ["Multiply", ["Divide", "Pi", 2], ["Square", "_"]]],
|
|
26862
|
+
// d/dx erfi(x) = (2/√π)·e^(x²) where erfi is the imaginary error function
|
|
26863
|
+
Erfi: [
|
|
26751
26864
|
"Multiply",
|
|
26752
|
-
["
|
|
26753
|
-
[
|
|
26754
|
-
|
|
26755
|
-
|
|
26756
|
-
|
|
26757
|
-
|
|
26758
|
-
|
|
26759
|
-
|
|
26760
|
-
|
|
26761
|
-
|
|
26762
|
-
|
|
26763
|
-
BesselI: ["Multiply", ["BesselI", "_"], ["BesselK", "_"]],
|
|
26764
|
-
BesselK: ["Multiply", ["BesselI", "_"], ["BesselK", "_"]],
|
|
26765
|
-
FresnelS: ["Multiply", ["FresnelS", "_"], ["FresnelC", "_"]],
|
|
26766
|
-
FresnelC: ["Multiply", ["FresnelS", "_"], ["FresnelC", "_"]],
|
|
26767
|
-
Erfi: ["Multiply", ["Erfi", "_"], ["Erf", "_"]]
|
|
26865
|
+
["Divide", 2, ["Sqrt", "Pi"]],
|
|
26866
|
+
["Exp", ["Square", "_"]]
|
|
26867
|
+
]
|
|
26868
|
+
// Note: Bessel functions (BesselJ, BesselY, BesselI, BesselK) and Airy functions
|
|
26869
|
+
// (AiryAi, AiryBi) have been omitted because their derivatives involve functions
|
|
26870
|
+
// of different orders or related derivative functions that are not in the standard
|
|
26871
|
+
// function set. For example, d/dx J_n(x) = (J_{n-1}(x) - J_{n+1}(x))/2.
|
|
26872
|
+
//
|
|
26873
|
+
// Similarly, Zeta, Digamma, PolyGamma, and Beta derivatives are omitted because
|
|
26874
|
+
// they either don't have simple closed forms or involve additional functions not
|
|
26875
|
+
// in the standard set (trigamma function, etc.).
|
|
26768
26876
|
};
|
|
26769
26877
|
function derivative(fn, order2) {
|
|
26770
26878
|
if (order2 === 0) return fn;
|
|
@@ -26817,6 +26925,15 @@ ${lines.join("\n")}`;
|
|
|
26817
26925
|
if (terms.some((term) => term === void 0)) return void 0;
|
|
26818
26926
|
return simplifyDerivative(add3(...terms));
|
|
26819
26927
|
}
|
|
26928
|
+
if (expr.operator === "Root") {
|
|
26929
|
+
const [base, n] = expr.ops;
|
|
26930
|
+
if (!base.has(v)) return ce.Zero;
|
|
26931
|
+
const exponent = ce.One.div(n);
|
|
26932
|
+
const basePrime = differentiate(base, v) ?? ce._fn("D", [base, ce.symbol(v)]);
|
|
26933
|
+
const newExponent = exponent.sub(ce.One);
|
|
26934
|
+
const power = ce.function("Power", [base, newExponent], { structural: true });
|
|
26935
|
+
return simplifyDerivative(exponent.mul(power).mul(basePrime));
|
|
26936
|
+
}
|
|
26820
26937
|
if (expr.operator === "Power") {
|
|
26821
26938
|
const [base, exponent] = expr.ops;
|
|
26822
26939
|
const baseHasV = base.has(v);
|
|
@@ -26853,7 +26970,7 @@ ${lines.join("\n")}`;
|
|
|
26853
26970
|
);
|
|
26854
26971
|
}
|
|
26855
26972
|
const h = DERIVATIVES_TABLE[expr.operator];
|
|
26856
|
-
if (
|
|
26973
|
+
if (h === void 0) {
|
|
26857
26974
|
if (expr.nops > 1) return void 0;
|
|
26858
26975
|
const fPrime = ce._fn("Derivative", [ce.symbol(expr.operator), ce.One]);
|
|
26859
26976
|
if (!fPrime.isValid) return void 0;
|
|
@@ -27434,6 +27551,14 @@ ${e.message}`);
|
|
|
27434
27551
|
// Handle ax = 0
|
|
27435
27552
|
condition: filter
|
|
27436
27553
|
},
|
|
27554
|
+
// -ax + b = 0 => x = b/a
|
|
27555
|
+
// This handles cases where the coefficient is negative and represented as Negate(Multiply(...))
|
|
27556
|
+
{
|
|
27557
|
+
match: ["Add", ["Negate", ["Multiply", "_x", "__a"]], "__b"],
|
|
27558
|
+
replace: ["Divide", "__b", "__a"],
|
|
27559
|
+
useVariations: true,
|
|
27560
|
+
condition: filter
|
|
27561
|
+
},
|
|
27437
27562
|
// ax^n + b = 0
|
|
27438
27563
|
{
|
|
27439
27564
|
match: ["Add", ["Multiply", "_a", ["Power", "_x", "_n"]], "__b"],
|
|
@@ -27569,27 +27694,140 @@ ${e.message}`);
|
|
|
27569
27694
|
replace: ["Divide", ["Negate", ["Add", "__b", "__c"], "__a"]],
|
|
27570
27695
|
condition: filter
|
|
27571
27696
|
},
|
|
27572
|
-
//
|
|
27573
|
-
//
|
|
27697
|
+
//
|
|
27698
|
+
// Square root equations: ax + b√x + c = 0
|
|
27699
|
+
// Using substitution u = √x, this becomes au² + bu + c = 0
|
|
27700
|
+
// Solving: u = (-b ± √(b² - 4ac)) / 2a
|
|
27701
|
+
// Then x = u² = ((-b ± √(b² - 4ac)) / 2a)²
|
|
27702
|
+
//
|
|
27703
|
+
// ax + b√x + c = 0 (plus root)
|
|
27704
|
+
{
|
|
27705
|
+
match: ["Add", ["Multiply", "_x", "__a"], ["Multiply", "__b", ["Sqrt", "_x"]], "___c"],
|
|
27706
|
+
replace: [
|
|
27707
|
+
"Power",
|
|
27708
|
+
[
|
|
27709
|
+
"Divide",
|
|
27710
|
+
["Add", ["Negate", "__b"], ["Sqrt", ["Subtract", ["Square", "__b"], ["Multiply", 4, "__a", "___c"]]]],
|
|
27711
|
+
["Multiply", 2, "__a"]
|
|
27712
|
+
],
|
|
27713
|
+
2
|
|
27714
|
+
],
|
|
27715
|
+
useVariations: true,
|
|
27716
|
+
condition: filter
|
|
27717
|
+
},
|
|
27718
|
+
// ax + b√x + c = 0 (minus root)
|
|
27719
|
+
{
|
|
27720
|
+
match: ["Add", ["Multiply", "_x", "__a"], ["Multiply", "__b", ["Sqrt", "_x"]], "___c"],
|
|
27721
|
+
replace: [
|
|
27722
|
+
"Power",
|
|
27723
|
+
[
|
|
27724
|
+
"Divide",
|
|
27725
|
+
["Subtract", ["Negate", "__b"], ["Sqrt", ["Subtract", ["Square", "__b"], ["Multiply", 4, "__a", "___c"]]]],
|
|
27726
|
+
["Multiply", 2, "__a"]
|
|
27727
|
+
],
|
|
27728
|
+
2
|
|
27729
|
+
],
|
|
27730
|
+
useVariations: true,
|
|
27731
|
+
condition: filter
|
|
27732
|
+
},
|
|
27733
|
+
// Handle negated coefficient: ax - b√x + c = 0
|
|
27734
|
+
// This handles the Negate(Multiply(...)) pattern
|
|
27735
|
+
{
|
|
27736
|
+
match: ["Add", ["Multiply", "_x", "__a"], ["Negate", ["Multiply", "__b", ["Sqrt", "_x"]]], "___c"],
|
|
27737
|
+
replace: [
|
|
27738
|
+
"Power",
|
|
27739
|
+
[
|
|
27740
|
+
"Divide",
|
|
27741
|
+
["Add", "__b", ["Sqrt", ["Add", ["Square", "__b"], ["Multiply", 4, "__a", "___c"]]]],
|
|
27742
|
+
["Multiply", 2, "__a"]
|
|
27743
|
+
],
|
|
27744
|
+
2
|
|
27745
|
+
],
|
|
27746
|
+
useVariations: true,
|
|
27747
|
+
condition: filter
|
|
27748
|
+
},
|
|
27749
|
+
// ax - b√x + c = 0 (minus root)
|
|
27750
|
+
{
|
|
27751
|
+
match: ["Add", ["Multiply", "_x", "__a"], ["Negate", ["Multiply", "__b", ["Sqrt", "_x"]]], "___c"],
|
|
27752
|
+
replace: [
|
|
27753
|
+
"Power",
|
|
27754
|
+
[
|
|
27755
|
+
"Divide",
|
|
27756
|
+
["Subtract", "__b", ["Sqrt", ["Add", ["Square", "__b"], ["Multiply", 4, "__a", "___c"]]]],
|
|
27757
|
+
["Multiply", 2, "__a"]
|
|
27758
|
+
],
|
|
27759
|
+
2
|
|
27760
|
+
],
|
|
27761
|
+
useVariations: true,
|
|
27762
|
+
condition: filter
|
|
27763
|
+
},
|
|
27764
|
+
//
|
|
27765
|
+
// Additional solve rules
|
|
27766
|
+
//
|
|
27767
|
+
// a√x + b = 0 => x = (b/a)² (only valid when -b/a ≥ 0)
|
|
27768
|
+
{
|
|
27769
|
+
match: ["Add", ["Multiply", "__a", ["Sqrt", "_x"]], "__b"],
|
|
27770
|
+
replace: ["Square", ["Divide", ["Negate", "__b"], "__a"]],
|
|
27771
|
+
useVariations: true,
|
|
27772
|
+
condition: (sub2) => {
|
|
27773
|
+
if (!filter(sub2)) return false;
|
|
27774
|
+
const a = sub2.__a;
|
|
27775
|
+
const b = sub2.__b;
|
|
27776
|
+
if (!a || !b) return false;
|
|
27777
|
+
const ratio = b.div(a);
|
|
27778
|
+
return ratio.isNonPositive ?? true;
|
|
27779
|
+
}
|
|
27780
|
+
},
|
|
27781
|
+
// a·ln(x) + b = 0 => x = e^(-b/a)
|
|
27574
27782
|
{
|
|
27575
|
-
match: "
|
|
27576
|
-
replace: "
|
|
27783
|
+
match: ["Add", ["Multiply", "__a", ["Ln", "_x"]], "__b"],
|
|
27784
|
+
replace: ["Exp", ["Divide", ["Negate", "__b"], "__a"]],
|
|
27577
27785
|
useVariations: true,
|
|
27578
27786
|
condition: filter
|
|
27579
27787
|
},
|
|
27580
|
-
//
|
|
27788
|
+
// ln(x) + b = 0 => x = e^(-b)
|
|
27581
27789
|
{
|
|
27582
|
-
match: "
|
|
27583
|
-
replace: "
|
|
27790
|
+
match: ["Add", ["Ln", "_x"], "__b"],
|
|
27791
|
+
replace: ["Exp", ["Negate", "__b"]],
|
|
27584
27792
|
useVariations: true,
|
|
27585
27793
|
condition: filter
|
|
27586
27794
|
}
|
|
27587
27795
|
];
|
|
27796
|
+
function clearDenominators(expr, variable) {
|
|
27797
|
+
if (expr.operator !== "Add") return expr;
|
|
27798
|
+
const ops = expr.ops;
|
|
27799
|
+
if (!ops || ops.length === 0) return expr;
|
|
27800
|
+
const denominators = ops.map((op) => op.denominator).filter((d) => !d.is(1));
|
|
27801
|
+
if (denominators.length === 0) return expr;
|
|
27802
|
+
const lcmFactors = [];
|
|
27803
|
+
for (const denom of denominators) {
|
|
27804
|
+
let isDuplicate = false;
|
|
27805
|
+
for (const existing of lcmFactors) {
|
|
27806
|
+
if (denom.isSame(existing)) {
|
|
27807
|
+
isDuplicate = true;
|
|
27808
|
+
break;
|
|
27809
|
+
}
|
|
27810
|
+
if (denom.symbol && existing.symbol && denom.symbol === existing.symbol) {
|
|
27811
|
+
isDuplicate = true;
|
|
27812
|
+
break;
|
|
27813
|
+
}
|
|
27814
|
+
}
|
|
27815
|
+
if (!isDuplicate) {
|
|
27816
|
+
lcmFactors.push(denom);
|
|
27817
|
+
}
|
|
27818
|
+
}
|
|
27819
|
+
let lcm4 = lcmFactors[0];
|
|
27820
|
+
for (let i = 1; i < lcmFactors.length; i++) {
|
|
27821
|
+
lcm4 = lcm4.mul(lcmFactors[i]);
|
|
27822
|
+
}
|
|
27823
|
+
return expr.mul(lcm4).simplify();
|
|
27824
|
+
}
|
|
27588
27825
|
function findUnivariateRoots(expr, x) {
|
|
27589
27826
|
const ce = expr.engine;
|
|
27590
27827
|
if (expr.operator === "Equal")
|
|
27591
27828
|
expr = expr.op1.expand().sub(expr.op2.expand()).simplify();
|
|
27592
27829
|
else expr = expr.expand().simplify();
|
|
27830
|
+
expr = clearDenominators(expr);
|
|
27593
27831
|
const rules = ce.getRuleSet("solve-univariate");
|
|
27594
27832
|
let exprs = [expr.subs({ [x]: "_x" }, { canonical: false })];
|
|
27595
27833
|
ce.pushScope();
|
|
@@ -28451,40 +28689,46 @@ ${e.message}`);
|
|
|
28451
28689
|
],
|
|
28452
28690
|
condition: filter2
|
|
28453
28691
|
},
|
|
28454
|
-
// \arctan(ax + b) ->
|
|
28692
|
+
// \arctan(ax + b) -> (1/a) * [(ax+b)*arctan(ax+b) - (1/2)*ln(1+(ax+b)^2)]
|
|
28455
28693
|
{
|
|
28456
28694
|
match: ["Arctan", ["Add", ["Multiply", "_a", "_x"], "__b"]],
|
|
28457
28695
|
replace: [
|
|
28458
28696
|
"Divide",
|
|
28459
28697
|
[
|
|
28460
|
-
"
|
|
28698
|
+
"Subtract",
|
|
28461
28699
|
[
|
|
28462
|
-
"
|
|
28463
|
-
["
|
|
28464
|
-
["
|
|
28700
|
+
"Multiply",
|
|
28701
|
+
["Add", ["Multiply", "_a", "_x"], "__b"],
|
|
28702
|
+
["Arctan", ["Add", ["Multiply", "_a", "_x"], "__b"]]
|
|
28703
|
+
],
|
|
28704
|
+
[
|
|
28705
|
+
"Multiply",
|
|
28706
|
+
["Rational", 1, 2],
|
|
28707
|
+
["Ln", ["Add", 1, ["Power", ["Add", ["Multiply", "_a", "_x"], "__b"], 2]]]
|
|
28465
28708
|
]
|
|
28466
28709
|
],
|
|
28467
28710
|
"_a"
|
|
28468
28711
|
],
|
|
28469
28712
|
condition: filter2
|
|
28470
28713
|
},
|
|
28471
|
-
// \arccos(ax + b) ->
|
|
28714
|
+
// \arccos(ax + b) -> (1/a) * [(ax+b)*arccos(ax+b) - sqrt(1-(ax+b)^2)]
|
|
28472
28715
|
{
|
|
28473
28716
|
match: ["Arccos", ["Add", ["Multiply", "_a", "_x"], "__b"]],
|
|
28474
28717
|
replace: [
|
|
28475
28718
|
"Divide",
|
|
28476
28719
|
[
|
|
28477
|
-
"
|
|
28720
|
+
"Subtract",
|
|
28478
28721
|
[
|
|
28479
|
-
"
|
|
28722
|
+
"Multiply",
|
|
28480
28723
|
["Add", ["Multiply", "_a", "_x"], "__b"],
|
|
28724
|
+
["Arccos", ["Add", ["Multiply", "_a", "_x"], "__b"]]
|
|
28725
|
+
],
|
|
28726
|
+
[
|
|
28727
|
+
"Sqrt",
|
|
28481
28728
|
[
|
|
28482
|
-
"
|
|
28483
|
-
|
|
28484
|
-
|
|
28485
|
-
["Power", ["Add", ["Multiply", "_a", "_x"], "__b"], 2],
|
|
28486
|
-
1
|
|
28487
|
-
]
|
|
28729
|
+
"Subtract",
|
|
28730
|
+
1,
|
|
28731
|
+
["Power", ["Add", ["Multiply", "_a", "_x"], "__b"], 2]
|
|
28488
28732
|
]
|
|
28489
28733
|
]
|
|
28490
28734
|
],
|
|
@@ -28492,23 +28736,24 @@ ${e.message}`);
|
|
|
28492
28736
|
],
|
|
28493
28737
|
condition: filter2
|
|
28494
28738
|
},
|
|
28495
|
-
// \arcsin(ax + b) ->
|
|
28739
|
+
// \arcsin(ax + b) -> (1/a) * [(ax+b)*arcsin(ax+b) + sqrt(1-(ax+b)^2)]
|
|
28496
28740
|
{
|
|
28497
28741
|
match: ["Arcsin", ["Add", ["Multiply", "_a", "_x"], "__b"]],
|
|
28498
28742
|
replace: [
|
|
28499
28743
|
"Divide",
|
|
28500
28744
|
[
|
|
28501
|
-
"
|
|
28745
|
+
"Add",
|
|
28502
28746
|
[
|
|
28503
|
-
"
|
|
28747
|
+
"Multiply",
|
|
28504
28748
|
["Add", ["Multiply", "_a", "_x"], "__b"],
|
|
28749
|
+
["Arcsin", ["Add", ["Multiply", "_a", "_x"], "__b"]]
|
|
28750
|
+
],
|
|
28751
|
+
[
|
|
28752
|
+
"Sqrt",
|
|
28505
28753
|
[
|
|
28506
|
-
"
|
|
28507
|
-
|
|
28508
|
-
|
|
28509
|
-
1,
|
|
28510
|
-
["Power", ["Add", ["Multiply", "_a", "_x"], "__b"], 2]
|
|
28511
|
-
]
|
|
28754
|
+
"Subtract",
|
|
28755
|
+
1,
|
|
28756
|
+
["Power", ["Add", ["Multiply", "_a", "_x"], "__b"], 2]
|
|
28512
28757
|
]
|
|
28513
28758
|
]
|
|
28514
28759
|
],
|
|
@@ -29322,6 +29567,8 @@ ${e.message}`);
|
|
|
29322
29567
|
}
|
|
29323
29568
|
f = f?.canonical;
|
|
29324
29569
|
if (f?.operator === "D") return f;
|
|
29570
|
+
if (f?.operator === "Apply" && f.op1?.operator === "Derivative")
|
|
29571
|
+
return f;
|
|
29325
29572
|
if (f && hasSymbolicTranscendental(f)) return f;
|
|
29326
29573
|
return f?.evaluate();
|
|
29327
29574
|
}
|
|
@@ -29448,7 +29695,7 @@ ${e.message}`);
|
|
|
29448
29695
|
complexity: 5e3,
|
|
29449
29696
|
broadcastable: false,
|
|
29450
29697
|
lazy: true,
|
|
29451
|
-
signature: "(index:symbol, lower:
|
|
29698
|
+
signature: "(index:symbol, lower:value, upper:value) -> tuple",
|
|
29452
29699
|
canonical: (ops, { engine }) => canonicalLimits(ops, { engine }) ?? null
|
|
29453
29700
|
}
|
|
29454
29701
|
},
|
|
@@ -30961,12 +31208,22 @@ ${e.message}`);
|
|
|
30961
31208
|
}
|
|
30962
31209
|
if (op1.isIndexedCollection) return ce._fn("At", [op1, op2.canonical]);
|
|
30963
31210
|
if (op1.symbol) {
|
|
30964
|
-
const
|
|
30965
|
-
if (
|
|
31211
|
+
const sub3 = op2.string ?? op2.symbol ?? asSmallInteger(op2)?.toString();
|
|
31212
|
+
if (sub3) return ce.symbol(op1.symbol + "_" + sub3);
|
|
31213
|
+
if (op2.operator === "InvisibleOperator" && op2.ops) {
|
|
31214
|
+
const parts = op2.ops.map(
|
|
31215
|
+
(x) => x.symbol ?? asSmallInteger(x)?.toString()
|
|
31216
|
+
);
|
|
31217
|
+
if (parts.every((p) => p !== void 0 && p !== null)) {
|
|
31218
|
+
return ce.symbol(op1.symbol + "_" + parts.join(""));
|
|
31219
|
+
}
|
|
31220
|
+
}
|
|
30966
31221
|
}
|
|
30967
31222
|
if (op2.operator === "Sequence")
|
|
30968
31223
|
ce._fn("Subscript", [op1, ce._fn("List", op2.ops)]);
|
|
30969
|
-
|
|
31224
|
+
let sub2 = op2;
|
|
31225
|
+
if (op2.operator === "Delimiter" && op2.op1) sub2 = op2.op1.canonical;
|
|
31226
|
+
return ce._fn("Subscript", [op1, sub2]);
|
|
30970
31227
|
}
|
|
30971
31228
|
},
|
|
30972
31229
|
Symbol: {
|
|
@@ -32696,6 +32953,539 @@ ${e.message}`);
|
|
|
32696
32953
|
return ce._fn(operator2, [body]);
|
|
32697
32954
|
}
|
|
32698
32955
|
|
|
32956
|
+
// src/compute-engine/library/logic-utils.ts
|
|
32957
|
+
function evaluateAnd(args, { engine: ce }) {
|
|
32958
|
+
if (args.length === 0) return ce.True;
|
|
32959
|
+
const ops = [];
|
|
32960
|
+
for (const arg of args) {
|
|
32961
|
+
if (arg.symbol === "False") return ce.False;
|
|
32962
|
+
if (arg.symbol !== "True") {
|
|
32963
|
+
let duplicate = false;
|
|
32964
|
+
for (const x of ops) {
|
|
32965
|
+
if (x.isSame(arg)) {
|
|
32966
|
+
duplicate = true;
|
|
32967
|
+
} else if (arg.operator === "Not" && arg.op1.isSame(x) || x.operator === "Not" && x.op1.isSame(arg)) {
|
|
32968
|
+
return ce.False;
|
|
32969
|
+
}
|
|
32970
|
+
}
|
|
32971
|
+
if (!duplicate) ops.push(arg);
|
|
32972
|
+
}
|
|
32973
|
+
}
|
|
32974
|
+
if (ops.length === 0) return ce.True;
|
|
32975
|
+
if (ops.length === 1) return ops[0];
|
|
32976
|
+
return ce._fn("And", ops);
|
|
32977
|
+
}
|
|
32978
|
+
function evaluateOr(args, { engine: ce }) {
|
|
32979
|
+
if (args.length === 0) return ce.True;
|
|
32980
|
+
const ops = [];
|
|
32981
|
+
for (const arg of args) {
|
|
32982
|
+
if (arg.symbol === "True") return ce.True;
|
|
32983
|
+
if (arg.symbol !== "False") {
|
|
32984
|
+
let duplicate = false;
|
|
32985
|
+
for (const x of ops) {
|
|
32986
|
+
if (x.isSame(arg)) {
|
|
32987
|
+
duplicate = true;
|
|
32988
|
+
} else if (arg.operator === "Not" && arg.op1.isSame(x) || x.operator === "Not" && x.op1.isSame(arg)) {
|
|
32989
|
+
return ce.True;
|
|
32990
|
+
}
|
|
32991
|
+
}
|
|
32992
|
+
if (!duplicate) ops.push(arg);
|
|
32993
|
+
}
|
|
32994
|
+
}
|
|
32995
|
+
if (ops.length === 0) return ce.False;
|
|
32996
|
+
if (ops.length === 1) return ops[0];
|
|
32997
|
+
return ce._fn("Or", ops);
|
|
32998
|
+
}
|
|
32999
|
+
function evaluateNot(args, { engine: ce }) {
|
|
33000
|
+
const op1 = args[0]?.symbol;
|
|
33001
|
+
if (op1 === "True") return ce.False;
|
|
33002
|
+
if (op1 === "False") return ce.True;
|
|
33003
|
+
return void 0;
|
|
33004
|
+
}
|
|
33005
|
+
function evaluateEquivalent(args, { engine: ce }) {
|
|
33006
|
+
const lhs = args[0].symbol;
|
|
33007
|
+
const rhs = args[1].symbol;
|
|
33008
|
+
if (lhs === "True" && rhs === "True" || lhs === "False" && rhs === "False")
|
|
33009
|
+
return ce.True;
|
|
33010
|
+
if (lhs === "True" && rhs === "False" || lhs === "False" && rhs === "True")
|
|
33011
|
+
return ce.False;
|
|
33012
|
+
return void 0;
|
|
33013
|
+
}
|
|
33014
|
+
function evaluateImplies(args, { engine: ce }) {
|
|
33015
|
+
const lhs = args[0].symbol;
|
|
33016
|
+
const rhs = args[1].symbol;
|
|
33017
|
+
if (lhs === "True" && rhs === "True" || lhs === "False" && rhs === "False" || lhs === "False" && rhs === "True")
|
|
33018
|
+
return ce.True;
|
|
33019
|
+
if (lhs === "True" && rhs === "False") return ce.False;
|
|
33020
|
+
return void 0;
|
|
33021
|
+
}
|
|
33022
|
+
function evaluateXor(args, { engine: ce }) {
|
|
33023
|
+
if (args.length === 0) return ce.False;
|
|
33024
|
+
let trueCount = 0;
|
|
33025
|
+
const unknowns = [];
|
|
33026
|
+
for (const arg of args) {
|
|
33027
|
+
if (arg.symbol === "True") {
|
|
33028
|
+
trueCount++;
|
|
33029
|
+
} else if (arg.symbol === "False") {
|
|
33030
|
+
} else {
|
|
33031
|
+
unknowns.push(arg);
|
|
33032
|
+
}
|
|
33033
|
+
}
|
|
33034
|
+
if (unknowns.length === 0) {
|
|
33035
|
+
return trueCount % 2 === 1 ? ce.True : ce.False;
|
|
33036
|
+
}
|
|
33037
|
+
if (unknowns.length === 1 && trueCount % 2 === 1) {
|
|
33038
|
+
return ce._fn("Not", [unknowns[0]]);
|
|
33039
|
+
}
|
|
33040
|
+
if (unknowns.length === 1 && trueCount % 2 === 0) {
|
|
33041
|
+
return unknowns[0];
|
|
33042
|
+
}
|
|
33043
|
+
return void 0;
|
|
33044
|
+
}
|
|
33045
|
+
function evaluateNand(args, { engine: ce }) {
|
|
33046
|
+
if (args.length === 0) return ce.False;
|
|
33047
|
+
for (const arg of args) {
|
|
33048
|
+
if (arg.symbol === "False") return ce.True;
|
|
33049
|
+
}
|
|
33050
|
+
let allTrue = true;
|
|
33051
|
+
for (const arg of args) {
|
|
33052
|
+
if (arg.symbol !== "True") {
|
|
33053
|
+
allTrue = false;
|
|
33054
|
+
break;
|
|
33055
|
+
}
|
|
33056
|
+
}
|
|
33057
|
+
if (allTrue) return ce.False;
|
|
33058
|
+
return void 0;
|
|
33059
|
+
}
|
|
33060
|
+
function evaluateNor(args, { engine: ce }) {
|
|
33061
|
+
if (args.length === 0) return ce.True;
|
|
33062
|
+
for (const arg of args) {
|
|
33063
|
+
if (arg.symbol === "True") return ce.False;
|
|
33064
|
+
}
|
|
33065
|
+
let allFalse = true;
|
|
33066
|
+
for (const arg of args) {
|
|
33067
|
+
if (arg.symbol !== "False") {
|
|
33068
|
+
allFalse = false;
|
|
33069
|
+
break;
|
|
33070
|
+
}
|
|
33071
|
+
}
|
|
33072
|
+
if (allFalse) return ce.True;
|
|
33073
|
+
return void 0;
|
|
33074
|
+
}
|
|
33075
|
+
function toNNF(expr, ce) {
|
|
33076
|
+
const op = expr.operator;
|
|
33077
|
+
if (!op) return expr;
|
|
33078
|
+
if (expr.symbol === "True" || expr.symbol === "False") return expr;
|
|
33079
|
+
if (op === "Not") {
|
|
33080
|
+
const inner = expr.op1;
|
|
33081
|
+
if (!inner) return expr;
|
|
33082
|
+
const innerOp = inner.operator;
|
|
33083
|
+
if (innerOp === "Not") {
|
|
33084
|
+
return toNNF(inner.op1, ce);
|
|
33085
|
+
}
|
|
33086
|
+
if (innerOp === "And") {
|
|
33087
|
+
const negatedOps = inner.ops.map((x) => toNNF(ce._fn("Not", [x]), ce));
|
|
33088
|
+
return ce._fn("Or", negatedOps);
|
|
33089
|
+
}
|
|
33090
|
+
if (innerOp === "Or") {
|
|
33091
|
+
const negatedOps = inner.ops.map((x) => toNNF(ce._fn("Not", [x]), ce));
|
|
33092
|
+
return ce._fn("And", negatedOps);
|
|
33093
|
+
}
|
|
33094
|
+
if (inner.symbol === "True") return ce.False;
|
|
33095
|
+
if (inner.symbol === "False") return ce.True;
|
|
33096
|
+
if (innerOp === "Implies") {
|
|
33097
|
+
const a = inner.op1;
|
|
33098
|
+
const b = inner.op2;
|
|
33099
|
+
return toNNF(ce._fn("And", [a, ce._fn("Not", [b])]), ce);
|
|
33100
|
+
}
|
|
33101
|
+
if (innerOp === "Equivalent") {
|
|
33102
|
+
const a = inner.op1;
|
|
33103
|
+
const b = inner.op2;
|
|
33104
|
+
return toNNF(
|
|
33105
|
+
ce._fn("Or", [
|
|
33106
|
+
ce._fn("And", [a, ce._fn("Not", [b])]),
|
|
33107
|
+
ce._fn("And", [ce._fn("Not", [a]), b])
|
|
33108
|
+
]),
|
|
33109
|
+
ce
|
|
33110
|
+
);
|
|
33111
|
+
}
|
|
33112
|
+
if (innerOp === "Xor") {
|
|
33113
|
+
const ops = inner.ops;
|
|
33114
|
+
if (ops.length === 2) {
|
|
33115
|
+
const a = ops[0];
|
|
33116
|
+
const b = ops[1];
|
|
33117
|
+
return toNNF(
|
|
33118
|
+
ce._fn("Or", [
|
|
33119
|
+
ce._fn("And", [a, b]),
|
|
33120
|
+
ce._fn("And", [ce._fn("Not", [a]), ce._fn("Not", [b])])
|
|
33121
|
+
]),
|
|
33122
|
+
ce
|
|
33123
|
+
);
|
|
33124
|
+
}
|
|
33125
|
+
return toNNF(ce._fn("Not", [toNNF(inner, ce)]), ce);
|
|
33126
|
+
}
|
|
33127
|
+
if (innerOp === "Nand") {
|
|
33128
|
+
return toNNF(ce._fn("And", inner.ops), ce);
|
|
33129
|
+
}
|
|
33130
|
+
if (innerOp === "Nor") {
|
|
33131
|
+
return toNNF(ce._fn("Or", inner.ops), ce);
|
|
33132
|
+
}
|
|
33133
|
+
return expr;
|
|
33134
|
+
}
|
|
33135
|
+
if (op === "Implies") {
|
|
33136
|
+
const a = expr.op1;
|
|
33137
|
+
const b = expr.op2;
|
|
33138
|
+
return toNNF(ce._fn("Or", [ce._fn("Not", [a]), b]), ce);
|
|
33139
|
+
}
|
|
33140
|
+
if (op === "Equivalent") {
|
|
33141
|
+
const a = expr.op1;
|
|
33142
|
+
const b = expr.op2;
|
|
33143
|
+
return toNNF(
|
|
33144
|
+
ce._fn("And", [
|
|
33145
|
+
ce._fn("Or", [ce._fn("Not", [a]), b]),
|
|
33146
|
+
ce._fn("Or", [ce._fn("Not", [b]), a])
|
|
33147
|
+
]),
|
|
33148
|
+
ce
|
|
33149
|
+
);
|
|
33150
|
+
}
|
|
33151
|
+
if (op === "Xor") {
|
|
33152
|
+
const ops = expr.ops;
|
|
33153
|
+
if (ops.length === 2) {
|
|
33154
|
+
const a = ops[0];
|
|
33155
|
+
const b = ops[1];
|
|
33156
|
+
return toNNF(
|
|
33157
|
+
ce._fn("And", [
|
|
33158
|
+
ce._fn("Or", [a, b]),
|
|
33159
|
+
ce._fn("Or", [ce._fn("Not", [a]), ce._fn("Not", [b])])
|
|
33160
|
+
]),
|
|
33161
|
+
ce
|
|
33162
|
+
);
|
|
33163
|
+
}
|
|
33164
|
+
if (ops.length > 2) {
|
|
33165
|
+
const first = ce._fn("Xor", [ops[0], ops[1]]);
|
|
33166
|
+
const rest = ops.slice(2);
|
|
33167
|
+
return toNNF(ce._fn("Xor", [first, ...rest]), ce);
|
|
33168
|
+
}
|
|
33169
|
+
if (ops.length === 1) return toNNF(ops[0], ce);
|
|
33170
|
+
return ce.False;
|
|
33171
|
+
}
|
|
33172
|
+
if (op === "Nand") {
|
|
33173
|
+
const ops = expr.ops;
|
|
33174
|
+
return toNNF(ce._fn("Not", [ce._fn("And", ops)]), ce);
|
|
33175
|
+
}
|
|
33176
|
+
if (op === "Nor") {
|
|
33177
|
+
const ops = expr.ops;
|
|
33178
|
+
return toNNF(ce._fn("Not", [ce._fn("Or", ops)]), ce);
|
|
33179
|
+
}
|
|
33180
|
+
if (op === "And" || op === "Or") {
|
|
33181
|
+
const nnfOps = expr.ops.map((x) => toNNF(x, ce));
|
|
33182
|
+
return ce._fn(op, nnfOps);
|
|
33183
|
+
}
|
|
33184
|
+
return expr;
|
|
33185
|
+
}
|
|
33186
|
+
function distributeOrOverAnd(expr, ce) {
|
|
33187
|
+
const op = expr.operator;
|
|
33188
|
+
if (op !== "Or") {
|
|
33189
|
+
if (op === "And") {
|
|
33190
|
+
return ce._fn(
|
|
33191
|
+
"And",
|
|
33192
|
+
expr.ops.map((x) => distributeOrOverAnd(x, ce))
|
|
33193
|
+
);
|
|
33194
|
+
}
|
|
33195
|
+
return expr;
|
|
33196
|
+
}
|
|
33197
|
+
const orOperands = [];
|
|
33198
|
+
for (const operand2 of expr.ops) {
|
|
33199
|
+
if (operand2.operator === "Or") {
|
|
33200
|
+
orOperands.push(...operand2.ops);
|
|
33201
|
+
} else {
|
|
33202
|
+
orOperands.push(operand2);
|
|
33203
|
+
}
|
|
33204
|
+
}
|
|
33205
|
+
const andIndex = orOperands.findIndex((x) => x.operator === "And");
|
|
33206
|
+
if (andIndex === -1) {
|
|
33207
|
+
return expr;
|
|
33208
|
+
}
|
|
33209
|
+
const andExpr = orOperands[andIndex];
|
|
33210
|
+
const otherOperands = [
|
|
33211
|
+
...orOperands.slice(0, andIndex),
|
|
33212
|
+
...orOperands.slice(andIndex + 1)
|
|
33213
|
+
];
|
|
33214
|
+
const otherOr = otherOperands.length === 1 ? otherOperands[0] : ce._fn("Or", otherOperands);
|
|
33215
|
+
const distributed = ce._fn(
|
|
33216
|
+
"And",
|
|
33217
|
+
andExpr.ops.map((x) => ce._fn("Or", [x, otherOr]))
|
|
33218
|
+
);
|
|
33219
|
+
return distributeOrOverAnd(distributed, ce);
|
|
33220
|
+
}
|
|
33221
|
+
function toCNF(expr, ce) {
|
|
33222
|
+
const nnf = toNNF(expr, ce);
|
|
33223
|
+
const cnf = distributeOrOverAnd(nnf, ce);
|
|
33224
|
+
return cnf.simplify();
|
|
33225
|
+
}
|
|
33226
|
+
function distributeAndOverOr(expr, ce) {
|
|
33227
|
+
const op = expr.operator;
|
|
33228
|
+
if (op !== "And") {
|
|
33229
|
+
if (op === "Or") {
|
|
33230
|
+
return ce._fn(
|
|
33231
|
+
"Or",
|
|
33232
|
+
expr.ops.map((x) => distributeAndOverOr(x, ce))
|
|
33233
|
+
);
|
|
33234
|
+
}
|
|
33235
|
+
return expr;
|
|
33236
|
+
}
|
|
33237
|
+
const andOperands = [];
|
|
33238
|
+
for (const operand2 of expr.ops) {
|
|
33239
|
+
if (operand2.operator === "And") {
|
|
33240
|
+
andOperands.push(...operand2.ops);
|
|
33241
|
+
} else {
|
|
33242
|
+
andOperands.push(operand2);
|
|
33243
|
+
}
|
|
33244
|
+
}
|
|
33245
|
+
const orIndex = andOperands.findIndex((x) => x.operator === "Or");
|
|
33246
|
+
if (orIndex === -1) {
|
|
33247
|
+
return expr;
|
|
33248
|
+
}
|
|
33249
|
+
const orExpr = andOperands[orIndex];
|
|
33250
|
+
const otherOperands = [
|
|
33251
|
+
...andOperands.slice(0, orIndex),
|
|
33252
|
+
...andOperands.slice(orIndex + 1)
|
|
33253
|
+
];
|
|
33254
|
+
const otherAnd = otherOperands.length === 1 ? otherOperands[0] : ce._fn("And", otherOperands);
|
|
33255
|
+
const distributed = ce._fn(
|
|
33256
|
+
"Or",
|
|
33257
|
+
orExpr.ops.map((x) => ce._fn("And", [x, otherAnd]))
|
|
33258
|
+
);
|
|
33259
|
+
return distributeAndOverOr(distributed, ce);
|
|
33260
|
+
}
|
|
33261
|
+
function toDNF(expr, ce) {
|
|
33262
|
+
const nnf = toNNF(expr, ce);
|
|
33263
|
+
const dnf = distributeAndOverOr(nnf, ce);
|
|
33264
|
+
return dnf.simplify();
|
|
33265
|
+
}
|
|
33266
|
+
function extractVariables(expr) {
|
|
33267
|
+
const variables = /* @__PURE__ */ new Set();
|
|
33268
|
+
function visit(e) {
|
|
33269
|
+
if (e.symbol === "True" || e.symbol === "False") return;
|
|
33270
|
+
if (e.symbol && e.operator === "Symbol") {
|
|
33271
|
+
variables.add(e.symbol);
|
|
33272
|
+
return;
|
|
33273
|
+
}
|
|
33274
|
+
if (e.ops) {
|
|
33275
|
+
for (const op of e.ops) {
|
|
33276
|
+
visit(op);
|
|
33277
|
+
}
|
|
33278
|
+
}
|
|
33279
|
+
}
|
|
33280
|
+
visit(expr);
|
|
33281
|
+
return Array.from(variables).sort();
|
|
33282
|
+
}
|
|
33283
|
+
function evaluateWithAssignment(expr, assignment, ce) {
|
|
33284
|
+
const subs = {};
|
|
33285
|
+
for (const [variable, value] of Object.entries(assignment)) {
|
|
33286
|
+
subs[variable] = value ? ce.True : ce.False;
|
|
33287
|
+
}
|
|
33288
|
+
const substituted = expr.subs(subs).canonical;
|
|
33289
|
+
return substituted.evaluate();
|
|
33290
|
+
}
|
|
33291
|
+
function* generateAssignments(variables) {
|
|
33292
|
+
const n = variables.length;
|
|
33293
|
+
const total = 1 << n;
|
|
33294
|
+
for (let i = 0; i < total; i++) {
|
|
33295
|
+
const assignment = {};
|
|
33296
|
+
for (let j = 0; j < n; j++) {
|
|
33297
|
+
assignment[variables[j]] = (i >> n - 1 - j & 1) === 1;
|
|
33298
|
+
}
|
|
33299
|
+
yield assignment;
|
|
33300
|
+
}
|
|
33301
|
+
}
|
|
33302
|
+
|
|
33303
|
+
// src/compute-engine/library/logic-analysis.ts
|
|
33304
|
+
function extractFiniteDomain(condition, ce) {
|
|
33305
|
+
if (condition.operator !== "Element") return null;
|
|
33306
|
+
const variable = condition.op1?.symbol;
|
|
33307
|
+
if (!variable) return null;
|
|
33308
|
+
const domain = condition.op2;
|
|
33309
|
+
if (!domain) return null;
|
|
33310
|
+
if (domain.operator === "Set" || domain.operator === "List") {
|
|
33311
|
+
const values = domain.ops;
|
|
33312
|
+
if (values && values.length <= 1e3) {
|
|
33313
|
+
return { variable, values: [...values] };
|
|
33314
|
+
}
|
|
33315
|
+
return null;
|
|
33316
|
+
}
|
|
33317
|
+
if (domain.operator === "Range") {
|
|
33318
|
+
const start = asSmallInteger(domain.op1);
|
|
33319
|
+
const end = asSmallInteger(domain.op2);
|
|
33320
|
+
const step = domain.ops && domain.ops.length >= 3 ? asSmallInteger(domain.op3) : 1;
|
|
33321
|
+
if (start !== null && end !== null && step !== null && step !== 0) {
|
|
33322
|
+
const count = Math.floor((end - start) / step) + 1;
|
|
33323
|
+
if (count > 0 && count <= 1e3) {
|
|
33324
|
+
const values = [];
|
|
33325
|
+
for (let i = start; step > 0 ? i <= end : i >= end; i += step) {
|
|
33326
|
+
values.push(ce.number(i));
|
|
33327
|
+
}
|
|
33328
|
+
return { variable, values };
|
|
33329
|
+
}
|
|
33330
|
+
}
|
|
33331
|
+
return null;
|
|
33332
|
+
}
|
|
33333
|
+
if (domain.operator === "Interval") {
|
|
33334
|
+
const start = asSmallInteger(domain.op1);
|
|
33335
|
+
const end = asSmallInteger(domain.op2);
|
|
33336
|
+
if (start !== null && end !== null) {
|
|
33337
|
+
const count = end - start + 1;
|
|
33338
|
+
if (count > 0 && count <= 1e3) {
|
|
33339
|
+
const values = [];
|
|
33340
|
+
for (let i = start; i <= end; i++) {
|
|
33341
|
+
values.push(ce.number(i));
|
|
33342
|
+
}
|
|
33343
|
+
return { variable, values };
|
|
33344
|
+
}
|
|
33345
|
+
}
|
|
33346
|
+
return null;
|
|
33347
|
+
}
|
|
33348
|
+
return null;
|
|
33349
|
+
}
|
|
33350
|
+
function bodyContainsVariable(expr, variable) {
|
|
33351
|
+
if (expr.symbol === variable) return true;
|
|
33352
|
+
if (expr.ops) {
|
|
33353
|
+
for (const op of expr.ops) {
|
|
33354
|
+
if (bodyContainsVariable(op, variable)) return true;
|
|
33355
|
+
}
|
|
33356
|
+
}
|
|
33357
|
+
return false;
|
|
33358
|
+
}
|
|
33359
|
+
function collectNestedDomains(body, ce) {
|
|
33360
|
+
const canonicalBody = body.canonical;
|
|
33361
|
+
const op = canonicalBody.operator;
|
|
33362
|
+
if (op !== "ForAll" && op !== "Exists") return [];
|
|
33363
|
+
const condition = canonicalBody.op1;
|
|
33364
|
+
const innerBody = canonicalBody.op2;
|
|
33365
|
+
if (!condition || !innerBody) return [];
|
|
33366
|
+
const domain = extractFiniteDomain(condition, ce);
|
|
33367
|
+
if (!domain) return [];
|
|
33368
|
+
const innerDomains = collectNestedDomains(innerBody, ce);
|
|
33369
|
+
return [{ variable: domain.variable, values: domain.values }, ...innerDomains];
|
|
33370
|
+
}
|
|
33371
|
+
function getInnermostBody(body) {
|
|
33372
|
+
const canonicalBody = body.canonical;
|
|
33373
|
+
const op = canonicalBody.operator;
|
|
33374
|
+
if (op === "ForAll" || op === "Exists") {
|
|
33375
|
+
const innerBody = canonicalBody.op2;
|
|
33376
|
+
if (innerBody) return getInnermostBody(innerBody);
|
|
33377
|
+
}
|
|
33378
|
+
return canonicalBody;
|
|
33379
|
+
}
|
|
33380
|
+
function evaluateForAllCartesian(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.True;
|
|
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 === "False") {
|
|
33392
|
+
return ce.False;
|
|
33393
|
+
}
|
|
33394
|
+
if (result.symbol !== "True") {
|
|
33395
|
+
return void 0;
|
|
33396
|
+
}
|
|
33397
|
+
let dim = domains.length - 1;
|
|
33398
|
+
while (dim >= 0) {
|
|
33399
|
+
indices[dim]++;
|
|
33400
|
+
if (indices[dim] < lengths[dim]) break;
|
|
33401
|
+
indices[dim] = 0;
|
|
33402
|
+
dim--;
|
|
33403
|
+
}
|
|
33404
|
+
if (dim < 0) break;
|
|
33405
|
+
}
|
|
33406
|
+
return ce.True;
|
|
33407
|
+
}
|
|
33408
|
+
function evaluateExistsCartesian(domains, body, ce) {
|
|
33409
|
+
const indices = domains.map(() => 0);
|
|
33410
|
+
const lengths = domains.map((d) => d.values.length);
|
|
33411
|
+
if (lengths.some((l) => l === 0)) return ce.False;
|
|
33412
|
+
while (true) {
|
|
33413
|
+
const subs = {};
|
|
33414
|
+
for (let i = 0; i < domains.length; i++) {
|
|
33415
|
+
subs[domains[i].variable] = domains[i].values[indices[i]];
|
|
33416
|
+
}
|
|
33417
|
+
const substituted = body.subs(subs).canonical;
|
|
33418
|
+
const result = substituted.evaluate();
|
|
33419
|
+
if (result.symbol === "True") {
|
|
33420
|
+
return ce.True;
|
|
33421
|
+
}
|
|
33422
|
+
let dim = domains.length - 1;
|
|
33423
|
+
while (dim >= 0) {
|
|
33424
|
+
indices[dim]++;
|
|
33425
|
+
if (indices[dim] < lengths[dim]) break;
|
|
33426
|
+
indices[dim] = 0;
|
|
33427
|
+
dim--;
|
|
33428
|
+
}
|
|
33429
|
+
if (dim < 0) break;
|
|
33430
|
+
}
|
|
33431
|
+
return ce.False;
|
|
33432
|
+
}
|
|
33433
|
+
function isSatisfiable(expr, ce) {
|
|
33434
|
+
const variables = extractVariables(expr);
|
|
33435
|
+
if (variables.length === 0) {
|
|
33436
|
+
const result = expr.evaluate();
|
|
33437
|
+
return result.symbol === "True" ? ce.True : ce.False;
|
|
33438
|
+
}
|
|
33439
|
+
if (variables.length > 20) {
|
|
33440
|
+
return ce._fn("IsSatisfiable", [expr]);
|
|
33441
|
+
}
|
|
33442
|
+
for (const assignment of generateAssignments(variables)) {
|
|
33443
|
+
const result = evaluateWithAssignment(expr, assignment, ce);
|
|
33444
|
+
if (result.symbol === "True") {
|
|
33445
|
+
return ce.True;
|
|
33446
|
+
}
|
|
33447
|
+
}
|
|
33448
|
+
return ce.False;
|
|
33449
|
+
}
|
|
33450
|
+
function isTautology(expr, ce) {
|
|
33451
|
+
const variables = extractVariables(expr);
|
|
33452
|
+
if (variables.length === 0) {
|
|
33453
|
+
const result = expr.evaluate();
|
|
33454
|
+
return result.symbol === "True" ? ce.True : ce.False;
|
|
33455
|
+
}
|
|
33456
|
+
if (variables.length > 20) {
|
|
33457
|
+
return ce._fn("IsTautology", [expr]);
|
|
33458
|
+
}
|
|
33459
|
+
for (const assignment of generateAssignments(variables)) {
|
|
33460
|
+
const result = evaluateWithAssignment(expr, assignment, ce);
|
|
33461
|
+
if (result.symbol !== "True") {
|
|
33462
|
+
return ce.False;
|
|
33463
|
+
}
|
|
33464
|
+
}
|
|
33465
|
+
return ce.True;
|
|
33466
|
+
}
|
|
33467
|
+
function generateTruthTable(expr, ce) {
|
|
33468
|
+
const variables = extractVariables(expr);
|
|
33469
|
+
if (variables.length > 10) {
|
|
33470
|
+
return ce._fn("TruthTable", [expr]);
|
|
33471
|
+
}
|
|
33472
|
+
const rows = [];
|
|
33473
|
+
const header = ce._fn("List", [
|
|
33474
|
+
...variables.map((v) => ce.string(v)),
|
|
33475
|
+
ce.string("Result")
|
|
33476
|
+
]);
|
|
33477
|
+
rows.push(header);
|
|
33478
|
+
for (const assignment of generateAssignments(variables)) {
|
|
33479
|
+
const result = evaluateWithAssignment(expr, assignment, ce);
|
|
33480
|
+
const row = ce._fn("List", [
|
|
33481
|
+
...variables.map((v) => assignment[v] ? ce.True : ce.False),
|
|
33482
|
+
result
|
|
33483
|
+
]);
|
|
33484
|
+
rows.push(row);
|
|
33485
|
+
}
|
|
33486
|
+
return ce._fn("List", rows);
|
|
33487
|
+
}
|
|
33488
|
+
|
|
32699
33489
|
// src/compute-engine/library/logic.ts
|
|
32700
33490
|
var LOGIC_LIBRARY = {
|
|
32701
33491
|
True: {
|
|
@@ -32766,11 +33556,96 @@ ${e.message}`);
|
|
|
32766
33556
|
signature: "(boolean, boolean) -> boolean",
|
|
32767
33557
|
evaluate: evaluateImplies
|
|
32768
33558
|
},
|
|
32769
|
-
|
|
32770
|
-
|
|
32771
|
-
|
|
32772
|
-
|
|
32773
|
-
|
|
33559
|
+
Xor: {
|
|
33560
|
+
description: "Exclusive or: true when an odd number of operands are true",
|
|
33561
|
+
wikidata: "Q498186",
|
|
33562
|
+
broadcastable: true,
|
|
33563
|
+
associative: true,
|
|
33564
|
+
commutative: true,
|
|
33565
|
+
complexity: 10200,
|
|
33566
|
+
signature: "(boolean+) -> boolean",
|
|
33567
|
+
evaluate: evaluateXor
|
|
33568
|
+
},
|
|
33569
|
+
Nand: {
|
|
33570
|
+
description: "Not-and: negation of conjunction",
|
|
33571
|
+
wikidata: "Q189550",
|
|
33572
|
+
broadcastable: true,
|
|
33573
|
+
commutative: true,
|
|
33574
|
+
complexity: 10200,
|
|
33575
|
+
signature: "(boolean+) -> boolean",
|
|
33576
|
+
evaluate: evaluateNand
|
|
33577
|
+
},
|
|
33578
|
+
Nor: {
|
|
33579
|
+
description: "Not-or: negation of disjunction",
|
|
33580
|
+
wikidata: "Q189561",
|
|
33581
|
+
broadcastable: true,
|
|
33582
|
+
commutative: true,
|
|
33583
|
+
complexity: 10200,
|
|
33584
|
+
signature: "(boolean+) -> boolean",
|
|
33585
|
+
evaluate: evaluateNor
|
|
33586
|
+
},
|
|
33587
|
+
// Quantifiers return boolean values (they are propositions)
|
|
33588
|
+
// They support evaluation over finite domains (e.g., ForAll with Element condition)
|
|
33589
|
+
// The first argument can be:
|
|
33590
|
+
// - a symbol (e.g., "x") for symbolic quantification
|
|
33591
|
+
// - an Element expression (e.g., ["Element", "x", ["Set", 1, 2, 3]]) for finite domain evaluation
|
|
33592
|
+
Exists: {
|
|
33593
|
+
signature: "(value, boolean) -> boolean",
|
|
33594
|
+
lazy: true,
|
|
33595
|
+
scoped: true,
|
|
33596
|
+
evaluate: evaluateExists
|
|
33597
|
+
},
|
|
33598
|
+
NotExists: {
|
|
33599
|
+
signature: "(value, boolean) -> boolean",
|
|
33600
|
+
lazy: true,
|
|
33601
|
+
scoped: true,
|
|
33602
|
+
evaluate: (args, options) => {
|
|
33603
|
+
const result = evaluateExists(args, options);
|
|
33604
|
+
if (result?.symbol === "True") return options.engine.False;
|
|
33605
|
+
if (result?.symbol === "False") return options.engine.True;
|
|
33606
|
+
return void 0;
|
|
33607
|
+
}
|
|
33608
|
+
},
|
|
33609
|
+
ExistsUnique: {
|
|
33610
|
+
signature: "(value, boolean) -> boolean",
|
|
33611
|
+
lazy: true,
|
|
33612
|
+
scoped: true,
|
|
33613
|
+
evaluate: evaluateExistsUnique
|
|
33614
|
+
},
|
|
33615
|
+
ForAll: {
|
|
33616
|
+
signature: "(value, boolean) -> boolean",
|
|
33617
|
+
lazy: true,
|
|
33618
|
+
scoped: true,
|
|
33619
|
+
evaluate: evaluateForAll
|
|
33620
|
+
},
|
|
33621
|
+
NotForAll: {
|
|
33622
|
+
signature: "(value, boolean) -> boolean",
|
|
33623
|
+
lazy: true,
|
|
33624
|
+
scoped: true,
|
|
33625
|
+
evaluate: (args, options) => {
|
|
33626
|
+
const result = evaluateForAll(args, options);
|
|
33627
|
+
if (result?.symbol === "True") return options.engine.False;
|
|
33628
|
+
if (result?.symbol === "False") return options.engine.True;
|
|
33629
|
+
return void 0;
|
|
33630
|
+
}
|
|
33631
|
+
},
|
|
33632
|
+
// Predicate application in First-Order Logic.
|
|
33633
|
+
// ["Predicate", "P", "x"] represents the predicate P applied to x.
|
|
33634
|
+
// This is semantically different from a function application: predicates
|
|
33635
|
+
// return boolean values and are used in logical formulas.
|
|
33636
|
+
// In LaTeX, P(x) inside a quantifier context parses to ["Predicate", "P", "x"].
|
|
33637
|
+
Predicate: {
|
|
33638
|
+
description: "Apply a predicate to arguments, returning a boolean",
|
|
33639
|
+
signature: "(symbol, value+) -> boolean",
|
|
33640
|
+
lazy: true,
|
|
33641
|
+
// Predicates remain symbolic unless explicitly defined
|
|
33642
|
+
evaluate: (args, { engine }) => {
|
|
33643
|
+
if (args.length === 0) return void 0;
|
|
33644
|
+
const pred = args[0];
|
|
33645
|
+
if (!pred.symbol) return void 0;
|
|
33646
|
+
return void 0;
|
|
33647
|
+
}
|
|
33648
|
+
},
|
|
32774
33649
|
KroneckerDelta: {
|
|
32775
33650
|
description: "Return 1 if the arguments are equal, 0 otherwise",
|
|
32776
33651
|
signature: "(value+) -> integer",
|
|
@@ -32791,82 +33666,189 @@ ${e.message}`);
|
|
|
32791
33666
|
evaluate: (args, { engine: ce }) => args[0].symbol === "True" ? ce.One : ce.Zero
|
|
32792
33667
|
}
|
|
32793
33668
|
};
|
|
32794
|
-
function
|
|
32795
|
-
|
|
32796
|
-
|
|
32797
|
-
|
|
32798
|
-
|
|
32799
|
-
|
|
32800
|
-
|
|
32801
|
-
|
|
32802
|
-
|
|
32803
|
-
|
|
32804
|
-
|
|
32805
|
-
|
|
32806
|
-
|
|
32807
|
-
|
|
32808
|
-
|
|
32809
|
-
}
|
|
32810
|
-
}
|
|
32811
|
-
if (ops.length === 0) return ce.True;
|
|
32812
|
-
if (ops.length === 1) return ops[0];
|
|
32813
|
-
return ce._fn("And", ops);
|
|
33669
|
+
function simplifyLogicFunction(x) {
|
|
33670
|
+
const fn = {
|
|
33671
|
+
And: evaluateAnd,
|
|
33672
|
+
Or: evaluateOr,
|
|
33673
|
+
Not: evaluateNot,
|
|
33674
|
+
Equivalent: evaluateEquivalent,
|
|
33675
|
+
Implies: evaluateImplies,
|
|
33676
|
+
Xor: evaluateXor,
|
|
33677
|
+
Nand: evaluateNand,
|
|
33678
|
+
Nor: evaluateNor
|
|
33679
|
+
}[x.operator];
|
|
33680
|
+
if (!fn || !x.ops) return void 0;
|
|
33681
|
+
const value = fn(x.ops, { engine: x.engine });
|
|
33682
|
+
if (!value) return void 0;
|
|
33683
|
+
return { value, because: "logic" };
|
|
32814
33684
|
}
|
|
32815
|
-
function
|
|
32816
|
-
if (args.length
|
|
32817
|
-
const
|
|
32818
|
-
|
|
32819
|
-
|
|
32820
|
-
|
|
32821
|
-
|
|
32822
|
-
|
|
32823
|
-
|
|
32824
|
-
|
|
32825
|
-
|
|
32826
|
-
|
|
32827
|
-
|
|
33685
|
+
function evaluateForAll(args, { engine: ce }) {
|
|
33686
|
+
if (args.length < 2) return void 0;
|
|
33687
|
+
const condition = args[0];
|
|
33688
|
+
const body = args[1];
|
|
33689
|
+
const canonicalBody = body.canonical;
|
|
33690
|
+
if (canonicalBody.symbol === "True") return ce.True;
|
|
33691
|
+
if (canonicalBody.symbol === "False") return ce.False;
|
|
33692
|
+
const variable = condition.symbol ?? condition.op1?.symbol;
|
|
33693
|
+
if (variable && !bodyContainsVariable(canonicalBody, variable)) {
|
|
33694
|
+
return canonicalBody.evaluate();
|
|
33695
|
+
}
|
|
33696
|
+
const domain = extractFiniteDomain(condition, ce);
|
|
33697
|
+
if (domain) {
|
|
33698
|
+
const nestedDomains = collectNestedDomains(body, ce);
|
|
33699
|
+
if (nestedDomains.length > 0) {
|
|
33700
|
+
return evaluateForAllCartesian(
|
|
33701
|
+
[{ variable: domain.variable, values: domain.values }, ...nestedDomains],
|
|
33702
|
+
getInnermostBody(body),
|
|
33703
|
+
ce
|
|
33704
|
+
);
|
|
33705
|
+
}
|
|
33706
|
+
for (const value of domain.values) {
|
|
33707
|
+
const substituted = body.subs({ [domain.variable]: value }).canonical;
|
|
33708
|
+
const result = substituted.evaluate();
|
|
33709
|
+
if (result.symbol === "False") {
|
|
33710
|
+
return ce.False;
|
|
33711
|
+
}
|
|
33712
|
+
if (result.symbol !== "True") {
|
|
33713
|
+
return void 0;
|
|
32828
33714
|
}
|
|
32829
|
-
if (!duplicate) ops.push(arg);
|
|
32830
33715
|
}
|
|
33716
|
+
return ce.True;
|
|
32831
33717
|
}
|
|
32832
|
-
|
|
32833
|
-
if (
|
|
32834
|
-
|
|
32835
|
-
}
|
|
32836
|
-
function evaluateNot(args, { engine: ce }) {
|
|
32837
|
-
const op1 = args[0]?.symbol;
|
|
32838
|
-
if (op1 === "True") return ce.False;
|
|
32839
|
-
if (op1 === "False") return ce.True;
|
|
33718
|
+
const bodyEval = canonicalBody.evaluate();
|
|
33719
|
+
if (bodyEval.symbol === "True") return ce.True;
|
|
33720
|
+
if (bodyEval.symbol === "False") return ce.False;
|
|
32840
33721
|
return void 0;
|
|
32841
33722
|
}
|
|
32842
|
-
function
|
|
32843
|
-
|
|
32844
|
-
const
|
|
32845
|
-
|
|
32846
|
-
|
|
32847
|
-
if (
|
|
33723
|
+
function evaluateExists(args, { engine: ce }) {
|
|
33724
|
+
if (args.length < 2) return void 0;
|
|
33725
|
+
const condition = args[0];
|
|
33726
|
+
const body = args[1];
|
|
33727
|
+
const canonicalBody = body.canonical;
|
|
33728
|
+
if (canonicalBody.symbol === "True") return ce.True;
|
|
33729
|
+
if (canonicalBody.symbol === "False") return ce.False;
|
|
33730
|
+
const variable = condition.symbol ?? condition.op1?.symbol;
|
|
33731
|
+
if (variable && !bodyContainsVariable(canonicalBody, variable)) {
|
|
33732
|
+
return canonicalBody.evaluate();
|
|
33733
|
+
}
|
|
33734
|
+
const domain = extractFiniteDomain(condition, ce);
|
|
33735
|
+
if (domain) {
|
|
33736
|
+
const nestedDomains = collectNestedDomains(body, ce);
|
|
33737
|
+
if (nestedDomains.length > 0) {
|
|
33738
|
+
return evaluateExistsCartesian(
|
|
33739
|
+
[{ variable: domain.variable, values: domain.values }, ...nestedDomains],
|
|
33740
|
+
getInnermostBody(body),
|
|
33741
|
+
ce
|
|
33742
|
+
);
|
|
33743
|
+
}
|
|
33744
|
+
for (const value of domain.values) {
|
|
33745
|
+
const substituted = body.subs({ [domain.variable]: value }).canonical;
|
|
33746
|
+
const result = substituted.evaluate();
|
|
33747
|
+
if (result.symbol === "True") {
|
|
33748
|
+
return ce.True;
|
|
33749
|
+
}
|
|
33750
|
+
}
|
|
32848
33751
|
return ce.False;
|
|
33752
|
+
}
|
|
33753
|
+
const bodyEval = canonicalBody.evaluate();
|
|
33754
|
+
if (bodyEval.symbol === "True") return ce.True;
|
|
33755
|
+
if (bodyEval.symbol === "False") return ce.False;
|
|
32849
33756
|
return void 0;
|
|
32850
33757
|
}
|
|
32851
|
-
function
|
|
32852
|
-
|
|
32853
|
-
const
|
|
32854
|
-
|
|
32855
|
-
|
|
32856
|
-
if (
|
|
33758
|
+
function evaluateExistsUnique(args, { engine: ce }) {
|
|
33759
|
+
if (args.length < 2) return void 0;
|
|
33760
|
+
const condition = args[0];
|
|
33761
|
+
const body = args[1];
|
|
33762
|
+
const domain = extractFiniteDomain(condition, ce);
|
|
33763
|
+
if (domain) {
|
|
33764
|
+
let count = 0;
|
|
33765
|
+
for (const value of domain.values) {
|
|
33766
|
+
const substituted = body.subs({ [domain.variable]: value }).canonical;
|
|
33767
|
+
const result = substituted.evaluate();
|
|
33768
|
+
if (result.symbol === "True") {
|
|
33769
|
+
count++;
|
|
33770
|
+
if (count > 1) return ce.False;
|
|
33771
|
+
} else if (result.symbol !== "False") {
|
|
33772
|
+
return void 0;
|
|
33773
|
+
}
|
|
33774
|
+
}
|
|
33775
|
+
return count === 1 ? ce.True : ce.False;
|
|
33776
|
+
}
|
|
32857
33777
|
return void 0;
|
|
32858
33778
|
}
|
|
32859
|
-
|
|
32860
|
-
|
|
32861
|
-
|
|
32862
|
-
|
|
32863
|
-
|
|
32864
|
-
|
|
32865
|
-
|
|
32866
|
-
|
|
32867
|
-
|
|
32868
|
-
|
|
32869
|
-
|
|
33779
|
+
var LOGIC_FUNCTION_LIBRARY = {
|
|
33780
|
+
/**
|
|
33781
|
+
* Convert a boolean expression to Conjunctive Normal Form (CNF).
|
|
33782
|
+
* CNF is a conjunction (And) of disjunctions (Or) of literals.
|
|
33783
|
+
* A literal is either a variable or its negation.
|
|
33784
|
+
*
|
|
33785
|
+
* Example: (A ∨ B) ∧ (¬A ∨ C)
|
|
33786
|
+
*/
|
|
33787
|
+
ToCNF: {
|
|
33788
|
+
signature: "(boolean) -> boolean",
|
|
33789
|
+
evaluate: ([expr], { engine: ce }) => {
|
|
33790
|
+
if (!expr) return void 0;
|
|
33791
|
+
return toCNF(expr.evaluate(), ce);
|
|
33792
|
+
}
|
|
33793
|
+
},
|
|
33794
|
+
/**
|
|
33795
|
+
* Convert a boolean expression to Disjunctive Normal Form (DNF).
|
|
33796
|
+
* DNF is a disjunction (Or) of conjunctions (And) of literals.
|
|
33797
|
+
* A literal is either a variable or its negation.
|
|
33798
|
+
*
|
|
33799
|
+
* Example: (A ∧ B) ∨ (¬A ∧ C)
|
|
33800
|
+
*/
|
|
33801
|
+
ToDNF: {
|
|
33802
|
+
signature: "(boolean) -> boolean",
|
|
33803
|
+
evaluate: ([expr], { engine: ce }) => {
|
|
33804
|
+
if (!expr) return void 0;
|
|
33805
|
+
return toDNF(expr.evaluate(), ce);
|
|
33806
|
+
}
|
|
33807
|
+
},
|
|
33808
|
+
/**
|
|
33809
|
+
* Check if a boolean expression is satisfiable.
|
|
33810
|
+
* Returns True if there exists an assignment of truth values to variables
|
|
33811
|
+
* that makes the expression true.
|
|
33812
|
+
*/
|
|
33813
|
+
IsSatisfiable: {
|
|
33814
|
+
signature: "(boolean) -> boolean",
|
|
33815
|
+
evaluate: ([expr], { engine: ce }) => {
|
|
33816
|
+
if (!expr) return void 0;
|
|
33817
|
+
return isSatisfiable(expr, ce);
|
|
33818
|
+
}
|
|
33819
|
+
},
|
|
33820
|
+
/**
|
|
33821
|
+
* Check if a boolean expression is a tautology.
|
|
33822
|
+
* Returns True if the expression is true for all possible assignments
|
|
33823
|
+
* of truth values to variables.
|
|
33824
|
+
*/
|
|
33825
|
+
IsTautology: {
|
|
33826
|
+
signature: "(boolean) -> boolean",
|
|
33827
|
+
evaluate: ([expr], { engine: ce }) => {
|
|
33828
|
+
if (!expr) return void 0;
|
|
33829
|
+
return isTautology(expr, ce);
|
|
33830
|
+
}
|
|
33831
|
+
},
|
|
33832
|
+
/**
|
|
33833
|
+
* Generate a truth table for a boolean expression.
|
|
33834
|
+
* Returns a List of Lists, where each inner list contains the variable
|
|
33835
|
+
* assignments followed by the result.
|
|
33836
|
+
*
|
|
33837
|
+
* Example: TruthTable(["And", "A", "B"]) returns:
|
|
33838
|
+
* [["List", "A", "B", "Result"],
|
|
33839
|
+
* ["List", False, False, False],
|
|
33840
|
+
* ["List", False, True, False],
|
|
33841
|
+
* ["List", True, False, False],
|
|
33842
|
+
* ["List", True, True, True]]
|
|
33843
|
+
*/
|
|
33844
|
+
TruthTable: {
|
|
33845
|
+
signature: "(boolean) -> list",
|
|
33846
|
+
evaluate: ([expr], { engine: ce }) => {
|
|
33847
|
+
if (!expr) return void 0;
|
|
33848
|
+
return generateTruthTable(expr, ce);
|
|
33849
|
+
}
|
|
33850
|
+
}
|
|
33851
|
+
};
|
|
32870
33852
|
|
|
32871
33853
|
// src/compute-engine/library/number-theory.ts
|
|
32872
33854
|
var NUMBER_THEORY_LIBRARY = [
|
|
@@ -35398,7 +36380,7 @@ ${e.message}`);
|
|
|
35398
36380
|
"domains": [],
|
|
35399
36381
|
// 'domains': getDomainsDictionary(),
|
|
35400
36382
|
"linear-algebra": LINEAR_ALGEBRA_LIBRARY,
|
|
35401
|
-
"logic": LOGIC_LIBRARY,
|
|
36383
|
+
"logic": [LOGIC_LIBRARY, LOGIC_FUNCTION_LIBRARY],
|
|
35402
36384
|
"number-theory": NUMBER_THEORY_LIBRARY,
|
|
35403
36385
|
"numeric": [],
|
|
35404
36386
|
// @todo // 'numeric': [
|
|
@@ -35694,6 +36676,64 @@ Error in definition of "${name}"`,
|
|
|
35694
36676
|
const ce = expr.engine;
|
|
35695
36677
|
let result = null;
|
|
35696
36678
|
const operator2 = pattern.operator;
|
|
36679
|
+
if (operator2 === "Divide" && expr.numericValue !== null && !expr.denominator.is(1)) {
|
|
36680
|
+
const divideExpr = ce.function(
|
|
36681
|
+
"Divide",
|
|
36682
|
+
[expr.numerator, expr.denominator],
|
|
36683
|
+
{ canonical: false, structural: true }
|
|
36684
|
+
);
|
|
36685
|
+
return matchArguments(divideExpr, pattern.ops, substitution, options);
|
|
36686
|
+
}
|
|
36687
|
+
if (operator2 === "Divide" && expr.operator === "Multiply") {
|
|
36688
|
+
const ops = expr.ops;
|
|
36689
|
+
for (let i = 0; i < ops.length; i++) {
|
|
36690
|
+
const op = ops[i];
|
|
36691
|
+
if (op.numericValue !== null && op.numerator.is(1) && !op.denominator.is(1)) {
|
|
36692
|
+
const others = ops.filter((_, j) => j !== i);
|
|
36693
|
+
const numerator = others.length === 1 ? others[0] : ce.function("Multiply", others, { canonical: false });
|
|
36694
|
+
const divideExpr = ce.function(
|
|
36695
|
+
"Divide",
|
|
36696
|
+
[numerator, op.denominator],
|
|
36697
|
+
{ canonical: false, structural: true }
|
|
36698
|
+
);
|
|
36699
|
+
const result2 = matchArguments(
|
|
36700
|
+
divideExpr,
|
|
36701
|
+
pattern.ops,
|
|
36702
|
+
substitution,
|
|
36703
|
+
options
|
|
36704
|
+
);
|
|
36705
|
+
if (result2 !== null) return result2;
|
|
36706
|
+
}
|
|
36707
|
+
}
|
|
36708
|
+
}
|
|
36709
|
+
if (operator2 === "Power" && expr.operator === "Divide" && expr.op1.is(1)) {
|
|
36710
|
+
const powerExpr = ce.function(
|
|
36711
|
+
"Power",
|
|
36712
|
+
[expr.op2, ce.number(-1)],
|
|
36713
|
+
{ canonical: false, structural: true }
|
|
36714
|
+
);
|
|
36715
|
+
const result2 = matchArguments(
|
|
36716
|
+
powerExpr,
|
|
36717
|
+
pattern.ops,
|
|
36718
|
+
substitution,
|
|
36719
|
+
options
|
|
36720
|
+
);
|
|
36721
|
+
if (result2 !== null) return result2;
|
|
36722
|
+
}
|
|
36723
|
+
if (operator2 === "Power" && expr.operator === "Root") {
|
|
36724
|
+
const powerExpr = ce.function(
|
|
36725
|
+
"Power",
|
|
36726
|
+
[expr.op1, ce.box(["Divide", 1, expr.op2], { canonical: false })],
|
|
36727
|
+
{ canonical: false, structural: true }
|
|
36728
|
+
);
|
|
36729
|
+
const result2 = matchArguments(
|
|
36730
|
+
powerExpr,
|
|
36731
|
+
pattern.ops,
|
|
36732
|
+
substitution,
|
|
36733
|
+
options
|
|
36734
|
+
);
|
|
36735
|
+
if (result2 !== null) return result2;
|
|
36736
|
+
}
|
|
35697
36737
|
if (operator2.startsWith("_")) {
|
|
35698
36738
|
result = captureWildcard(operator2, ce.box(expr.operator), substitution);
|
|
35699
36739
|
if (result !== null)
|
|
@@ -38743,12 +39783,568 @@ Error in definition of "${name}"`,
|
|
|
38743
39783
|
}
|
|
38744
39784
|
};
|
|
38745
39785
|
|
|
39786
|
+
// src/compute-engine/symbolic/simplify-sum.ts
|
|
39787
|
+
function simplifySum(x) {
|
|
39788
|
+
if (x.operator !== "Sum") return void 0;
|
|
39789
|
+
let body = x.op1;
|
|
39790
|
+
const limits = x.op2;
|
|
39791
|
+
if (!body || !limits || limits.operator !== "Limits") return void 0;
|
|
39792
|
+
const index = limits.op1?.symbol;
|
|
39793
|
+
const lower = limits.op2;
|
|
39794
|
+
const upper = limits.op3;
|
|
39795
|
+
if (!index || !lower || !upper) return void 0;
|
|
39796
|
+
const ce = x.engine;
|
|
39797
|
+
if (body.operator === "Sum" || body.operator === "Product") {
|
|
39798
|
+
const simplifiedBody = body.simplify();
|
|
39799
|
+
if (!simplifiedBody.isSame(body)) {
|
|
39800
|
+
const newSum = ce.function("Sum", [simplifiedBody, limits]);
|
|
39801
|
+
return { value: newSum, because: "simplified nested sum/product" };
|
|
39802
|
+
}
|
|
39803
|
+
}
|
|
39804
|
+
if (lower.isNumberLiteral && upper.isNumberLiteral) {
|
|
39805
|
+
const lowerVal = lower.numericValue;
|
|
39806
|
+
const upperVal = upper.numericValue;
|
|
39807
|
+
if (typeof lowerVal === "number" && typeof upperVal === "number" && Number.isInteger(lowerVal) && Number.isInteger(upperVal)) {
|
|
39808
|
+
if (upperVal < lowerVal) {
|
|
39809
|
+
return { value: ce.Zero, because: "empty sum" };
|
|
39810
|
+
}
|
|
39811
|
+
if (upperVal === lowerVal) {
|
|
39812
|
+
return {
|
|
39813
|
+
value: body.subs({ [index]: lower }).simplify(),
|
|
39814
|
+
because: "single term sum"
|
|
39815
|
+
};
|
|
39816
|
+
}
|
|
39817
|
+
}
|
|
39818
|
+
}
|
|
39819
|
+
const bodyUnknowns = new Set(body.unknowns);
|
|
39820
|
+
if (!bodyUnknowns.has(index)) {
|
|
39821
|
+
const count = upper.sub(lower).add(ce.One).simplify();
|
|
39822
|
+
if (count.isNumberLiteral && count.numericValue !== null) {
|
|
39823
|
+
const countVal = typeof count.numericValue === "number" ? count.numericValue : count.numericValue.re;
|
|
39824
|
+
if (countVal <= 0) {
|
|
39825
|
+
return { value: ce.Zero, because: "empty sum" };
|
|
39826
|
+
}
|
|
39827
|
+
}
|
|
39828
|
+
return {
|
|
39829
|
+
value: count.mul(body.simplify()),
|
|
39830
|
+
because: "sum of constant"
|
|
39831
|
+
};
|
|
39832
|
+
}
|
|
39833
|
+
if (body.symbol === index) {
|
|
39834
|
+
const a = lower;
|
|
39835
|
+
const b = upper;
|
|
39836
|
+
const result = b.mul(b.add(ce.One)).sub(a.mul(a.sub(ce.One))).div(2);
|
|
39837
|
+
return { value: result.simplify(), because: "triangular number" };
|
|
39838
|
+
}
|
|
39839
|
+
if (body.operator === "Power" && body.op1?.symbol === index && body.op2?.is(2) && lower.is(1)) {
|
|
39840
|
+
const b = upper;
|
|
39841
|
+
const result = b.mul(b.add(ce.One)).mul(b.mul(2).add(ce.One)).div(6);
|
|
39842
|
+
return { value: result, because: "sum of squares" };
|
|
39843
|
+
}
|
|
39844
|
+
if (body.operator === "Power" && body.op1?.symbol === index && body.op2?.is(3) && lower.is(1)) {
|
|
39845
|
+
const b = upper;
|
|
39846
|
+
const triangular = b.mul(b.add(ce.One)).div(2);
|
|
39847
|
+
return { value: triangular.pow(2), because: "sum of cubes" };
|
|
39848
|
+
}
|
|
39849
|
+
if (body.operator === "Power" && body.op1?.is(-1) && body.op2?.symbol === index && lower.is(0)) {
|
|
39850
|
+
const b = upper;
|
|
39851
|
+
const result = ce.One.add(ce.number(-1).pow(b)).div(2);
|
|
39852
|
+
return { value: result, because: "alternating unit series" };
|
|
39853
|
+
}
|
|
39854
|
+
if (body.operator === "Multiply" && body.ops && lower.is(0)) {
|
|
39855
|
+
let hasAlternating = false;
|
|
39856
|
+
let hasIndex = false;
|
|
39857
|
+
for (const op of body.ops) {
|
|
39858
|
+
if (op.operator === "Power" && op.op1?.is(-1) && op.op2?.symbol === index) {
|
|
39859
|
+
hasAlternating = true;
|
|
39860
|
+
} else if (op.symbol === index) {
|
|
39861
|
+
hasIndex = true;
|
|
39862
|
+
}
|
|
39863
|
+
}
|
|
39864
|
+
if (hasAlternating && hasIndex && body.ops.length === 2) {
|
|
39865
|
+
const b = upper;
|
|
39866
|
+
const result = ce.function("Multiply", [
|
|
39867
|
+
ce.function("Power", [ce.number(-1), b]),
|
|
39868
|
+
ce.function("Floor", [
|
|
39869
|
+
ce.function("Divide", [ce.function("Add", [b, ce.One]), ce.number(2)])
|
|
39870
|
+
])
|
|
39871
|
+
]);
|
|
39872
|
+
return { value: result, because: "alternating linear series" };
|
|
39873
|
+
}
|
|
39874
|
+
}
|
|
39875
|
+
if (body.operator === "Add" && body.ops) {
|
|
39876
|
+
let constant = null;
|
|
39877
|
+
let coefficient = null;
|
|
39878
|
+
for (const term of body.ops) {
|
|
39879
|
+
const termUnknowns = new Set(term.unknowns);
|
|
39880
|
+
if (!termUnknowns.has(index)) {
|
|
39881
|
+
constant = constant ? constant.add(term) : term;
|
|
39882
|
+
} else if (term.symbol === index) {
|
|
39883
|
+
coefficient = coefficient ? coefficient.add(ce.One) : ce.One;
|
|
39884
|
+
} else if (term.operator === "Multiply" && term.ops?.some((op) => op.symbol === index)) {
|
|
39885
|
+
const coef = term.ops.filter((op) => op.symbol !== index);
|
|
39886
|
+
if (coef.length === term.ops.length - 1) {
|
|
39887
|
+
const c = coef.length === 1 ? coef[0] : ce.function("Multiply", coef);
|
|
39888
|
+
coefficient = coefficient ? coefficient.add(c) : c;
|
|
39889
|
+
}
|
|
39890
|
+
} else {
|
|
39891
|
+
constant = null;
|
|
39892
|
+
coefficient = null;
|
|
39893
|
+
break;
|
|
39894
|
+
}
|
|
39895
|
+
}
|
|
39896
|
+
if (constant !== null && coefficient !== null) {
|
|
39897
|
+
const m = lower;
|
|
39898
|
+
const b = upper;
|
|
39899
|
+
if (lower.is(0)) {
|
|
39900
|
+
const bPlus1 = ce.function("Add", [b, ce.One]);
|
|
39901
|
+
const inner = ce.function("Add", [
|
|
39902
|
+
constant,
|
|
39903
|
+
ce.function("Divide", [
|
|
39904
|
+
ce.function("Multiply", [coefficient, b]),
|
|
39905
|
+
ce.number(2)
|
|
39906
|
+
])
|
|
39907
|
+
]);
|
|
39908
|
+
const result = ce.function("Multiply", [bPlus1, inner]);
|
|
39909
|
+
return { value: result, because: "arithmetic progression" };
|
|
39910
|
+
} else {
|
|
39911
|
+
const numTerms = ce.function("Add", [
|
|
39912
|
+
ce.function("Subtract", [b, m]),
|
|
39913
|
+
ce.One
|
|
39914
|
+
]);
|
|
39915
|
+
const avgIndex = ce.function("Divide", [
|
|
39916
|
+
ce.function("Add", [m, b]),
|
|
39917
|
+
ce.number(2)
|
|
39918
|
+
]);
|
|
39919
|
+
const avgValue = ce.function("Add", [
|
|
39920
|
+
constant,
|
|
39921
|
+
ce.function("Multiply", [coefficient, avgIndex])
|
|
39922
|
+
]);
|
|
39923
|
+
const result = ce.function("Multiply", [numTerms, avgValue]);
|
|
39924
|
+
return { value: result, because: "arithmetic progression" };
|
|
39925
|
+
}
|
|
39926
|
+
}
|
|
39927
|
+
}
|
|
39928
|
+
if (body.operator === "Power" && body.op2?.symbol === index && !new Set(body.op1?.unknowns ?? []).has(index)) {
|
|
39929
|
+
const r = body.op1;
|
|
39930
|
+
const b = upper;
|
|
39931
|
+
if (lower.is(0)) {
|
|
39932
|
+
const numerator = ce.One.sub(r.pow(b.add(ce.One)));
|
|
39933
|
+
const denominator = ce.One.sub(r);
|
|
39934
|
+
return { value: numerator.div(denominator), because: "geometric series" };
|
|
39935
|
+
} else if (lower.is(1)) {
|
|
39936
|
+
const numerator = r.sub(r.pow(b.add(ce.One)));
|
|
39937
|
+
const denominator = ce.One.sub(r);
|
|
39938
|
+
return { value: numerator.div(denominator), because: "geometric series" };
|
|
39939
|
+
}
|
|
39940
|
+
}
|
|
39941
|
+
if (body.operator === "Binomial" && lower.is(0) && body.op2?.symbol === index) {
|
|
39942
|
+
const n = body.op1;
|
|
39943
|
+
if (n && upper.isSame(n)) {
|
|
39944
|
+
const result = ce.function("Power", [ce.number(2), n]);
|
|
39945
|
+
return { value: result, because: "sum of binomial coefficients" };
|
|
39946
|
+
}
|
|
39947
|
+
}
|
|
39948
|
+
if (body.operator === "Multiply" && body.ops && lower.is(0)) {
|
|
39949
|
+
let hasBinomial = false;
|
|
39950
|
+
let hasAlternating = false;
|
|
39951
|
+
let binomialN = null;
|
|
39952
|
+
for (const op of body.ops) {
|
|
39953
|
+
if (op.operator === "Binomial" && op.op2?.symbol === index) {
|
|
39954
|
+
hasBinomial = true;
|
|
39955
|
+
binomialN = op.op1 ?? null;
|
|
39956
|
+
} else if (op.operator === "Power" && op.op1?.is(-1) && op.op2?.symbol === index) {
|
|
39957
|
+
hasAlternating = true;
|
|
39958
|
+
}
|
|
39959
|
+
}
|
|
39960
|
+
if (hasBinomial && hasAlternating && binomialN && upper.isSame(binomialN)) {
|
|
39961
|
+
return { value: ce.Zero, because: "alternating binomial sum" };
|
|
39962
|
+
}
|
|
39963
|
+
let hasIndex = false;
|
|
39964
|
+
binomialN = null;
|
|
39965
|
+
hasBinomial = false;
|
|
39966
|
+
for (const op of body.ops) {
|
|
39967
|
+
if (op.symbol === index) {
|
|
39968
|
+
hasIndex = true;
|
|
39969
|
+
} else if (op.operator === "Binomial" && op.op2?.symbol === index) {
|
|
39970
|
+
hasBinomial = true;
|
|
39971
|
+
binomialN = op.op1 ?? null;
|
|
39972
|
+
}
|
|
39973
|
+
}
|
|
39974
|
+
if (hasIndex && hasBinomial && binomialN && upper.isSame(binomialN) && body.ops.length === 2) {
|
|
39975
|
+
const n = binomialN;
|
|
39976
|
+
const result = ce.function("Multiply", [
|
|
39977
|
+
n,
|
|
39978
|
+
ce.function("Power", [ce.number(2), n.sub(ce.One)])
|
|
39979
|
+
]);
|
|
39980
|
+
return { value: result, because: "weighted binomial sum" };
|
|
39981
|
+
}
|
|
39982
|
+
let hasIndexSquared = false;
|
|
39983
|
+
binomialN = null;
|
|
39984
|
+
hasBinomial = false;
|
|
39985
|
+
for (const op of body.ops) {
|
|
39986
|
+
if (op.operator === "Power" && op.op1?.symbol === index && op.op2?.is(2)) {
|
|
39987
|
+
hasIndexSquared = true;
|
|
39988
|
+
} else if (op.operator === "Binomial" && op.op2?.symbol === index) {
|
|
39989
|
+
hasBinomial = true;
|
|
39990
|
+
binomialN = op.op1 ?? null;
|
|
39991
|
+
}
|
|
39992
|
+
}
|
|
39993
|
+
if (hasIndexSquared && hasBinomial && binomialN && upper.isSame(binomialN) && body.ops.length === 2) {
|
|
39994
|
+
const n = binomialN;
|
|
39995
|
+
const result = ce.function("Multiply", [
|
|
39996
|
+
n,
|
|
39997
|
+
n.add(ce.One),
|
|
39998
|
+
ce.function("Power", [ce.number(2), n.sub(ce.number(2))])
|
|
39999
|
+
]);
|
|
40000
|
+
return { value: result, because: "weighted squared binomial sum" };
|
|
40001
|
+
}
|
|
40002
|
+
let hasIndexCubed = false;
|
|
40003
|
+
binomialN = null;
|
|
40004
|
+
hasBinomial = false;
|
|
40005
|
+
for (const op of body.ops) {
|
|
40006
|
+
if (op.operator === "Power" && op.op1?.symbol === index && op.op2?.is(3)) {
|
|
40007
|
+
hasIndexCubed = true;
|
|
40008
|
+
} else if (op.operator === "Binomial" && op.op2?.symbol === index) {
|
|
40009
|
+
hasBinomial = true;
|
|
40010
|
+
binomialN = op.op1 ?? null;
|
|
40011
|
+
}
|
|
40012
|
+
}
|
|
40013
|
+
if (hasIndexCubed && hasBinomial && binomialN && upper.isSame(binomialN) && body.ops.length === 2) {
|
|
40014
|
+
const n = binomialN;
|
|
40015
|
+
const result = ce.function("Multiply", [
|
|
40016
|
+
ce.function("Power", [n, ce.number(2)]),
|
|
40017
|
+
n.add(ce.number(3)),
|
|
40018
|
+
ce.function("Power", [ce.number(2), n.sub(ce.number(3))])
|
|
40019
|
+
]);
|
|
40020
|
+
return { value: result, because: "weighted cubed binomial sum" };
|
|
40021
|
+
}
|
|
40022
|
+
let hasAltTerm = false;
|
|
40023
|
+
let hasIndexTerm = false;
|
|
40024
|
+
binomialN = null;
|
|
40025
|
+
hasBinomial = false;
|
|
40026
|
+
for (const op of body.ops) {
|
|
40027
|
+
if (op.operator === "Power" && op.op1?.is(-1) && op.op2?.symbol === index) {
|
|
40028
|
+
hasAltTerm = true;
|
|
40029
|
+
} else if (op.symbol === index) {
|
|
40030
|
+
hasIndexTerm = true;
|
|
40031
|
+
} else if (op.operator === "Binomial" && op.op2?.symbol === index) {
|
|
40032
|
+
hasBinomial = true;
|
|
40033
|
+
binomialN = op.op1 ?? null;
|
|
40034
|
+
}
|
|
40035
|
+
}
|
|
40036
|
+
if (hasAltTerm && hasIndexTerm && hasBinomial && binomialN && upper.isSame(binomialN) && body.ops.length === 3) {
|
|
40037
|
+
return { value: ce.Zero, because: "alternating weighted binomial sum" };
|
|
40038
|
+
}
|
|
40039
|
+
}
|
|
40040
|
+
if (body.operator === "Power" && body.op1?.operator === "Binomial" && body.op2?.is(2) && lower.is(0)) {
|
|
40041
|
+
const binomial2 = body.op1;
|
|
40042
|
+
const n = binomial2.op1;
|
|
40043
|
+
const k = binomial2.op2;
|
|
40044
|
+
if (n && k?.symbol === index && upper.isSame(n)) {
|
|
40045
|
+
const result = ce.function("Binomial", [
|
|
40046
|
+
ce.function("Multiply", [ce.number(2), n]),
|
|
40047
|
+
n
|
|
40048
|
+
]);
|
|
40049
|
+
return { value: result, because: "sum of binomial squares" };
|
|
40050
|
+
}
|
|
40051
|
+
}
|
|
40052
|
+
if (body.operator === "Multiply" && body.ops?.length === 2 && lower.is(1)) {
|
|
40053
|
+
const [op1, op2] = body.ops;
|
|
40054
|
+
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));
|
|
40055
|
+
if (isKTimesKPlus1) {
|
|
40056
|
+
const n = upper;
|
|
40057
|
+
const result = ce.function("Divide", [
|
|
40058
|
+
ce.function("Multiply", [
|
|
40059
|
+
n,
|
|
40060
|
+
ce.function("Add", [n, ce.One]),
|
|
40061
|
+
ce.function("Add", [n, ce.number(2)])
|
|
40062
|
+
]),
|
|
40063
|
+
ce.number(3)
|
|
40064
|
+
]);
|
|
40065
|
+
return { value: result, because: "sum of k*(k+1)" };
|
|
40066
|
+
}
|
|
40067
|
+
}
|
|
40068
|
+
if (body.operator === "Divide" && body.op1?.is(1) && body.op2?.operator === "Multiply") {
|
|
40069
|
+
const denom = body.op2;
|
|
40070
|
+
if (denom.ops?.length === 2) {
|
|
40071
|
+
const [d1, d2] = denom.ops;
|
|
40072
|
+
if (lower.is(1)) {
|
|
40073
|
+
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));
|
|
40074
|
+
if (isKTimesKPlus1) {
|
|
40075
|
+
const n = upper;
|
|
40076
|
+
const result = n.div(n.add(ce.One));
|
|
40077
|
+
return { value: result, because: "partial fractions (telescoping)" };
|
|
40078
|
+
}
|
|
40079
|
+
}
|
|
40080
|
+
if (lower.is(2)) {
|
|
40081
|
+
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));
|
|
40082
|
+
if (isKTimesKMinus1) {
|
|
40083
|
+
const n = upper;
|
|
40084
|
+
const result = n.sub(ce.One).div(n);
|
|
40085
|
+
return { value: result, because: "partial fractions (telescoping k*(k-1))" };
|
|
40086
|
+
}
|
|
40087
|
+
}
|
|
40088
|
+
}
|
|
40089
|
+
}
|
|
40090
|
+
if (body.operator === "Multiply" && body.ops) {
|
|
40091
|
+
const constantFactors = [];
|
|
40092
|
+
const indexFactors = [];
|
|
40093
|
+
for (const factor2 of body.ops) {
|
|
40094
|
+
const factorUnknowns = new Set(factor2.unknowns);
|
|
40095
|
+
if (factorUnknowns.has(index)) {
|
|
40096
|
+
indexFactors.push(factor2);
|
|
40097
|
+
} else {
|
|
40098
|
+
constantFactors.push(factor2);
|
|
40099
|
+
}
|
|
40100
|
+
}
|
|
40101
|
+
if (constantFactors.length > 0 && indexFactors.length > 0) {
|
|
40102
|
+
const constant = constantFactors.length === 1 ? constantFactors[0] : ce.function("Multiply", constantFactors);
|
|
40103
|
+
const indexPart = indexFactors.length === 1 ? indexFactors[0] : ce.function("Multiply", indexFactors);
|
|
40104
|
+
const newSum = ce.function("Sum", [indexPart, limits]);
|
|
40105
|
+
return {
|
|
40106
|
+
value: constant.mul(newSum),
|
|
40107
|
+
because: "factor out constant from sum"
|
|
40108
|
+
};
|
|
40109
|
+
}
|
|
40110
|
+
}
|
|
40111
|
+
return void 0;
|
|
40112
|
+
}
|
|
40113
|
+
|
|
40114
|
+
// src/compute-engine/symbolic/simplify-product.ts
|
|
40115
|
+
function simplifyProduct(x) {
|
|
40116
|
+
if (x.operator !== "Product") return void 0;
|
|
40117
|
+
let body = x.op1;
|
|
40118
|
+
const limits = x.op2;
|
|
40119
|
+
if (!body || !limits || limits.operator !== "Limits") return void 0;
|
|
40120
|
+
const index = limits.op1?.symbol;
|
|
40121
|
+
const lower = limits.op2;
|
|
40122
|
+
const upper = limits.op3;
|
|
40123
|
+
if (!index || !lower || !upper) return void 0;
|
|
40124
|
+
const ce = x.engine;
|
|
40125
|
+
if (body.operator === "Sum" || body.operator === "Product") {
|
|
40126
|
+
const simplifiedBody = body.simplify();
|
|
40127
|
+
if (!simplifiedBody.isSame(body)) {
|
|
40128
|
+
const newProduct = ce.function("Product", [simplifiedBody, limits]);
|
|
40129
|
+
return { value: newProduct, because: "simplified nested sum/product" };
|
|
40130
|
+
}
|
|
40131
|
+
}
|
|
40132
|
+
if (lower.isNumberLiteral && upper.isNumberLiteral) {
|
|
40133
|
+
const lowerVal = lower.numericValue;
|
|
40134
|
+
const upperVal = upper.numericValue;
|
|
40135
|
+
if (typeof lowerVal === "number" && typeof upperVal === "number" && Number.isInteger(lowerVal) && Number.isInteger(upperVal)) {
|
|
40136
|
+
if (upperVal < lowerVal) {
|
|
40137
|
+
return { value: ce.One, because: "empty product" };
|
|
40138
|
+
}
|
|
40139
|
+
if (upperVal === lowerVal) {
|
|
40140
|
+
return {
|
|
40141
|
+
value: body.subs({ [index]: lower }).simplify(),
|
|
40142
|
+
because: "single term product"
|
|
40143
|
+
};
|
|
40144
|
+
}
|
|
40145
|
+
}
|
|
40146
|
+
}
|
|
40147
|
+
const bodyUnknowns = new Set(body.unknowns);
|
|
40148
|
+
if (!bodyUnknowns.has(index)) {
|
|
40149
|
+
const count = upper.sub(lower).add(ce.One).simplify();
|
|
40150
|
+
if (count.isNumberLiteral && count.numericValue !== null) {
|
|
40151
|
+
const countVal = typeof count.numericValue === "number" ? count.numericValue : count.numericValue.re;
|
|
40152
|
+
if (countVal <= 0) {
|
|
40153
|
+
return { value: ce.One, because: "empty product" };
|
|
40154
|
+
}
|
|
40155
|
+
}
|
|
40156
|
+
return {
|
|
40157
|
+
value: body.simplify().pow(count),
|
|
40158
|
+
because: "product of constant"
|
|
40159
|
+
};
|
|
40160
|
+
}
|
|
40161
|
+
if (body.symbol === index && lower.is(1)) {
|
|
40162
|
+
return {
|
|
40163
|
+
value: ce.function("Factorial", [upper]),
|
|
40164
|
+
because: "factorial"
|
|
40165
|
+
};
|
|
40166
|
+
}
|
|
40167
|
+
if (body.operator === "Add" && body.ops?.length === 2 && lower.is(1)) {
|
|
40168
|
+
const [op1, op2] = body.ops;
|
|
40169
|
+
let indexTerm = null;
|
|
40170
|
+
let constTerm = null;
|
|
40171
|
+
if (op1.symbol === index && !new Set(op2.unknowns).has(index)) {
|
|
40172
|
+
indexTerm = op1;
|
|
40173
|
+
constTerm = op2;
|
|
40174
|
+
} else if (op2.symbol === index && !new Set(op1.unknowns).has(index)) {
|
|
40175
|
+
indexTerm = op2;
|
|
40176
|
+
constTerm = op1;
|
|
40177
|
+
}
|
|
40178
|
+
if (indexTerm && constTerm) {
|
|
40179
|
+
const b = upper;
|
|
40180
|
+
const c = constTerm;
|
|
40181
|
+
const result = ce.function("Divide", [
|
|
40182
|
+
ce.function("Factorial", [ce.function("Add", [b, c])]),
|
|
40183
|
+
ce.function("Factorial", [c])
|
|
40184
|
+
]);
|
|
40185
|
+
return { value: result, because: "shifted factorial" };
|
|
40186
|
+
}
|
|
40187
|
+
}
|
|
40188
|
+
if (body.operator === "Divide" && lower.is(1)) {
|
|
40189
|
+
const num = body.op1;
|
|
40190
|
+
const denom = body.op2;
|
|
40191
|
+
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))) {
|
|
40192
|
+
return { value: upper.add(ce.One), because: "telescoping product" };
|
|
40193
|
+
}
|
|
40194
|
+
}
|
|
40195
|
+
if (body.operator === "Add" && body.ops?.length === 2 && lower.is(2)) {
|
|
40196
|
+
let hasOne = false;
|
|
40197
|
+
let hasNegInvSq = false;
|
|
40198
|
+
for (const op of body.ops) {
|
|
40199
|
+
if (op.is(1)) {
|
|
40200
|
+
hasOne = true;
|
|
40201
|
+
} else if (op.operator === "Negate" && op.op1?.operator === "Power" && op.op1.op1?.symbol === index && op.op1.op2?.is(-2)) {
|
|
40202
|
+
hasNegInvSq = true;
|
|
40203
|
+
} else if (op.operator === "Power" && op.op1?.symbol === index && op.op2?.is(-2)) {
|
|
40204
|
+
} else if (op.operator === "Multiply" && op.ops?.some((o) => o.is(-1)) && op.ops?.some(
|
|
40205
|
+
(o) => o.operator === "Power" && o.op1?.symbol === index && o.op2?.is(-2)
|
|
40206
|
+
)) {
|
|
40207
|
+
hasNegInvSq = true;
|
|
40208
|
+
}
|
|
40209
|
+
}
|
|
40210
|
+
if (hasOne && hasNegInvSq) {
|
|
40211
|
+
const n = upper;
|
|
40212
|
+
const result = ce.function("Divide", [
|
|
40213
|
+
ce.function("Add", [n, ce.One]),
|
|
40214
|
+
ce.function("Multiply", [ce.number(2), n])
|
|
40215
|
+
]);
|
|
40216
|
+
return { value: result, because: "Wallis-like product" };
|
|
40217
|
+
}
|
|
40218
|
+
}
|
|
40219
|
+
if (body.operator === "Add" && body.ops?.length === 2 && lower.is(1)) {
|
|
40220
|
+
const [op1, op2] = body.ops;
|
|
40221
|
+
let hasLinearTerm = false;
|
|
40222
|
+
let coefficient = 0;
|
|
40223
|
+
let constantTerm = 0;
|
|
40224
|
+
for (const op of body.ops) {
|
|
40225
|
+
if (op.isNumberLiteral && typeof op.numericValue === "number") {
|
|
40226
|
+
constantTerm = op.numericValue;
|
|
40227
|
+
} else if (op.operator === "Multiply" && op.ops?.length === 2) {
|
|
40228
|
+
const [a, b] = op.ops;
|
|
40229
|
+
if (a.isNumberLiteral && typeof a.numericValue === "number" && b.symbol === index) {
|
|
40230
|
+
coefficient = a.numericValue;
|
|
40231
|
+
hasLinearTerm = true;
|
|
40232
|
+
} else if (b.isNumberLiteral && typeof b.numericValue === "number" && a.symbol === index) {
|
|
40233
|
+
coefficient = b.numericValue;
|
|
40234
|
+
hasLinearTerm = true;
|
|
40235
|
+
}
|
|
40236
|
+
}
|
|
40237
|
+
}
|
|
40238
|
+
if (hasLinearTerm && coefficient === 2 && constantTerm === -1) {
|
|
40239
|
+
const b = upper;
|
|
40240
|
+
const result = ce.function("Factorial2", [
|
|
40241
|
+
ce.function("Subtract", [
|
|
40242
|
+
ce.function("Multiply", [ce.number(2), b]),
|
|
40243
|
+
ce.One
|
|
40244
|
+
])
|
|
40245
|
+
]);
|
|
40246
|
+
return { value: result, because: "odd double factorial" };
|
|
40247
|
+
}
|
|
40248
|
+
}
|
|
40249
|
+
if (body.operator === "Multiply" && body.ops?.length === 2 && lower.is(1)) {
|
|
40250
|
+
const [op1, op2] = body.ops;
|
|
40251
|
+
if (op1.is(2) && op2.symbol === index || op2.is(2) && op1.symbol === index) {
|
|
40252
|
+
const b = upper;
|
|
40253
|
+
const result = ce.function("Multiply", [
|
|
40254
|
+
ce.function("Power", [ce.number(2), b]),
|
|
40255
|
+
ce.function("Factorial", [b])
|
|
40256
|
+
]);
|
|
40257
|
+
return { value: result, because: "even double factorial" };
|
|
40258
|
+
}
|
|
40259
|
+
}
|
|
40260
|
+
if (body.operator === "Add" && body.ops?.length === 2 && lower.is(0)) {
|
|
40261
|
+
let base = null;
|
|
40262
|
+
let hasIndex = false;
|
|
40263
|
+
for (const op of body.ops) {
|
|
40264
|
+
if (op.symbol === index) {
|
|
40265
|
+
hasIndex = true;
|
|
40266
|
+
} else if (!new Set(op.unknowns).has(index)) {
|
|
40267
|
+
base = op;
|
|
40268
|
+
}
|
|
40269
|
+
}
|
|
40270
|
+
if (hasIndex && base) {
|
|
40271
|
+
const n = upper.add(ce.One).simplify();
|
|
40272
|
+
const result = ce.function("Pochhammer", [base, n]);
|
|
40273
|
+
return { value: result, because: "rising factorial (Pochhammer)" };
|
|
40274
|
+
}
|
|
40275
|
+
}
|
|
40276
|
+
if (lower.is(0)) {
|
|
40277
|
+
let base = null;
|
|
40278
|
+
let hasNegIndex = false;
|
|
40279
|
+
if (body.operator === "Subtract" && body.ops?.length === 2) {
|
|
40280
|
+
const [op1, op2] = body.ops;
|
|
40281
|
+
if (op2.symbol === index && !new Set(op1.unknowns).has(index)) {
|
|
40282
|
+
base = op1;
|
|
40283
|
+
hasNegIndex = true;
|
|
40284
|
+
}
|
|
40285
|
+
} else if (body.operator === "Add" && body.ops?.length === 2) {
|
|
40286
|
+
for (const op of body.ops) {
|
|
40287
|
+
if (op.operator === "Negate" && op.op1?.symbol === index) {
|
|
40288
|
+
hasNegIndex = true;
|
|
40289
|
+
} else if (!new Set(op.unknowns).has(index)) {
|
|
40290
|
+
base = op;
|
|
40291
|
+
}
|
|
40292
|
+
}
|
|
40293
|
+
}
|
|
40294
|
+
if (hasNegIndex && base) {
|
|
40295
|
+
const n = upper.add(ce.One).simplify();
|
|
40296
|
+
const result = ce.function("Divide", [
|
|
40297
|
+
ce.function("Factorial", [base]),
|
|
40298
|
+
ce.function("Factorial", [base.sub(n)])
|
|
40299
|
+
]);
|
|
40300
|
+
return { value: result, because: "falling factorial" };
|
|
40301
|
+
}
|
|
40302
|
+
}
|
|
40303
|
+
if (body.operator === "Multiply" && body.ops) {
|
|
40304
|
+
const constantFactors = [];
|
|
40305
|
+
const indexFactors = [];
|
|
40306
|
+
for (const factor2 of body.ops) {
|
|
40307
|
+
const factorUnknowns = new Set(factor2.unknowns);
|
|
40308
|
+
if (factorUnknowns.has(index)) {
|
|
40309
|
+
indexFactors.push(factor2);
|
|
40310
|
+
} else {
|
|
40311
|
+
constantFactors.push(factor2);
|
|
40312
|
+
}
|
|
40313
|
+
}
|
|
40314
|
+
if (constantFactors.length > 0 && indexFactors.length > 0) {
|
|
40315
|
+
const constant = constantFactors.length === 1 ? constantFactors[0] : ce.function("Multiply", constantFactors);
|
|
40316
|
+
const indexPart = indexFactors.length === 1 ? indexFactors[0] : ce.function("Multiply", indexFactors);
|
|
40317
|
+
const count = upper.sub(lower).add(ce.One).simplify();
|
|
40318
|
+
const newProduct = ce.function("Product", [indexPart, limits]);
|
|
40319
|
+
return {
|
|
40320
|
+
value: constant.pow(count).mul(newProduct),
|
|
40321
|
+
because: "factor out constant from product"
|
|
40322
|
+
};
|
|
40323
|
+
}
|
|
40324
|
+
}
|
|
40325
|
+
return void 0;
|
|
40326
|
+
}
|
|
40327
|
+
|
|
38746
40328
|
// src/compute-engine/symbolic/simplify-rules.ts
|
|
38747
40329
|
var SIMPLIFY_RULES = [
|
|
38748
40330
|
// The Golden Ratio, a constant that can be simplified
|
|
38749
40331
|
"\\varphi -> \\frac{1+\\sqrt{5}}{2}",
|
|
38750
40332
|
simplifyRelationalOperator,
|
|
38751
40333
|
simplifySystemOfEquations,
|
|
40334
|
+
//
|
|
40335
|
+
// Cancel common polynomial factors in Divide expressions
|
|
40336
|
+
// e.g., (x² - 1)/(x - 1) → x + 1
|
|
40337
|
+
// Must run before expand to preserve polynomial structure
|
|
40338
|
+
//
|
|
40339
|
+
(x) => {
|
|
40340
|
+
if (x.operator !== "Divide") return void 0;
|
|
40341
|
+
const unknowns = x.unknowns;
|
|
40342
|
+
if (unknowns.length !== 1) return void 0;
|
|
40343
|
+
const variable = unknowns[0];
|
|
40344
|
+
const result = cancelCommonFactors(x, variable);
|
|
40345
|
+
if (result.isSame(x)) return void 0;
|
|
40346
|
+
return { value: result, because: "cancel common polynomial factors" };
|
|
40347
|
+
},
|
|
38752
40348
|
// Try to expand the expression:
|
|
38753
40349
|
// x*(y+z) -> x*y + x*z
|
|
38754
40350
|
// { replace: (x) => expand(x) ?? undefined, id: 'expand' },
|
|
@@ -38838,7 +40434,8 @@ Error in definition of "${name}"`,
|
|
|
38838
40434
|
const ce = x.engine;
|
|
38839
40435
|
if (s === void 0) return void 0;
|
|
38840
40436
|
if (s === "positive") return { value: ce.One, because: "sign positive" };
|
|
38841
|
-
if (s === "negative")
|
|
40437
|
+
if (s === "negative")
|
|
40438
|
+
return { value: ce.NegativeOne, because: "sign negative" };
|
|
38842
40439
|
if (s === "zero") return { value: ce.Zero, because: "sign zero" };
|
|
38843
40440
|
if (s === "unsigned") return { value: ce.NaN, because: "sign unsinged" };
|
|
38844
40441
|
return void 0;
|
|
@@ -38921,14 +40518,10 @@ Error in definition of "${name}"`,
|
|
|
38921
40518
|
because: "congruent"
|
|
38922
40519
|
};
|
|
38923
40520
|
},
|
|
38924
|
-
//
|
|
38925
|
-
|
|
38926
|
-
//
|
|
38927
|
-
|
|
38928
|
-
if (x.operator === "Max") {
|
|
38929
|
-
}
|
|
38930
|
-
return void 0;
|
|
38931
|
-
},
|
|
40521
|
+
// Sum simplification (extracted to simplify-sum.ts)
|
|
40522
|
+
simplifySum,
|
|
40523
|
+
// Product simplification (extracted to simplify-product.ts)
|
|
40524
|
+
simplifyProduct,
|
|
38932
40525
|
//
|
|
38933
40526
|
// Constructible values of trig functions
|
|
38934
40527
|
//
|
|
@@ -41154,7 +42747,8 @@ Error in definition of "${name}"`,
|
|
|
41154
42747
|
return BoxedType.unknown;
|
|
41155
42748
|
},
|
|
41156
42749
|
parseUnexpectedToken: (_lhs, _parser) => null,
|
|
41157
|
-
preserveLatex: false
|
|
42750
|
+
preserveLatex: false,
|
|
42751
|
+
quantifierScope: "tight"
|
|
41158
42752
|
};
|
|
41159
42753
|
const result = parse2(
|
|
41160
42754
|
asLatexString(latex) ?? latex,
|
|
@@ -41307,10 +42901,10 @@ Error in definition of "${name}"`,
|
|
|
41307
42901
|
}
|
|
41308
42902
|
|
|
41309
42903
|
// src/compute-engine.ts
|
|
41310
|
-
var version = "0.
|
|
42904
|
+
var version = "0.32.1";
|
|
41311
42905
|
globalThis[Symbol.for("io.cortexjs.compute-engine")] = {
|
|
41312
42906
|
ComputeEngine: ComputeEngine.prototype.constructor,
|
|
41313
|
-
version: "0.
|
|
42907
|
+
version: "0.32.1"
|
|
41314
42908
|
};
|
|
41315
42909
|
return __toCommonJS(compute_engine_exports);
|
|
41316
42910
|
})();
|