nerdamer 1.1.13 → 2.0.0-rc.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/LICENSE.md +184 -0
- package/README.md +293 -312
- package/dist/bundle.js +2 -0
- package/dist/bundle.js.LICENSE.txt +7 -0
- package/dist/parser.js +2 -0
- package/dist/parser.js.LICENSE.txt +7 -0
- package/docs-data/parser-functions.json +1960 -0
- package/index.d.ts +10 -426
- package/output/algebra/adapters.d.ts +33 -0
- package/output/algebra/adapters.js +109 -0
- package/output/algebra/algorithms/arith.d.ts +84 -0
- package/output/algebra/algorithms/arith.js +323 -0
- package/output/algebra/algorithms/factor.d.ts +3 -0
- package/output/algebra/algorithms/factor.js +5 -0
- package/output/algebra/algorithms/factorMultivariate.d.ts +23 -0
- package/output/algebra/algorithms/factorMultivariate.js +2393 -0
- package/output/algebra/algorithms/factorUnivariate.d.ts +72 -0
- package/output/algebra/algorithms/factorUnivariate.js +1072 -0
- package/output/algebra/algorithms/gcd.d.ts +22 -0
- package/output/algebra/algorithms/gcd.js +690 -0
- package/output/algebra/algorithms/groebnerBase.d.ts +157 -0
- package/output/algebra/algorithms/groebnerBase.js +1166 -0
- package/output/algebra/algorithms/multiPoly/MultiPoly.d.ts +137 -0
- package/output/algebra/algorithms/multiPoly/MultiPoly.js +346 -0
- package/output/algebra/algorithms/poly.d.ts +228 -0
- package/output/algebra/algorithms/poly.js +1299 -0
- package/output/algebra/algorithms/rational.d.ts +17 -0
- package/output/algebra/algorithms/rational.js +115 -0
- package/output/algebra/factor/factor.d.ts +62 -0
- package/output/algebra/factor/factor.js +158 -0
- package/output/algebra/gcd/gcd.d.ts +29 -0
- package/output/algebra/gcd/gcd.js +141 -0
- package/output/algebra/groebner.d.ts +21 -0
- package/output/algebra/groebner.js +42 -0
- package/output/algebra/partfrac.d.ts +19 -0
- package/output/algebra/partfrac.js +398 -0
- package/output/algebra/polynomialize.d.ts +20 -0
- package/output/algebra/polynomialize.js +24 -0
- package/output/algebra/simplify/complexsimp.d.ts +7 -0
- package/output/algebra/simplify/complexsimp.js +24 -0
- package/output/algebra/simplify/factorCommon.d.ts +13 -0
- package/output/algebra/simplify/factorCommon.js +136 -0
- package/output/algebra/simplify/funcsimp.d.ts +26 -0
- package/output/algebra/simplify/funcsimp.js +633 -0
- package/output/algebra/simplify/invtrigrewrite.d.ts +10 -0
- package/output/algebra/simplify/invtrigrewrite.js +96 -0
- package/output/algebra/simplify/ratsimp.d.ts +21 -0
- package/output/algebra/simplify/ratsimp.js +140 -0
- package/output/algebra/simplify/simplify.d.ts +25 -0
- package/output/algebra/simplify/simplify.js +228 -0
- package/output/algebra/simplify/trigreduce.d.ts +38 -0
- package/output/algebra/simplify/trigreduce.js +424 -0
- package/output/algebra/simplify/trigrewrite.d.ts +17 -0
- package/output/algebra/simplify/trigrewrite.js +156 -0
- package/output/algebra/simplify/trigsimp.d.ts +11 -0
- package/output/algebra/simplify/trigsimp.js +369 -0
- package/output/algebra/simplify/utils.d.ts +32 -0
- package/output/algebra/simplify/utils.js +56 -0
- package/output/algebra/utils.d.ts +32 -0
- package/output/algebra/utils.js +48 -0
- package/output/api/advanced.d.ts +7 -0
- package/output/api/advanced.js +18 -0
- package/output/api/algebra.d.ts +17 -0
- package/output/api/algebra.js +32 -0
- package/output/api/assumptions.d.ts +4 -0
- package/output/api/assumptions.js +11 -0
- package/output/api/calculus.d.ts +9 -0
- package/output/api/calculus.js +21 -0
- package/output/api/core.d.ts +17 -0
- package/output/api/core.js +41 -0
- package/output/api/debug.d.ts +16 -0
- package/output/api/debug.js +23 -0
- package/output/api/parser.d.ts +85 -0
- package/output/api/parser.js +16 -0
- package/output/api/solve.d.ts +10 -0
- package/output/api/solve.js +16 -0
- package/output/api/structures.d.ts +10 -0
- package/output/api/structures.js +22 -0
- package/output/calculus/derivative/diff.d.ts +30 -0
- package/output/calculus/derivative/diff.js +238 -0
- package/output/calculus/fresnel.d.ts +16 -0
- package/output/calculus/fresnel.js +39 -0
- package/output/calculus/integrate/byParts.d.ts +18 -0
- package/output/calculus/integrate/byParts.js +339 -0
- package/output/calculus/integrate/bySubstitution.d.ts +135 -0
- package/output/calculus/integrate/bySubstitution.js +411 -0
- package/output/calculus/integrate/integrate.d.ts +38 -0
- package/output/calculus/integrate/integrate.js +652 -0
- package/output/calculus/integrate/integrationTable.d.ts +2 -0
- package/output/calculus/integrate/integrationTable.js +914 -0
- package/output/calculus/integrate/utils.d.ts +28 -0
- package/output/calculus/integrate/utils.js +96 -0
- package/output/calculus/laplace/ilaplace.d.ts +31 -0
- package/output/calculus/laplace/ilaplace.js +192 -0
- package/output/calculus/laplace/ilaplaceTable.d.ts +2 -0
- package/output/calculus/laplace/ilaplaceTable.js +200 -0
- package/output/calculus/laplace/laplace.d.ts +22 -0
- package/output/calculus/laplace/laplace.js +109 -0
- package/output/calculus/laplace/laplaceTable.d.ts +2 -0
- package/output/calculus/laplace/laplaceTable.js +187 -0
- package/output/calculus/limit/limit.d.ts +35 -0
- package/output/calculus/limit/limit.js +1183 -0
- package/output/calculus/limit/limitsTable.d.ts +2 -0
- package/output/calculus/limit/limitsTable.js +7 -0
- package/output/core/Settings.d.ts +32 -0
- package/output/core/Settings.js +68 -0
- package/output/core/adapters.d.ts +18 -0
- package/output/core/adapters.js +40 -0
- package/output/core/classes/assumption/Assumption.d.ts +218 -0
- package/output/core/classes/assumption/Assumption.js +605 -0
- package/output/core/classes/assumption/assertiveFunctions.d.ts +6 -0
- package/output/core/classes/assumption/assertiveFunctions.js +64 -0
- package/output/core/classes/assumption/assume.d.ts +90 -0
- package/output/core/classes/assumption/assume.js +145 -0
- package/output/core/classes/collection/Collection.d.ts +107 -0
- package/output/core/classes/collection/Collection.js +231 -0
- package/output/core/classes/complex/Complex.d.ts +99 -0
- package/output/core/classes/complex/Complex.js +135 -0
- package/output/core/classes/decimalSet/DecimalSet.d.ts +226 -0
- package/output/core/classes/decimalSet/DecimalSet.js +453 -0
- package/output/core/classes/dictionary/Dictionary.d.ts +102 -0
- package/output/core/classes/dictionary/Dictionary.js +213 -0
- package/output/core/classes/equation/Equation.d.ts +256 -0
- package/output/core/classes/equation/Equation.js +350 -0
- package/output/core/classes/expression/CoeffObject.d.ts +100 -0
- package/output/core/classes/expression/CoeffObject.js +198 -0
- package/output/core/classes/expression/Expression.d.ts +1674 -0
- package/output/core/classes/expression/Expression.js +2332 -0
- package/output/core/classes/expression/analysis.d.ts +25 -0
- package/output/core/classes/expression/analysis.js +218 -0
- package/output/core/classes/expression/collect.d.ts +9 -0
- package/output/core/classes/expression/collect.js +49 -0
- package/output/core/classes/expression/format.d.ts +45 -0
- package/output/core/classes/expression/format.js +217 -0
- package/output/core/classes/expression/products.d.ts +23 -0
- package/output/core/classes/expression/products.js +115 -0
- package/output/core/classes/expression/shortcuts.d.ts +35 -0
- package/output/core/classes/expression/shortcuts.js +129 -0
- package/output/core/classes/expression/traversal.d.ts +31 -0
- package/output/core/classes/expression/traversal.js +216 -0
- package/output/core/classes/expression/trig.d.ts +25 -0
- package/output/core/classes/expression/trig.js +40 -0
- package/output/core/classes/expression/utils.d.ts +52 -0
- package/output/core/classes/expression/utils.js +189 -0
- package/output/core/classes/lookupTable/LookupTable.d.ts +12 -0
- package/output/core/classes/lookupTable/LookupTable.js +55 -0
- package/output/core/classes/matrix/Matrix.d.ts +227 -0
- package/output/core/classes/matrix/Matrix.js +889 -0
- package/output/core/classes/matrix/Sylvester.d.ts +11 -0
- package/output/core/classes/matrix/Sylvester.js +54 -0
- package/output/core/classes/matrix/functions.d.ts +26 -0
- package/output/core/classes/matrix/functions.js +52 -0
- package/output/core/classes/matrix/utils.d.ts +9 -0
- package/output/core/classes/matrix/utils.js +22 -0
- package/output/core/classes/parser/Parser.d.ts +480 -0
- package/output/core/classes/parser/Parser.js +1812 -0
- package/output/core/classes/parser/Token.d.ts +58 -0
- package/output/core/classes/parser/Token.js +137 -0
- package/output/core/classes/parser/constants.d.ts +160 -0
- package/output/core/classes/parser/constants.js +227 -0
- package/output/core/classes/parser/helpers.d.ts +21 -0
- package/output/core/classes/parser/helpers.js +42 -0
- package/output/core/classes/parser/operations/add.d.ts +15 -0
- package/output/core/classes/parser/operations/add.js +238 -0
- package/output/core/classes/parser/operations/comma.d.ts +7 -0
- package/output/core/classes/parser/operations/comma.js +11 -0
- package/output/core/classes/parser/operations/compare.d.ts +21 -0
- package/output/core/classes/parser/operations/compare.js +461 -0
- package/output/core/classes/parser/operations/divide.d.ts +2 -0
- package/output/core/classes/parser/operations/divide.js +72 -0
- package/output/core/classes/parser/operations/functions.d.ts +46 -0
- package/output/core/classes/parser/operations/functions.js +430 -0
- package/output/core/classes/parser/operations/multiply.d.ts +11 -0
- package/output/core/classes/parser/operations/multiply.js +321 -0
- package/output/core/classes/parser/operations/power.d.ts +48 -0
- package/output/core/classes/parser/operations/power.js +673 -0
- package/output/core/classes/parser/operations/subtract.d.ts +3 -0
- package/output/core/classes/parser/operations/subtract.js +35 -0
- package/output/core/classes/parser/preprocess.d.ts +14 -0
- package/output/core/classes/parser/preprocess.js +259 -0
- package/output/core/classes/parser/scripting/controlFlow.d.ts +121 -0
- package/output/core/classes/parser/scripting/controlFlow.js +355 -0
- package/output/core/classes/parser/scripting/evaluate.d.ts +10 -0
- package/output/core/classes/parser/scripting/evaluate.js +112 -0
- package/output/core/classes/parser/scripting/functions.d.ts +14 -0
- package/output/core/classes/parser/scripting/functions.js +59 -0
- package/output/core/classes/parser/scripting/scope.d.ts +35 -0
- package/output/core/classes/parser/scripting/scope.js +155 -0
- package/output/core/classes/parser/types.d.ts +125 -0
- package/output/core/classes/parser/types.js +2 -0
- package/output/core/classes/parser/wrappers/IndexedReference.d.ts +31 -0
- package/output/core/classes/parser/wrappers/IndexedReference.js +68 -0
- package/output/core/classes/parser/wrappers/KeyValuePair.d.ts +24 -0
- package/output/core/classes/parser/wrappers/KeyValuePair.js +51 -0
- package/output/core/classes/polynomial/Polynomial.d.ts +500 -0
- package/output/core/classes/polynomial/Polynomial.js +1149 -0
- package/output/core/classes/polynomial/Term.d.ts +222 -0
- package/output/core/classes/polynomial/Term.js +430 -0
- package/output/core/classes/polynomial/functions.d.ts +69 -0
- package/output/core/classes/polynomial/functions.js +126 -0
- package/output/core/classes/polynomial/utils.d.ts +62 -0
- package/output/core/classes/polynomial/utils.js +206 -0
- package/output/core/classes/rational/Rational.d.ts +504 -0
- package/output/core/classes/rational/Rational.js +779 -0
- package/output/core/classes/seq/SEQ.d.ts +13 -0
- package/output/core/classes/seq/SEQ.js +137 -0
- package/output/core/classes/valuesSet/ValuesSet.d.ts +179 -0
- package/output/core/classes/valuesSet/ValuesSet.js +381 -0
- package/output/core/classes/vector/Vector.d.ts +222 -0
- package/output/core/classes/vector/Vector.js +497 -0
- package/output/core/classes/vector/functions.d.ts +28 -0
- package/output/core/classes/vector/functions.js +47 -0
- package/output/core/common/classes/MathematicalAggregate.d.ts +53 -0
- package/output/core/common/classes/MathematicalAggregate.js +140 -0
- package/output/core/common/classes/Scope.d.ts +62 -0
- package/output/core/common/classes/Scope.js +122 -0
- package/output/core/common/classes/StructuredEntity.d.ts +55 -0
- package/output/core/common/classes/StructuredEntity.js +151 -0
- package/output/core/common/common.d.ts +63 -0
- package/output/core/common/common.js +279 -0
- package/output/core/common/functions/functions.d.ts +14 -0
- package/output/core/common/functions/functions.js +33 -0
- package/output/core/common/functions/structuredEntityUtils.d.ts +27 -0
- package/output/core/common/functions/structuredEntityUtils.js +40 -0
- package/output/core/converters/BaseConverter.d.ts +97 -0
- package/output/core/converters/BaseConverter.js +405 -0
- package/output/core/converters/Converter.d.ts +111 -0
- package/output/core/converters/Converter.js +802 -0
- package/output/core/converters/Pattern.d.ts +71 -0
- package/output/core/converters/Pattern.js +302 -0
- package/output/core/dispatch.d.ts +34 -0
- package/output/core/dispatch.js +304 -0
- package/output/core/errors.d.ts +531 -0
- package/output/core/errors.js +621 -0
- package/output/core/functions/bigint/bigint.d.ts +121 -0
- package/output/core/functions/bigint/bigint.js +392 -0
- package/output/core/functions/bigint/primeFactor.d.ts +49 -0
- package/output/core/functions/bigint/primeFactor.js +267 -0
- package/output/core/functions/bigint/primes.d.ts +1 -0
- package/output/core/functions/bigint/primes.js +11 -0
- package/output/core/functions/build/definitions.d.ts +12 -0
- package/output/core/functions/build/definitions.js +133 -0
- package/output/core/functions/build/index.d.ts +32 -0
- package/output/core/functions/build/index.js +136 -0
- package/output/core/functions/complex.d.ts +90 -0
- package/output/core/functions/complex.js +482 -0
- package/output/core/functions/decimal.d.ts +24 -0
- package/output/core/functions/decimal.js +664 -0
- package/output/core/functions/expand/expand.d.ts +42 -0
- package/output/core/functions/expand/expand.js +376 -0
- package/output/core/functions/fresnelNumeric.d.ts +12 -0
- package/output/core/functions/fresnelNumeric.js +123 -0
- package/output/core/functions/numeric.d.ts +140 -0
- package/output/core/functions/numeric.js +790 -0
- package/output/core/functions/rationalNormalization.d.ts +11 -0
- package/output/core/functions/rationalNormalization.js +117 -0
- package/output/core/functions/setFunction.d.ts +19 -0
- package/output/core/functions/setFunction.js +75 -0
- package/output/core/functions/string.d.ts +26 -0
- package/output/core/functions/string.js +101 -0
- package/output/core/functions/subst.d.ts +90 -0
- package/output/core/functions/subst.js +498 -0
- package/output/core/functions/utils.d.ts +24 -0
- package/output/core/functions/utils.js +51 -0
- package/output/core/types.d.ts +48 -0
- package/output/core/types.js +2 -0
- package/output/index.d.ts +339 -0
- package/output/index.js +715 -0
- package/output/math/defint/defintDecimal.d.ts +37 -0
- package/output/math/defint/defintDecimal.js +320 -0
- package/output/math/defint/defintNative.d.ts +57 -0
- package/output/math/defint/defintNative.js +292 -0
- package/output/math/geometry.d.ts +8 -0
- package/output/math/geometry.js +32 -0
- package/output/math/math.d.ts +655 -0
- package/output/math/math.js +1811 -0
- package/output/math/trig.d.ts +518 -0
- package/output/math/trig.js +1444 -0
- package/output/math/trunc.d.ts +19 -0
- package/output/math/trunc.js +36 -0
- package/output/math/utils.d.ts +60 -0
- package/output/math/utils.js +180 -0
- package/output/solve/classes/DecimalMatrix.d.ts +17 -0
- package/output/solve/classes/DecimalMatrix.js +86 -0
- package/output/solve/classes/FunctionSolver.d.ts +135 -0
- package/output/solve/classes/FunctionSolver.js +433 -0
- package/output/solve/classes/MultivariateSolver.d.ts +84 -0
- package/output/solve/classes/MultivariateSolver.js +240 -0
- package/output/solve/classes/PolynomialSolver.d.ts +85 -0
- package/output/solve/classes/PolynomialSolver.js +292 -0
- package/output/solve/classes/SolutionSet.d.ts +153 -0
- package/output/solve/classes/SolutionSet.js +357 -0
- package/output/solve/classes/Solver.d.ts +17 -0
- package/output/solve/classes/Solver.js +132 -0
- package/output/solve/classes/SymbolicSolver.d.ts +74 -0
- package/output/solve/classes/SymbolicSolver.js +601 -0
- package/output/solve/linsolve.d.ts +51 -0
- package/output/solve/linsolve.js +225 -0
- package/output/solve/solve.d.ts +34 -0
- package/output/solve/solve.js +260 -0
- package/output/solve/solveSystem.d.ts +31 -0
- package/output/solve/solveSystem.js +290 -0
- package/output/solve/utils.d.ts +9 -0
- package/output/solve/utils.js +62 -0
- package/output/utils/array.d.ts +42 -0
- package/output/utils/array.js +98 -0
- package/output/utils/debug.d.ts +131 -0
- package/output/utils/debug.js +295 -0
- package/output/utils/decimal.d.ts +3 -0
- package/output/utils/decimal.js +16 -0
- package/output/utils/numeric.d.ts +14 -0
- package/output/utils/numeric.js +51 -0
- package/output/utils/object.d.ts +26 -0
- package/output/utils/object.js +56 -0
- package/package.json +213 -57
- package/.travis.yml +0 -3
- package/Algebra.js +0 -4568
- package/BREAKING_CHANGES.md +0 -5
- package/CODE_OF_CONDUCT.md +0 -46
- package/CONTRIBUTING.md +0 -14
- package/Calculus.js +0 -2675
- package/Extra.js +0 -622
- package/Solve.js +0 -1783
- package/all.js +0 -16
- package/all.min.js +0 -1
- package/gulpfile.js +0 -16
- package/index.html +0 -158
- package/license.txt +0 -19
- package/nerdamer.core.js +0 -12510
- package/spec/LaTeX.spec.js +0 -302
- package/spec/TeXConvert.spec.js +0 -8
- package/spec/algebra.spec.js +0 -287
- package/spec/basic_parser.spec.js +0 -134
- package/spec/build.spec.js +0 -131
- package/spec/calculus.spec.js +0 -183
- package/spec/core.spec.js +0 -2970
- package/spec/extra.spec.js +0 -54
- package/spec/solve.spec.js +0 -126
- package/spec/support/jasmine.json +0 -11
- package/spec/support/utils.js +0 -42
- package/spec/text.spec.js +0 -132
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Converter = void 0;
|
|
4
|
+
const Dictionary_1 = require("../classes/dictionary/Dictionary");
|
|
5
|
+
const Expression_1 = require("../classes/expression/Expression");
|
|
6
|
+
const shortcuts_1 = require("../classes/expression/shortcuts");
|
|
7
|
+
const Matrix_1 = require("../classes/matrix/Matrix");
|
|
8
|
+
const constants_1 = require("../classes/parser/constants");
|
|
9
|
+
const Parser_1 = require("../classes/parser/Parser");
|
|
10
|
+
const Token_1 = require("../classes/parser/Token");
|
|
11
|
+
const ValuesSet_1 = require("../classes/valuesSet/ValuesSet");
|
|
12
|
+
const Vector_1 = require("../classes/vector/Vector");
|
|
13
|
+
const Scope_1 = require("../common/classes/Scope");
|
|
14
|
+
const dispatch_1 = require("../dispatch");
|
|
15
|
+
const BaseConverter_1 = require("./BaseConverter");
|
|
16
|
+
const { TeX, TEXT } = BaseConverter_1.BaseConverter.modes;
|
|
17
|
+
/**
|
|
18
|
+
* Formats Nerdamer values as TeX or normalized text and imports supported TeX input.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* A converter retains its output mode between calls. The default mode is `"TeX"`;
|
|
22
|
+
* construct a separate `"text"` converter when both representations are needed.
|
|
23
|
+
* Formatting a string parses it with the process-wide parser, so registered functions,
|
|
24
|
+
* constants, settings, and known values can affect the result.
|
|
25
|
+
*
|
|
26
|
+
* {@link Converter.fromTeX} recognizes the TeX forms emitted by this converter and a
|
|
27
|
+
* practical subset of common mathematical notation. It is not a general TeX parser:
|
|
28
|
+
* unsupported macros, ambiguous implicit notation, or nesting outside the recognized
|
|
29
|
+
* forms can produce parser errors or a different symbolic interpretation.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* import nerdamer from 'nerdamer';
|
|
34
|
+
*
|
|
35
|
+
* const text = new nerdamer.classes.Converter('text');
|
|
36
|
+
* const tex = new nerdamer.classes.Converter();
|
|
37
|
+
*
|
|
38
|
+
* text.convert('x^2 + 2*x + 1'); // "1+2*x+x^2"
|
|
39
|
+
* tex.convert('sqrt(x)'); // "\\sqrt{x}"
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
class Converter extends BaseConverter_1.BaseConverter {
|
|
43
|
+
static TEX_FUNCTION_MAP = {
|
|
44
|
+
// Inverse trig
|
|
45
|
+
acos: 'arccos',
|
|
46
|
+
asin: 'arcsin',
|
|
47
|
+
atan: 'arctan',
|
|
48
|
+
asec: 'operatorname{arcsec}',
|
|
49
|
+
acsc: 'operatorname{arccsc}',
|
|
50
|
+
acot: 'operatorname{arccot}',
|
|
51
|
+
// Inverse hyperbolic
|
|
52
|
+
acosh: 'operatorname{arcosh}',
|
|
53
|
+
asinh: 'operatorname{arsinh}',
|
|
54
|
+
atanh: 'operatorname{artanh}',
|
|
55
|
+
asech: 'operatorname{arsech}',
|
|
56
|
+
acsch: 'operatorname{arcsch}',
|
|
57
|
+
acoth: 'operatorname{arcoth}',
|
|
58
|
+
// Hyperbolic (not built-in in LaTeX)
|
|
59
|
+
sech: 'operatorname{sech}',
|
|
60
|
+
csch: 'operatorname{csch}',
|
|
61
|
+
coth: 'operatorname{coth}',
|
|
62
|
+
// Special
|
|
63
|
+
realpart: 'Re',
|
|
64
|
+
imagpart: 'Im',
|
|
65
|
+
sign: 'operatorname{sgn}',
|
|
66
|
+
sinc: 'operatorname{sinc}',
|
|
67
|
+
erf: 'operatorname{erf}',
|
|
68
|
+
erfc: 'operatorname{erfc}',
|
|
69
|
+
determinant: 'det',
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Reverse map for fromTeX: maps TeX command names back to internal function names.
|
|
73
|
+
*/
|
|
74
|
+
static TEX_REVERSE_MAP = {
|
|
75
|
+
arccos: 'acos',
|
|
76
|
+
arcsin: 'asin',
|
|
77
|
+
arctan: 'atan',
|
|
78
|
+
arcsec: 'asec',
|
|
79
|
+
arccsc: 'acsc',
|
|
80
|
+
arccot: 'acot',
|
|
81
|
+
arcosh: 'acosh',
|
|
82
|
+
arsinh: 'asinh',
|
|
83
|
+
artanh: 'atanh',
|
|
84
|
+
arsech: 'asech',
|
|
85
|
+
arcsch: 'acsch',
|
|
86
|
+
arcoth: 'acoth',
|
|
87
|
+
det: 'determinant',
|
|
88
|
+
deg: constants_1.DEG,
|
|
89
|
+
sgn: 'sign',
|
|
90
|
+
operatorname: '',
|
|
91
|
+
Gamma: 'gamma',
|
|
92
|
+
delta: constants_1.DIRAC,
|
|
93
|
+
Re: 'realpart',
|
|
94
|
+
Im: 'imagpart',
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Creates a converter with persistent output mode.
|
|
98
|
+
*
|
|
99
|
+
* @param mode - `"TeX"` (the default) or `"text"`.
|
|
100
|
+
*/
|
|
101
|
+
constructor(mode) {
|
|
102
|
+
super();
|
|
103
|
+
if (mode) {
|
|
104
|
+
this.setMode(mode);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
static clearOnes(m, v) {
|
|
108
|
+
for (let i = 0; i < 2; i++) {
|
|
109
|
+
if (v[i] && Number(m[i]) === 1) {
|
|
110
|
+
m[i] = '';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return [m, v];
|
|
114
|
+
}
|
|
115
|
+
static wrapRoot(value, root) {
|
|
116
|
+
return root === '2' ? `\\sqrt{${value}}` : `\\sqrt[${root}]{${value}}`;
|
|
117
|
+
}
|
|
118
|
+
finalizePowerAndInput(power, input, options) {
|
|
119
|
+
if (!options?.convertRoots) {
|
|
120
|
+
return [power, input];
|
|
121
|
+
}
|
|
122
|
+
const num = power.getNumerator();
|
|
123
|
+
const den = power.getDenominator();
|
|
124
|
+
if (num.isOne() && !power.isOne()) {
|
|
125
|
+
if (this.mode === BaseConverter_1.BaseConverter.modes.TEXT && den.eq((0, shortcuts_1.two)())) {
|
|
126
|
+
return [(0, shortcuts_1.one)(), BaseConverter_1.BaseConverter.convertSQRT(input)];
|
|
127
|
+
}
|
|
128
|
+
if (this.mode === BaseConverter_1.BaseConverter.modes.TeX) {
|
|
129
|
+
return [(0, shortcuts_1.one)(), BaseConverter_1.BaseConverter.convertNtRoot(input, den)];
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return [power, input];
|
|
133
|
+
}
|
|
134
|
+
functionString(input, options) {
|
|
135
|
+
const name = this.getFunctionName(input.name || '');
|
|
136
|
+
const args = input.getArguments();
|
|
137
|
+
const output = args.map(arg => this.convert(arg, options));
|
|
138
|
+
if (this.mode === TEXT) {
|
|
139
|
+
return `${name}(${output.join(',')})`;
|
|
140
|
+
}
|
|
141
|
+
return this.formatTeXFunction(input.name || '', name, output, args);
|
|
142
|
+
}
|
|
143
|
+
value(input, isInverted, isNegative, options) {
|
|
144
|
+
const v = ['', ''];
|
|
145
|
+
const index = isInverted ? 1 : 0;
|
|
146
|
+
if (input.isNUM()) {
|
|
147
|
+
return v;
|
|
148
|
+
}
|
|
149
|
+
if (input.isEXP()) {
|
|
150
|
+
v[index] = this.handleExp(input, options);
|
|
151
|
+
}
|
|
152
|
+
else if (input.isInf()) {
|
|
153
|
+
v[index] = this.mode === 'text' ? constants_1.INFINITY[0] : '\\infty';
|
|
154
|
+
}
|
|
155
|
+
else if (!(input.elements || input.args)) {
|
|
156
|
+
v[index] = this.formatVariable(input.value);
|
|
157
|
+
}
|
|
158
|
+
else if (input.isFunction()) {
|
|
159
|
+
v[index] = this.functionString(input, options);
|
|
160
|
+
}
|
|
161
|
+
else if (input.isSum()) {
|
|
162
|
+
v[index] = this.handleSum(input, isNegative, options);
|
|
163
|
+
}
|
|
164
|
+
else if (input.isProduct()) {
|
|
165
|
+
return this.handleProduct(input, isInverted, options);
|
|
166
|
+
}
|
|
167
|
+
return v;
|
|
168
|
+
}
|
|
169
|
+
convertSourceRPN(rpn, options) {
|
|
170
|
+
const stack = [];
|
|
171
|
+
for (let i = 0; i < rpn.length; i++) {
|
|
172
|
+
const item = rpn[i];
|
|
173
|
+
if (Scope_1.Scope.isScope(item)) {
|
|
174
|
+
const converted = this.convertSourceRPN(item, options);
|
|
175
|
+
const innerText = converted.args
|
|
176
|
+
? converted.args.map(arg => arg.text).join(',')
|
|
177
|
+
: converted.text;
|
|
178
|
+
const innerSource = converted.args
|
|
179
|
+
? converted.args.map(arg => arg.source).join(',')
|
|
180
|
+
: converted.source;
|
|
181
|
+
let text = innerText;
|
|
182
|
+
let source = innerSource;
|
|
183
|
+
switch (item.type) {
|
|
184
|
+
case 'parenthesis':
|
|
185
|
+
text = this.inBrackets(innerText);
|
|
186
|
+
source = `(${innerSource})`;
|
|
187
|
+
break;
|
|
188
|
+
case 'square':
|
|
189
|
+
text = this.inBrackets(innerText, 'square');
|
|
190
|
+
source = `[${innerSource}]`;
|
|
191
|
+
break;
|
|
192
|
+
case 'curly':
|
|
193
|
+
text = this.inBrackets(innerText, 'brace');
|
|
194
|
+
source = `{${innerSource}}`;
|
|
195
|
+
break;
|
|
196
|
+
case 'pipe':
|
|
197
|
+
text = this.inBrackets(innerText, 'abs');
|
|
198
|
+
source = `|${innerSource}|`;
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
stack.push({ text, source });
|
|
202
|
+
}
|
|
203
|
+
else if (item.type === Token_1.Token.FUNCTION) {
|
|
204
|
+
const argsScope = rpn[++i];
|
|
205
|
+
if (!Scope_1.Scope.isScope(argsScope)) {
|
|
206
|
+
throw new Error(`Missing argument scope for function ${item.value}`);
|
|
207
|
+
}
|
|
208
|
+
let args = [];
|
|
209
|
+
if (argsScope.length > 0) {
|
|
210
|
+
const argumentRPN = dispatch_1.mathFunctionRegistry[item.value]?.deferArguments
|
|
211
|
+
? Parser_1.Parser.toRPN(argsScope)
|
|
212
|
+
: argsScope;
|
|
213
|
+
const converted = this.convertSourceRPN(argumentRPN, options);
|
|
214
|
+
args = converted.args ?? [converted];
|
|
215
|
+
}
|
|
216
|
+
const output = args.map(arg => arg.text);
|
|
217
|
+
const placeholders = args.map((_, index) => Expression_1.Expression.create(`zzsourcearg${index}`));
|
|
218
|
+
const name = this.getFunctionName(item.value);
|
|
219
|
+
let text;
|
|
220
|
+
if (item.value === Expression_1.Expression.LOG && args.length === 2) {
|
|
221
|
+
const numerator = this.formatTeXFunction(Expression_1.Expression.LOG, name, [output[0]], [placeholders[0]]);
|
|
222
|
+
const denominator = this.formatTeXFunction(Expression_1.Expression.LOG, name, [output[1]], [placeholders[1]]);
|
|
223
|
+
text = this.toFraction(numerator, denominator);
|
|
224
|
+
}
|
|
225
|
+
else if (item.value === 'sqrt' && args.length === 1) {
|
|
226
|
+
text = Converter.wrapRoot(output[0], '2');
|
|
227
|
+
}
|
|
228
|
+
else if (args.length === 1 &&
|
|
229
|
+
(item.value === constants_1.FACTORIAL ||
|
|
230
|
+
item.value === 'factorial' ||
|
|
231
|
+
item.value === constants_1.DOUBLE_FACTORIAL)) {
|
|
232
|
+
text = this.formatTeXFunction(item.value, name, output, [
|
|
233
|
+
Expression_1.Expression.create(args[0].source),
|
|
234
|
+
]);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
text = this.formatTeXFunction(item.value, name, output, placeholders);
|
|
238
|
+
}
|
|
239
|
+
stack.push({
|
|
240
|
+
text,
|
|
241
|
+
source: `${item.value}(${args.map(arg => arg.source).join(',')})`,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
else if (item.type === Token_1.Token.PREFIX) {
|
|
245
|
+
const operand = stack.pop();
|
|
246
|
+
if (!operand) {
|
|
247
|
+
throw new Error(`Missing operand for prefix operator ${item.value}`);
|
|
248
|
+
}
|
|
249
|
+
stack.push({
|
|
250
|
+
text: item.value + operand.text,
|
|
251
|
+
source: item.value + operand.source,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
else if (item.type === Token_1.Token.OPERATOR) {
|
|
255
|
+
const operator = item.resolvedOperator ?? Parser_1.Parser.getOperator(item.value);
|
|
256
|
+
const right = stack.pop();
|
|
257
|
+
if (!operator || !right) {
|
|
258
|
+
throw new Error(`Missing operand or metadata for operator ${item.value}`);
|
|
259
|
+
}
|
|
260
|
+
if (operator.isPostfix) {
|
|
261
|
+
const symbol = item.value === '%' ? '\\%' : item.value;
|
|
262
|
+
stack.push({
|
|
263
|
+
text: right.text + symbol,
|
|
264
|
+
source: right.source + item.value,
|
|
265
|
+
});
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const left = stack.pop();
|
|
269
|
+
if (!left) {
|
|
270
|
+
throw new Error(`Missing left operand for operator ${item.value}`);
|
|
271
|
+
}
|
|
272
|
+
if (operator.action === 'comma') {
|
|
273
|
+
const args = [...(left.args ?? [left]), ...(right.args ?? [right])];
|
|
274
|
+
stack.push({
|
|
275
|
+
text: args.map(arg => arg.text).join(','),
|
|
276
|
+
source: args.map(arg => arg.source).join(','),
|
|
277
|
+
args,
|
|
278
|
+
});
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
let text;
|
|
282
|
+
if (operator.action === 'times') {
|
|
283
|
+
text =
|
|
284
|
+
left.text +
|
|
285
|
+
(item.position === -1 ? '' : this.getMultiplicationSymbol()) +
|
|
286
|
+
right.text;
|
|
287
|
+
}
|
|
288
|
+
else if (operator.action === 'div') {
|
|
289
|
+
text = this.toFraction(left.text, right.text);
|
|
290
|
+
}
|
|
291
|
+
else if (operator.action === 'pow') {
|
|
292
|
+
const power = Expression_1.Expression.create(right.source);
|
|
293
|
+
if (power.sign() === -1) {
|
|
294
|
+
const positivePower = power.signFree();
|
|
295
|
+
const denominator = positivePower.isOne()
|
|
296
|
+
? left.text
|
|
297
|
+
: left.text + '^' + this.inBraces(super.convert(positivePower, options));
|
|
298
|
+
text = this.toFraction('1', denominator);
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
text = left.text + '^' + this.inBraces(right.text);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
else if (operator.action === 'mod') {
|
|
305
|
+
text = this.formatTeXFunction('mod', this.getFunctionName('mod'), [left.text, right.text], [Expression_1.Expression.create('zzsourcearg0'), Expression_1.Expression.create('zzsourcearg1')]);
|
|
306
|
+
}
|
|
307
|
+
else if (operator.action === 'mapTo') {
|
|
308
|
+
text = `${left.text} \\mapsto ${right.text}`;
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
text = left.text + item.value + right.text;
|
|
312
|
+
}
|
|
313
|
+
stack.push({
|
|
314
|
+
text,
|
|
315
|
+
source: `(${left.source})${item.value}(${right.source})`,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
let text = item.value;
|
|
320
|
+
if (item.type === Token_1.Token.VARIABLE) {
|
|
321
|
+
text = constants_1.INFINITY.includes(item.value) ? '\\infty' : this.formatVariable(item.value);
|
|
322
|
+
}
|
|
323
|
+
stack.push({ text, source: item.value });
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (stack.length !== 1) {
|
|
327
|
+
throw new Error('Unable to convert source expression to TeX');
|
|
328
|
+
}
|
|
329
|
+
const retval = stack[0];
|
|
330
|
+
return retval;
|
|
331
|
+
}
|
|
332
|
+
formatFactorial(arg, output, symbol) {
|
|
333
|
+
if (arg.isLinear() && (arg.isSum() || arg.isProduct())) {
|
|
334
|
+
output = this.inBrackets(output);
|
|
335
|
+
}
|
|
336
|
+
return output + symbol;
|
|
337
|
+
}
|
|
338
|
+
formatSumOrProduct(symbol, output) {
|
|
339
|
+
const [a, b, c, d] = output;
|
|
340
|
+
return `${symbol}_{${this.inBraces(b)}=${this.inBraces(c)}}^${this.inBraces(d)} ${this.inBraces(a)}`;
|
|
341
|
+
}
|
|
342
|
+
formatTeXFunction(originalName, name, output, args) {
|
|
343
|
+
// Standard function: \name\left(arg\right)
|
|
344
|
+
const std = () => name + this.inBrackets(output[0]);
|
|
345
|
+
const generic = () => {
|
|
346
|
+
const formattedName = '\\operatorname' + this.inBraces(originalName.replace(/_/g, '\\_'));
|
|
347
|
+
return formattedName + this.inBrackets(output.join(','), 'parens');
|
|
348
|
+
};
|
|
349
|
+
const handlers = {
|
|
350
|
+
// Basic math
|
|
351
|
+
sqrt: std,
|
|
352
|
+
abs: () => this.inBrackets(output[0], 'abs'),
|
|
353
|
+
cbrt: () => `\\sqrt[3]${this.inBraces(output[0])}`,
|
|
354
|
+
max: () => `\\max${this.inBrackets(output.join(','), 'parens')}`,
|
|
355
|
+
min: () => `\\min${this.inBrackets(output.join(','), 'parens')}`,
|
|
356
|
+
round: () => output.length === 1
|
|
357
|
+
? `\\left\\lfloor ${output[0]} \\right\\rceil`
|
|
358
|
+
: generic(),
|
|
359
|
+
mod: () => `${output[0]} \\bmod ${output[1]}`,
|
|
360
|
+
[constants_1.FACTORIAL]: () => this.formatFactorial(args[0], output[0], '!'),
|
|
361
|
+
factorial: () => this.formatFactorial(args[0], output[0], '!'),
|
|
362
|
+
[constants_1.DOUBLE_FACTORIAL]: () => this.formatFactorial(args[0], output[0], '!!'),
|
|
363
|
+
parens: () => this.inBrackets(output[0], 'parens'),
|
|
364
|
+
// Trig
|
|
365
|
+
cos: std,
|
|
366
|
+
sin: std,
|
|
367
|
+
tan: std,
|
|
368
|
+
sec: std,
|
|
369
|
+
csc: std,
|
|
370
|
+
cot: std,
|
|
371
|
+
// Inverse trig
|
|
372
|
+
acos: std,
|
|
373
|
+
asin: std,
|
|
374
|
+
atan: std,
|
|
375
|
+
asec: std,
|
|
376
|
+
acsc: std,
|
|
377
|
+
acot: std,
|
|
378
|
+
atan2: () => name + this.inBrackets(output.join(','), 'parens'),
|
|
379
|
+
// Hyperbolic
|
|
380
|
+
sinh: std,
|
|
381
|
+
cosh: std,
|
|
382
|
+
tanh: std,
|
|
383
|
+
sech: std,
|
|
384
|
+
csch: std,
|
|
385
|
+
coth: std,
|
|
386
|
+
// Inverse hyperbolic
|
|
387
|
+
acosh: std,
|
|
388
|
+
asinh: std,
|
|
389
|
+
atanh: std,
|
|
390
|
+
asech: std,
|
|
391
|
+
acsch: std,
|
|
392
|
+
acoth: std,
|
|
393
|
+
// Floor / ceiling
|
|
394
|
+
floor: () => `\\left\\lfloor ${output[0]} \\right\\rfloor`,
|
|
395
|
+
ceil: () => `\\left\\lceil ${output[0]} \\right\\rceil`,
|
|
396
|
+
ceiling: () => `\\left\\lceil ${output[0]} \\right\\rceil`,
|
|
397
|
+
// Logarithms
|
|
398
|
+
[Expression_1.Expression.LOG]: () => {
|
|
399
|
+
const base = output[1];
|
|
400
|
+
const subscript = base === undefined ? '' : `_${this.inBraces(base)}`;
|
|
401
|
+
return `\\mathrm${this.inBraces(Expression_1.Expression.LOG)}${subscript}${this.inBrackets(output[0])}`;
|
|
402
|
+
},
|
|
403
|
+
[Expression_1.Expression.LOG10]: () => `\\mathrm${this.inBraces(Expression_1.Expression.LOG)}_${this.inBraces('10')}${this.inBrackets(output[0])}`,
|
|
404
|
+
// Special functions
|
|
405
|
+
exp: std,
|
|
406
|
+
gamma: () => `\\Gamma${this.inBrackets(output[0])}`,
|
|
407
|
+
erf: std,
|
|
408
|
+
erfc: std,
|
|
409
|
+
sinc: std,
|
|
410
|
+
Si: () => `\\operatorname{Si}${this.inBrackets(output[0])}`,
|
|
411
|
+
Shi: () => `\\operatorname{Shi}${this.inBrackets(output[0])}`,
|
|
412
|
+
Ci: () => `\\operatorname{Ci}${this.inBrackets(output[0])}`,
|
|
413
|
+
Chi: () => `\\operatorname{Chi}${this.inBrackets(output[0])}`,
|
|
414
|
+
Ei: () => `\\operatorname{Ei}${this.inBrackets(output[0])}`,
|
|
415
|
+
[constants_1.LI]: () => `\\operatorname{Li}${this.inBrackets(output[0])}`,
|
|
416
|
+
// Step / impulse
|
|
417
|
+
[constants_1.HEAVISIDE]: () => `H${this.inBrackets(output[0])}`,
|
|
418
|
+
[constants_1.DIRAC]: () => `\\delta${this.inBrackets(output[0])}`,
|
|
419
|
+
dirac: () => `\\delta${this.inBrackets(output[0])}`,
|
|
420
|
+
sign: std,
|
|
421
|
+
// Complex
|
|
422
|
+
realpart: () => `\\Re${this.inBrackets(output[0])}`,
|
|
423
|
+
imagpart: () => `\\Im${this.inBrackets(output[0])}`,
|
|
424
|
+
arg: std,
|
|
425
|
+
[constants_1.CONJUGATE]: () => `\\overline${this.inBraces(output[0])}`,
|
|
426
|
+
// Linear algebra
|
|
427
|
+
determinant: std,
|
|
428
|
+
// Polynomials
|
|
429
|
+
[constants_1.DEG]: std,
|
|
430
|
+
// Calculus
|
|
431
|
+
limit: () => `\\lim_${this.inBraces(output[1] + ' \\to ' + output[2])} ${output[0]}`,
|
|
432
|
+
integrate: () => output.length === 2 ? `\\int ${output[0]}\\, d${output[1]}` : generic(),
|
|
433
|
+
defint: () => `\\int_${this.inBraces(output[1])}^${this.inBraces(output[2])} ${output[0]}\\, d${output[3]}`,
|
|
434
|
+
diff: () => {
|
|
435
|
+
let retval;
|
|
436
|
+
if (output.length === 1) {
|
|
437
|
+
retval = generic();
|
|
438
|
+
}
|
|
439
|
+
else if (output.length === 3) {
|
|
440
|
+
retval = `\\frac${this.inBraces('d^' + output[2])}${this.inBraces('d' + output[1] + '^' + output[2])} ${output[0]}`;
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
retval = `\\frac${this.inBraces('d')}${this.inBraces('d' + output[1])} ${output[0]}`;
|
|
444
|
+
}
|
|
445
|
+
return retval;
|
|
446
|
+
},
|
|
447
|
+
laplace: () => `\\mathcal{L}_${this.inBraces(output[1] + ' \\to ' + output[2])}\\left\\{${output[0]}\\right\\}`,
|
|
448
|
+
ilaplace: () => `\\mathcal{L}^{-1}_${this.inBraces(output[1] + ' \\to ' + output[2])}\\left\\{${output[0]}\\right\\}`,
|
|
449
|
+
partfrac: () => `\\operatorname{partfrac}${this.inBrackets(output.join(','), 'parens')}`,
|
|
450
|
+
// Summation / product
|
|
451
|
+
sum: () => this.formatSumOrProduct('\\sum', output),
|
|
452
|
+
product: () => this.formatSumOrProduct('\\prod', output),
|
|
453
|
+
// Roots
|
|
454
|
+
nthroot: () => output[1] === '2'
|
|
455
|
+
? `\\sqrt${this.inBraces(output[0])}`
|
|
456
|
+
: `\\sqrt[${output[1]}]${this.inBraces(output[0])}`,
|
|
457
|
+
// Number theory
|
|
458
|
+
gcd: () => name + this.inBrackets(output.join(','), 'parens'),
|
|
459
|
+
lcm: () => `\\operatorname{lcm}${this.inBrackets(output.join(','), 'parens')}`,
|
|
460
|
+
// Wrapper
|
|
461
|
+
[constants_1.WRAP]: () => output[0],
|
|
462
|
+
};
|
|
463
|
+
const handler = handlers[originalName];
|
|
464
|
+
if (handler) {
|
|
465
|
+
return handler();
|
|
466
|
+
}
|
|
467
|
+
return generic();
|
|
468
|
+
}
|
|
469
|
+
formatVariable(value) {
|
|
470
|
+
return this.formatSubscripts(value)
|
|
471
|
+
.split('_')
|
|
472
|
+
.map((v, i) => {
|
|
473
|
+
if (this.mode === BaseConverter_1.BaseConverter.modes.TeX && this.greek.includes(v)) {
|
|
474
|
+
v = `\\${v}`;
|
|
475
|
+
}
|
|
476
|
+
return i > 0 ? this.inBraces(v) : v;
|
|
477
|
+
})
|
|
478
|
+
.join('_');
|
|
479
|
+
}
|
|
480
|
+
getFunctionName(name) {
|
|
481
|
+
if (this.mode !== TeX) {
|
|
482
|
+
return name;
|
|
483
|
+
}
|
|
484
|
+
const mappedName = Converter.TEX_FUNCTION_MAP[name] || name;
|
|
485
|
+
return `\\${mappedName}`;
|
|
486
|
+
}
|
|
487
|
+
handleExp(input, options) {
|
|
488
|
+
const arg = input.getBase();
|
|
489
|
+
let value = this.convert(arg, options);
|
|
490
|
+
if (!(arg.isInteger() || arg.isVAR())) {
|
|
491
|
+
value = this.inBrackets(value);
|
|
492
|
+
}
|
|
493
|
+
return value;
|
|
494
|
+
}
|
|
495
|
+
handleProduct(input, isInverted, options) {
|
|
496
|
+
const mul = this.getMultiplicationSymbol();
|
|
497
|
+
const numOutput = [];
|
|
498
|
+
const denOutput = [];
|
|
499
|
+
for (let element of input.elementsArray()) {
|
|
500
|
+
if (element.isFunction(constants_1.WRAP)) {
|
|
501
|
+
element = element.getArguments()[0];
|
|
502
|
+
}
|
|
503
|
+
const elementIsInverted = element.getPower().sign() === -1;
|
|
504
|
+
const isInDenominator = isInverted ? !elementIsInverted : elementIsInverted;
|
|
505
|
+
const target = isInDenominator ? denOutput : numOutput;
|
|
506
|
+
if (elementIsInverted) {
|
|
507
|
+
element = element.invert();
|
|
508
|
+
}
|
|
509
|
+
let output = this.convert(element, options);
|
|
510
|
+
if (element.isSum() && element.isLinear()) {
|
|
511
|
+
output = this.inBrackets(output);
|
|
512
|
+
}
|
|
513
|
+
target.push(output);
|
|
514
|
+
}
|
|
515
|
+
return [numOutput.join(mul), denOutput.join(mul)];
|
|
516
|
+
}
|
|
517
|
+
handleSum(input, isNegative, options) {
|
|
518
|
+
const elements = input.elementsArray().map(e => this.convert(e, options));
|
|
519
|
+
const value = elements.join('+');
|
|
520
|
+
const needsBrackets = !(input.isLinear() && input.getMultiplier().isOne()) || isNegative;
|
|
521
|
+
return needsBrackets ? this.inBrackets(value, 'parens') : value;
|
|
522
|
+
}
|
|
523
|
+
/** Parses a top-level TeX matrix environment into a scalar-valued Matrix. */
|
|
524
|
+
parseTeXMatrix(input) {
|
|
525
|
+
const match = input.match(/^\\begin\{([pbBvV]?matrix)\}\s*([\s\S]*?)\s*\\end\{\1\}$/);
|
|
526
|
+
let retval;
|
|
527
|
+
if (match) {
|
|
528
|
+
const rows = match[2]
|
|
529
|
+
.split(/\\\\/)
|
|
530
|
+
.map(row => row.trim())
|
|
531
|
+
.filter(row => row.length > 0)
|
|
532
|
+
.map(row => row.split('&').map(cell => Expression_1.Expression.create(this.fromTeX(cell.trim()))));
|
|
533
|
+
retval = new Matrix_1.Matrix(...rows);
|
|
534
|
+
}
|
|
535
|
+
return retval;
|
|
536
|
+
}
|
|
537
|
+
parseTeXSetOrDictionary(inner) {
|
|
538
|
+
const items = this.splitTeXTopLevel(inner, ',');
|
|
539
|
+
const entries = items.map(item => this.splitTeXTopLevel(item, '\\mapsto'));
|
|
540
|
+
const isDictionary = entries.some(parts => parts.length === 2);
|
|
541
|
+
if (isDictionary) {
|
|
542
|
+
const dictionaryEntries = new Map();
|
|
543
|
+
for (const parts of entries) {
|
|
544
|
+
if (parts.length === 2) {
|
|
545
|
+
const key = parts[0].trim();
|
|
546
|
+
const value = this.fromTeX(parts[1].trim());
|
|
547
|
+
dictionaryEntries.set(key, value);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
return new Dictionary_1.Dictionary(dictionaryEntries);
|
|
551
|
+
}
|
|
552
|
+
const set = new ValuesSet_1.ValuesSet();
|
|
553
|
+
for (const item of items) {
|
|
554
|
+
if (item.trim()) {
|
|
555
|
+
set.add(this.fromTeX(item.trim()));
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return set;
|
|
559
|
+
}
|
|
560
|
+
parseTeXVector(input) {
|
|
561
|
+
const match = input.match(/^\\left\s*\[([\s\S]*)\\right\s*\]$/) || input.match(/^\[([\s\S]*)\]$/);
|
|
562
|
+
let retval;
|
|
563
|
+
if (match) {
|
|
564
|
+
const elements = this.splitTeXTopLevel(match[1], ',')
|
|
565
|
+
.map(item => item.trim())
|
|
566
|
+
.filter(item => item.length > 0)
|
|
567
|
+
.map(item => this.fromTeX(item));
|
|
568
|
+
retval = new Vector_1.Vector(elements);
|
|
569
|
+
}
|
|
570
|
+
return retval;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Rewrites the supported TeX subset into parser syntax in an ordered pass.
|
|
574
|
+
*
|
|
575
|
+
* Structure-dependent forms such as transforms, derivatives, integrals, limits, and
|
|
576
|
+
* indexed sums must be recognized before generic braces and commands are removed.
|
|
577
|
+
* This is a compatibility preprocessor rather than a TeX grammar, so each rewrite is
|
|
578
|
+
* limited to the forms that can be mapped unambiguously to parser calls.
|
|
579
|
+
*/
|
|
580
|
+
preprocessTeXClean(input) {
|
|
581
|
+
let s = input;
|
|
582
|
+
// Normalize valid short-form fractions before the existing brace-based TeX path runs.
|
|
583
|
+
s = s.replace(/\\frac\s*\{([^{}]+)\}\s*([a-zA-Z0-9.])/g, '\\frac{$1}{$2}');
|
|
584
|
+
s = s.replace(/\\frac\s*([a-zA-Z0-9.])\s*\{([^{}]+)\}/g, '\\frac{$1}{$2}');
|
|
585
|
+
s = s.replace(/\\frac\s*([a-zA-Z0-9.])\s*([a-zA-Z0-9.])/g, '\\frac{$1}{$2}');
|
|
586
|
+
// A whole number immediately followed by a numeric fraction is conventional mixed-number notation.
|
|
587
|
+
s = s.replace(/(\d+)\s*\\frac\s*\{(\d+)\}\s*\{(\d+)\}/g, '($1+\\frac{$2}{$3})');
|
|
588
|
+
// --- Laplace transforms (before brace stripping) ---
|
|
589
|
+
s = s.replace(/\\mathcal\s*\{L\}\s*\^\s*\{-1\}\s*_\s*\{([^{}]+?)\s*\\to\s*([^{}]+?)\}\s*(?:\\left\s*)?\\{(.+?)\\}\s*(?:\\right\s*)?/g, (_m, source, target, expr) => `ilaplace(${expr},${String(source).trim()},${String(target).trim()})`);
|
|
590
|
+
s = s.replace(/\\mathcal\s*\{L\}\s*_\s*\{([^{}]+?)\s*\\to\s*([^{}]+?)\}\s*(?:\\left\s*)?\\{(.+?)\\}\s*(?:\\right\s*)?/g, (_m, source, target, expr) => `laplace(${expr},${String(source).trim()},${String(target).trim()})`);
|
|
591
|
+
s = s.replace(/\\mathcal\s*\{L\}\s*\^\s*\{-1\}\s*(?:\\left\s*)?\\{(.+?)\\}\s*(?:\\right\s*)?/g, 'ilaplace($1)');
|
|
592
|
+
s = s.replace(/\\mathcal\s*\{L\}\s*(?:\\left\s*)?\\{(.+?)\\}\s*(?:\\right\s*)?/g, 'laplace($1)');
|
|
593
|
+
// --- Derivatives: \frac{d^n}{dx^n} f → diff(f, x, n) ---
|
|
594
|
+
// Higher order
|
|
595
|
+
s = s.replace(/\\frac\s*\{d\^(\w+)\}\s*\{d(\w+)\^\1\}\s*(.+)/g, (_m, n, v, f) => `diff(${f},${v},${n})`);
|
|
596
|
+
// First order
|
|
597
|
+
s = s.replace(/\\frac\s*\{d\}\s*\{d(\w+)\}\s*(.+)/g, (_m, v, f) => `diff(${f},${v})`);
|
|
598
|
+
// --- Definite integrals ---
|
|
599
|
+
s = s.replace(/\\int\s*_\s*\{([^}]+)\}\s*\^\s*\{([^}]+)\}\s*(.+?)\\?,?\s*d(\w+)/g, (_m, a, b, f, v) => `defint(${f},${a},${b},${v})`);
|
|
600
|
+
// --- Indefinite integrals ---
|
|
601
|
+
s = s.replace(/\\int\s+(.+?)\\?,?\s*d(\w+)/g, (_m, f, v) => `integrate(${f},${v})`);
|
|
602
|
+
// --- Limits: \lim_{x \to a} f → limit(f, x, a) ---
|
|
603
|
+
s = s.replace(/\\lim\s*_\s*\{(\w+)\s*\\to\s*([^}]+)\}\s*(.+)/g, (_m, v, a, f) => `limit(${f},${v},${a})`);
|
|
604
|
+
// --- Sum / Product: \sum_{i=a}^{b} f → sum(f, i, a, b) ---
|
|
605
|
+
s = s.replace(/\\sum\s*_\s*\{(\w+)=([^}]+)\}\s*\^\s*\{([^}]+)\}\s*(.+)/g, (_m, i, a, b, f) => `sum(${f},${i},${a},${b})`);
|
|
606
|
+
s = s.replace(/\\prod\s*_\s*\{(\w+)=([^}]+)\}\s*\^\s*\{([^}]+)\}\s*(.+)/g, (_m, i, a, b, f) => `product(${f},${i},${a},${b})`);
|
|
607
|
+
// --- Floor / Ceiling ---
|
|
608
|
+
s = s.replace(/(?:\\left\s*)?\\lfloor\s*(.+?)\s*(?:\\right\s*)?\\rceil/g, 'round($1)');
|
|
609
|
+
s = s.replace(/(?:\\left\s*)?\\lfloor\s*/g, 'floor(');
|
|
610
|
+
s = s.replace(/\\rfloor\s*(?:\\right\s*)?/g, ')');
|
|
611
|
+
s = s.replace(/(?:\\left\s*)?\\lceil\s*/g, 'ceil(');
|
|
612
|
+
s = s.replace(/\\rceil\s*(?:\\right\s*)?/g, ')');
|
|
613
|
+
// --- Arbitrary-base logarithms ---
|
|
614
|
+
s = s.replace(/\\log\s*_\s*\{([^}]+)\}\s*\{([^}]+)\}/g, 'log($2,$1)');
|
|
615
|
+
s = s.replace(/\\log\s*_\s*\{([^}]+)\}\s*([a-zA-Z0-9_.]+)/g, 'log($2,$1)');
|
|
616
|
+
// --- Special functions ---
|
|
617
|
+
s = this.replaceBracedTeXCommand(s, 'overline', constants_1.CONJUGATE);
|
|
618
|
+
s = s.replace(/\\Gamma\s*/g, 'gamma');
|
|
619
|
+
s = s.replace(/\\delta\s*/g, constants_1.DIRAC);
|
|
620
|
+
s = s.replace(/(?<![a-zA-Z])H\s*(?=(?:\\left\s*)?\()/g, constants_1.HEAVISIDE);
|
|
621
|
+
s = s.replace(/\\Re\s*/g, 'realpart');
|
|
622
|
+
s = s.replace(/\\Im\s*/g, 'imagpart');
|
|
623
|
+
// --- \operatorname{name} → name ---
|
|
624
|
+
s = s.replace(/\\operatorname\s*\{([^}]+)\}/g, '$1');
|
|
625
|
+
// --- Inverse trig/hyperbolic TeX names → internal names ---
|
|
626
|
+
for (const [texName, internalName] of Object.entries(Converter.TEX_REVERSE_MAP)) {
|
|
627
|
+
if (texName === 'operatorname' ||
|
|
628
|
+
texName === 'Gamma' ||
|
|
629
|
+
texName === 'delta' ||
|
|
630
|
+
texName === 'Re' ||
|
|
631
|
+
texName === 'Im') {
|
|
632
|
+
continue; // already handled above
|
|
633
|
+
}
|
|
634
|
+
s = s.replace(new RegExp(`\\\\${texName}\\b`, 'g'), internalName);
|
|
635
|
+
}
|
|
636
|
+
// --- \bmod ---
|
|
637
|
+
s = s.replace(/(.+?)\s*\\bmod\s*(.+)/g, 'mod($1,$2)');
|
|
638
|
+
// --- nth root: \sqrt[n]{x} → nthroot(x,n), \sqrt{x} → sqrt(x) ---
|
|
639
|
+
s = s.replace(/\\sqrt\s*\[([^\]]+)\]\s*\{([^}]+)\}/g, 'nthroot($2,$1)');
|
|
640
|
+
s = s.replace(/\\sqrt\s*\{([^}]+)\}/g, 'sqrt($1)');
|
|
641
|
+
// --- Standard cleanup (same as original fromTeX) ---
|
|
642
|
+
s = s.replace(/\\,/g, '');
|
|
643
|
+
s = s.replace(/\s*\\cdot\s*/g, '*');
|
|
644
|
+
s = s.replace(/\s*(?:\\left|\\right)\s*/g, '');
|
|
645
|
+
s = s.replace(/\\infty/g, 'Infinity');
|
|
646
|
+
s = s.replace(/\s*[{(]/g, '(');
|
|
647
|
+
s = s.replace(/}/g, ')');
|
|
648
|
+
s = s.replace(/\s+|\\/g, ' ');
|
|
649
|
+
return s;
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Rewrites one TeX command whose argument is carried in balanced braces.
|
|
653
|
+
*
|
|
654
|
+
* The converter emits some commands around expressions that can themselves contain
|
|
655
|
+
* nested TeX groups. A flat regular expression cannot safely recover those arguments,
|
|
656
|
+
* so this keeps the brace matching local to the TeX conversion pipeline.
|
|
657
|
+
*/
|
|
658
|
+
replaceBracedTeXCommand(input, command, functionName) {
|
|
659
|
+
const marker = `\\${command}`;
|
|
660
|
+
let retval = '';
|
|
661
|
+
let cursor = 0;
|
|
662
|
+
while (cursor < input.length) {
|
|
663
|
+
const commandIndex = input.indexOf(marker, cursor);
|
|
664
|
+
if (commandIndex === -1) {
|
|
665
|
+
retval += input.slice(cursor);
|
|
666
|
+
cursor = input.length;
|
|
667
|
+
}
|
|
668
|
+
else {
|
|
669
|
+
retval += input.slice(cursor, commandIndex);
|
|
670
|
+
let openIndex = commandIndex + marker.length;
|
|
671
|
+
while (openIndex < input.length && /\s/.test(input[openIndex])) {
|
|
672
|
+
openIndex++;
|
|
673
|
+
}
|
|
674
|
+
if (input[openIndex] !== '{') {
|
|
675
|
+
retval += marker;
|
|
676
|
+
cursor = commandIndex + marker.length;
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
let depth = 1;
|
|
680
|
+
let closeIndex = openIndex + 1;
|
|
681
|
+
while (closeIndex < input.length && depth > 0) {
|
|
682
|
+
if (input[closeIndex] === '{') {
|
|
683
|
+
depth++;
|
|
684
|
+
}
|
|
685
|
+
else if (input[closeIndex] === '}') {
|
|
686
|
+
depth--;
|
|
687
|
+
}
|
|
688
|
+
closeIndex++;
|
|
689
|
+
}
|
|
690
|
+
if (depth !== 0) {
|
|
691
|
+
retval += input.slice(commandIndex);
|
|
692
|
+
cursor = input.length;
|
|
693
|
+
}
|
|
694
|
+
else {
|
|
695
|
+
const inner = input.slice(openIndex + 1, closeIndex - 1);
|
|
696
|
+
const convertedInner = this.replaceBracedTeXCommand(inner, command, functionName);
|
|
697
|
+
retval += `${functionName}(${convertedInner})`;
|
|
698
|
+
cursor = closeIndex;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return retval;
|
|
704
|
+
}
|
|
705
|
+
splitTeXTopLevel(input, delimiter) {
|
|
706
|
+
const items = [];
|
|
707
|
+
let depth = 0;
|
|
708
|
+
let current = '';
|
|
709
|
+
for (let i = 0; i < input.length; i++) {
|
|
710
|
+
const ch = input[i];
|
|
711
|
+
if (delimiter === ',' && ch === '\\' && input[i + 1] === ',') {
|
|
712
|
+
i++;
|
|
713
|
+
continue;
|
|
714
|
+
}
|
|
715
|
+
if (ch === '{' || ch === '[' || ch === '(') {
|
|
716
|
+
depth++;
|
|
717
|
+
}
|
|
718
|
+
else if (ch === '}' || ch === ']' || ch === ')') {
|
|
719
|
+
depth--;
|
|
720
|
+
}
|
|
721
|
+
if (depth === 0 && input.startsWith(delimiter, i)) {
|
|
722
|
+
items.push(current);
|
|
723
|
+
current = '';
|
|
724
|
+
i += delimiter.length - 1;
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
current += ch;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
if (current.trim()) {
|
|
731
|
+
items.push(current);
|
|
732
|
+
}
|
|
733
|
+
return items;
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Formats supported values while retaining ordinary Converter semantics by default.
|
|
737
|
+
* Source preservation is an internal compatibility option used by convertToLaTeX.
|
|
738
|
+
*/
|
|
739
|
+
convert(input, options) {
|
|
740
|
+
let retval;
|
|
741
|
+
if (typeof input === 'string' &&
|
|
742
|
+
this.mode === TeX &&
|
|
743
|
+
options?.preserveSource === true &&
|
|
744
|
+
options.decimal !== true) {
|
|
745
|
+
const rpn = Parser_1.Parser.toRPN(Parser_1.Parser.tokenize(input));
|
|
746
|
+
const converted = this.convertSourceRPN(rpn, options);
|
|
747
|
+
retval = converted.args
|
|
748
|
+
? converted.args.map(arg => arg.text).join(',')
|
|
749
|
+
: converted.text;
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
retval = super.convert(input, options);
|
|
753
|
+
}
|
|
754
|
+
return retval;
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Parses a supported TeX subset into a Nerdamer parser entity.
|
|
758
|
+
*
|
|
759
|
+
* @remarks
|
|
760
|
+
* Set notation is recognized before ordinary expression preprocessing and produces a
|
|
761
|
+
* value set or dictionary when appropriate. Other input is rewritten to Nerdamer
|
|
762
|
+
* parser syntax, tokenized in pure mode, and evaluated through the process-wide parser.
|
|
763
|
+
* Consequently, parser settings or registered functions can affect the result.
|
|
764
|
+
*
|
|
765
|
+
* The importer supports the converter's common function forms, roots, arbitrary-base
|
|
766
|
+
* logarithms, transforms, derivatives, integrals, limits, sums, products, floor and
|
|
767
|
+
* ceiling notation, equations, vectors, matrices, finite sets, and dictionaries. It does
|
|
768
|
+
* not promise round-tripping arbitrary third-party TeX.
|
|
769
|
+
*
|
|
770
|
+
* @param input - TeX text in the supported conversion subset.
|
|
771
|
+
* @returns The parser entity represented by the supported TeX input.
|
|
772
|
+
* @throws Error When preprocessing leaves syntax that the parser cannot interpret.
|
|
773
|
+
*
|
|
774
|
+
* @example
|
|
775
|
+
* ```ts
|
|
776
|
+
* import nerdamer from 'nerdamer';
|
|
777
|
+
*
|
|
778
|
+
* const converter = new nerdamer.classes.Converter();
|
|
779
|
+
* nerdamer.pretty(converter.fromTeX('\\log_{2}{256}'), 'text'); // "8"
|
|
780
|
+
* ```
|
|
781
|
+
*/
|
|
782
|
+
fromTeX(input) {
|
|
783
|
+
const trimmed = input.trim();
|
|
784
|
+
const matrix = this.parseTeXMatrix(trimmed);
|
|
785
|
+
if (matrix) {
|
|
786
|
+
return matrix;
|
|
787
|
+
}
|
|
788
|
+
const vector = this.parseTeXVector(trimmed);
|
|
789
|
+
if (vector) {
|
|
790
|
+
return vector;
|
|
791
|
+
}
|
|
792
|
+
// Detect set/dictionary notation: \{...\} or \left\{...\right\}
|
|
793
|
+
const setMatch = trimmed.match(/^\\left\s*\\{(.*)\\right\s*\\}$/) || trimmed.match(/^\\{(.*)\\}$/);
|
|
794
|
+
if (setMatch) {
|
|
795
|
+
return this.parseTeXSetOrDictionary(setMatch[1]);
|
|
796
|
+
}
|
|
797
|
+
const str = this.preprocessTeXClean(input);
|
|
798
|
+
const TeXRPN = Parser_1.Parser.tokenize(str, { pure: true });
|
|
799
|
+
return Parser_1.Parser.parse(Parser_1.Parser.parseTeXRPN(TeXRPN));
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
exports.Converter = Converter;
|