nerdamer-ts
Version:
javascript light-weight symbolic math expression evaluator
192 lines • 7.64 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.expandall = exports.expand = void 0;
const Utils_1 = require("../../../Core/Utils");
const Symbol_1 = require("../../../Types/Symbol");
const Groups_1 = require("../../../Types/Groups");
const index_1 = require("../index");
const Parser_1 = require("../../../Parser/Parser");
/**
* Expands a symbol
* @param symbol
*/
// Old expand
function expand(symbol, opt = undefined) {
if (Array.isArray(symbol)) {
return symbol.map(function (x) {
return expand(x, opt);
});
}
opt = opt || {};
//deal with parenthesis
if (symbol.group === Groups_1.Groups.FN && symbol.fname === '') {
var f = expand(symbol.args[0], opt);
var x = expand((0, index_1.pow)(f, (0, Parser_1.parse)(symbol.power)), opt);
return (0, index_1.multiply)((0, Parser_1.parse)(symbol.multiplier), x).distributeMultiplier();
}
// We can expand these groups so no need to waste time. Just return and be done.
if ([Groups_1.Groups.N, Groups_1.Groups.P, Groups_1.Groups.S].indexOf(symbol.group) !== -1) {
return symbol; //nothing to do
}
var original = symbol.clone();
// Set up a try-catch block. If anything goes wrong then we simply return the original symbol
try {
// Store the power and multiplier
var m = symbol.multiplier.toString();
var p = Number(symbol.power);
var retval = symbol;
// Handle (a+b)^2 | (x+x^2)^2
if (symbol.isComposite() && (0, Utils_1.isInt)(symbol.power) && symbol.power > 0) {
var n = p - 1;
// Strip the expression of it's multiplier and power. We'll call it f. The power will be p and the multiplier m.
var f = new Symbol_1.Symbol(0);
symbol.each(function (x) {
f = (0, index_1.add)(f, expand((0, Parser_1.parse)(x), opt));
});
var expanded = (0, Parser_1.parse)(f);
for (var i = 0; i < n; i++) {
expanded = mix(expanded, f, opt);
}
retval = (0, index_1.multiply)((0, Parser_1.parse)(m), expanded).distributeMultiplier();
}
else if (symbol.group === Groups_1.Groups.FN && opt.expand_functions === true) {
var args = [];
// Expand function the arguments
symbol.args.forEach(function (x) {
args.push(expand(x, opt));
});
// Put back the power and multiplier
retval = (0, index_1.pow)((0, Symbol_1.symfunction)(symbol.fname, args), (0, Parser_1.parse)(symbol.power));
retval = (0, index_1.multiply)(retval, (0, Parser_1.parse)(symbol.multiplier));
}
else if (symbol.isComposite() && (0, Utils_1.isInt)(symbol.power) && symbol.power < 0 && opt.expand_denominator === true) {
// Invert it. Expand it and then re-invert it.
symbol = symbol.invert();
retval = expand(symbol, opt);
retval.invert();
}
else if (symbol.group === Groups_1.Groups.CB) {
var rank = function (s) {
switch (s.group) {
case Groups_1.Groups.CP:
return 0;
case Groups_1.Groups.PL:
return 1;
case Groups_1.Groups.CB:
return 2;
case Groups_1.Groups.FN:
return 3;
default:
return 4;
}
};
// Consider (a+b)(c+d). The result will be (a*c+a*d)+(b*c+b*d).
// We start by moving collecting the symbols. We want others>FN>CB>PL>CP
var symbols = symbol.collectSymbols().sort(function (a, b) {
return rank(b) - rank(a);
})
// Distribute the power to each symbol and expand
.map(function (s) {
var x = (0, index_1.pow)(s, (0, Parser_1.parse)(p));
var e = expand(x, opt);
return e;
});
var f = symbols.pop();
// If the first symbols isn't a composite then we're done
if (f.isComposite() && f.isLinear()) {
symbols.forEach(function (s) {
f = mix(f, s, opt);
});
// If f is of group PL or CP then we can expand some more
if (f.isComposite()) {
if (f.power > 1) {
f = expand((0, index_1.pow)(f, (0, Parser_1.parse)(f.power)), opt);
}
// Put back the multiplier
retval = (0, index_1.multiply)((0, Parser_1.parse)(m), f).distributeMultiplier();
}
else {
// Everything is expanded at this point so if it's still a CB
// then just return the symbol
retval = f;
}
}
else {
// Just multiply back in the expanded form of each
retval = f;
symbols.forEach(function (s) {
retval = (0, index_1.multiply)(retval, s);
});
// Put back the multiplier
retval = (0, index_1.multiply)(retval, (0, Parser_1.parse)(m)).distributeMultiplier();
}
// TODO: This exists solely as a quick fix for sqrt(11)*sqrt(33) not simplifying.
if (retval.group === Groups_1.Groups.CB) {
retval = (0, Parser_1.parse)(retval);
}
}
else {
// Otherwise just return the expression
retval = symbol;
}
// Final cleanup and return
return retval;
}
catch (e) {
return original;
}
}
exports.expand = expand;
/**
* A wrapper for the expand function
* @param {Symbol} symbol
* @returns {Symbol}
*/
function expandall(symbol, opt) {
opt = opt || {
expand_denominator: true,
expand_functions: true
};
return expand(symbol, opt);
}
exports.expandall = expandall;
/**
* Used to multiply two expression in expanded form
* @param {Symbol} a
* @param {Symbol} b
*/
function mix(a, b, opt) {
// Flip them if b is a CP or PL and a is not
if (b.isComposite() && !a.isComposite() || b.isLinear() && !a.isLinear()) {
[a, b] = [b, a];
}
// A temporary variable to hold the expanded terms
var t = new Symbol_1.Symbol(0);
if (a.isLinear()) {
a.each(function (x) {
// If b is not a PL or a CP then simply multiply it
if (!b.isComposite()) {
var term = (0, index_1.multiply)((0, Parser_1.parse)(x), (0, Parser_1.parse)(b));
t = (0, index_1.add)(t, expand(term, opt));
}
// Otherwise multiply out each term.
else if (b.isLinear()) {
b.each(function (y) {
var term = (0, index_1.multiply)((0, Parser_1.parse)(x), (0, Parser_1.parse)(y));
var expanded = expand((0, Parser_1.parse)(term), opt);
t = (0, index_1.add)(t, expanded);
}, true);
}
else {
t = (0, index_1.add)(t, (0, index_1.multiply)(x, (0, Parser_1.parse)(b)));
}
}, true);
}
else {
// Just multiply them together
t = (0, index_1.multiply)(a, b);
}
// The expanded function is now t
return t;
}
//# sourceMappingURL=expand.js.map