Adding object properties usable in expressions
This commit is contained in:
parent
fad5325501
commit
6b535dd8a2
6 changed files with 30 additions and 17 deletions
|
@ -194,6 +194,7 @@ function evaluate(tokens, expr, values) {
|
||||||
nstack.push(f(resolveExpression(n1, values), resolveExpression(n2, values), resolveExpression(n3, values)));
|
nstack.push(f(resolveExpression(n1, values), resolveExpression(n2, values), resolveExpression(n3, values)));
|
||||||
}
|
}
|
||||||
} else if (type === IVAR) {
|
} else if (type === IVAR) {
|
||||||
|
// Check for variable value
|
||||||
if (item.value in expr.functions) {
|
if (item.value in expr.functions) {
|
||||||
nstack.push(expr.functions[item.value]);
|
nstack.push(expr.functions[item.value]);
|
||||||
} else if (item.value in expr.unaryOps && expr.parser.isOperatorEnabled(item.value)) {
|
} else if (item.value in expr.unaryOps && expr.parser.isOperatorEnabled(item.value)) {
|
||||||
|
@ -219,8 +220,11 @@ function evaluate(tokens, expr, values) {
|
||||||
f = nstack.pop();
|
f = nstack.pop();
|
||||||
if (f.apply && f.call) {
|
if (f.apply && f.call) {
|
||||||
nstack.push(f.apply(undefined, args));
|
nstack.push(f.apply(undefined, args));
|
||||||
|
} else if(f.execute) {
|
||||||
|
// Objects & expressions execution
|
||||||
|
nstack.push(f.execute.apply(undefined, args));
|
||||||
} else {
|
} else {
|
||||||
throw new Error(f + ' is not a function');
|
throw new Error(f + ' cannot be executed');
|
||||||
}
|
}
|
||||||
} else if (type === IFUNDEF) {
|
} else if (type === IFUNDEF) {
|
||||||
// Create closure to keep references to arguments and expression
|
// Create closure to keep references to arguments and expression
|
||||||
|
|
|
@ -22,7 +22,9 @@
|
||||||
.import "../utils.js" as Utils
|
.import "../utils.js" as Utils
|
||||||
.import "latex.js" as Latex
|
.import "latex.js" as Latex
|
||||||
|
|
||||||
var evalVariables = { // Variables not provided by expr-eval.js, needs to be provided manualy
|
const DERIVATION_PRECISION = 0.1
|
||||||
|
|
||||||
|
var evalVariables = { // Variables not provided by expr-eval.js, needs to be provided manually
|
||||||
"pi": Math.PI,
|
"pi": Math.PI,
|
||||||
"π": Math.PI,
|
"π": Math.PI,
|
||||||
"inf": Infinity,
|
"inf": Infinity,
|
||||||
|
@ -33,18 +35,21 @@ var evalVariables = { // Variables not provided by expr-eval.js, needs to be pro
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentVars = {}
|
var currentVars = {}
|
||||||
|
var currentObjectsByName = {} // Mirror of currentObjectsByName in objects.js
|
||||||
|
|
||||||
const parser = new ExprEval.Parser()
|
const parser = new ExprEval.Parser()
|
||||||
|
|
||||||
|
parser.consts = Object.assign({}, parser.consts, evalVariables)
|
||||||
|
|
||||||
|
// Function definition
|
||||||
parser.functions.integral = function(a, b, f, variable) {
|
parser.functions.integral = function(a, b, f, variable) {
|
||||||
// https://en.wikipedia.org/wiki/Simpson%27s_rule
|
// https://en.wikipedia.org/wiki/Simpson%27s_rule
|
||||||
|
// Simpler, faster than tokenizing the expression
|
||||||
f = parser.parse(f).toJSFunction(variable, currentVars)
|
f = parser.parse(f).toJSFunction(variable, currentVars)
|
||||||
return (b-a)/6*(f(a)+4*f((a+b)/2)+f(b))
|
return (b-a)/6*(f(a)+4*f((a+b)/2)+f(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
const DERIVATION_PRECISION = 0.1
|
|
||||||
|
|
||||||
parser.functions.derivative = function(f, variable, x) {
|
parser.functions.derivative = function(f, variable, x) {
|
||||||
f = parser.parse(f).toJSFunction(variable, currentVars)
|
f = parser.parse(f).toJSFunction(variable, currentVars)
|
||||||
return (f(x+DERIVATION_PRECISION/2)-f(x-DERIVATION_PRECISION/2))/DERIVATION_PRECISION
|
return (f(x+DERIVATION_PRECISION/2)-f(x-DERIVATION_PRECISION/2))/DERIVATION_PRECISION
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,23 +30,25 @@ class Expression {
|
||||||
this.expr = expr
|
this.expr = expr
|
||||||
this.calc = C.parser.parse(expr).simplify()
|
this.calc = C.parser.parse(expr).simplify()
|
||||||
this.cached = this.isConstant()
|
this.cached = this.isConstant()
|
||||||
this.cachedValue = this.cached ? this.calc.evaluate(C.evalVariables) : null
|
this.cachedValue = this.cached ? this.calc.evaluate(C.currentObjectsByName) : null
|
||||||
this.latexMarkup = Latex.expression(this.calc.tokens)
|
this.latexMarkup = Latex.expression(this.calc.tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() {
|
isConstant() {
|
||||||
return !this.expr.includes("x") && !this.expr.includes("n")
|
let vars = this.calc.variables()
|
||||||
|
return !vars.includes("x") && !vars.includes("n")
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(x = 1) {
|
execute(x = 1) {
|
||||||
if(this.cached) return this.cachedValue
|
if(this.cached) return this.cachedValue
|
||||||
C.currentVars = Object.assign({'x': x}, C.evalVariables)
|
C.currentVars = Object.assign({'x': x}, C.currentObjectsByName)
|
||||||
|
//console.log("Executing", this.expr, "with", JSON.stringify(C.currentVars))
|
||||||
return this.calc.evaluate(C.currentVars)
|
return this.calc.evaluate(C.currentVars)
|
||||||
}
|
}
|
||||||
|
|
||||||
simplify(x) {
|
simplify(x) {
|
||||||
var expr = this.calc.substitute('x', x).simplify()
|
var expr = this.calc.substitute('x', x).simplify()
|
||||||
if(expr.evaluate(C.evalVariables) == 0) return '0'
|
if(expr.evaluate() == 0) return '0'
|
||||||
var str = Utils.makeExpressionReadable(expr.toString());
|
var str = Utils.makeExpressionReadable(expr.toString());
|
||||||
if(str != undefined && str.match(/^\d*\.\d+$/)) {
|
if(str != undefined && str.match(/^\d*\.\d+$/)) {
|
||||||
if(str.split('.')[1].split('0').length > 7) {
|
if(str.split('.')[1].split('0').length > 7) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ class Sequence extends Expr.Expression {
|
||||||
if(['string', 'number'].includes(typeof this.calcValues[n])) {
|
if(['string', 'number'].includes(typeof this.calcValues[n])) {
|
||||||
let parsed = C.parser.parse(this.calcValues[n].toString()).simplify()
|
let parsed = C.parser.parse(this.calcValues[n].toString()).simplify()
|
||||||
this.latexValues[n] = Latex.expression(parsed.tokens)
|
this.latexValues[n] = Latex.expression(parsed.tokens)
|
||||||
this.calcValues[n] = parsed.evaluate(C.evalVariables)
|
this.calcValues[n] = parsed.evaluate()
|
||||||
}
|
}
|
||||||
this.valuePlus = parseInt(valuePlus)
|
this.valuePlus = parseInt(valuePlus)
|
||||||
}
|
}
|
||||||
|
@ -65,9 +65,10 @@ class Sequence extends Expr.Expression {
|
||||||
cache(n = 1) {
|
cache(n = 1) {
|
||||||
var str = Utils.simplifyExpression(this.calc.substitute('n', n-this.valuePlus).toString())
|
var str = Utils.simplifyExpression(this.calc.substitute('n', n-this.valuePlus).toString())
|
||||||
var expr = C.parser.parse(str).simplify()
|
var expr = C.parser.parse(str).simplify()
|
||||||
var l = {'n': n-this.valuePlus} // Just in case, add n (for custom functions)
|
C.currentVars = Object.assign(
|
||||||
l[this.name] = this.calcValues
|
{'n': n-this.valuePlus, [this.name]: this.calcValues}, // Just in case, add n (for custom functions)
|
||||||
C.currentVars = Object.assign(l, C.evalVariables)
|
C.currentObjectsByName
|
||||||
|
)
|
||||||
this.calcValues[n] = expr.evaluate(C.currentVars)
|
this.calcValues[n] = expr.evaluate(C.currentVars)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,14 +19,15 @@
|
||||||
.pragma library
|
.pragma library
|
||||||
|
|
||||||
.import "utils.js" as Utils
|
.import "utils.js" as Utils
|
||||||
.import "mathlib.js" as MathLib
|
.import "math/common.js" as MathCommons
|
||||||
.import "parameters.js" as P
|
.import "parameters.js" as P
|
||||||
|
|
||||||
var types = {}
|
var types = {}
|
||||||
|
|
||||||
var currentObjects = {}
|
var currentObjects = {}
|
||||||
var currentObjectsByName = {}
|
var currentObjectsByName = {}
|
||||||
|
MathCommons.currentObjectsByName = currentObjectsByName // Required for using objects in variables.
|
||||||
|
|
||||||
function renameObject(oldName, newName) {
|
function renameObject(oldName, newName) {
|
||||||
/**
|
/**
|
||||||
* Renames an object from its old name to the new one.
|
* Renames an object from its old name to the new one.
|
||||||
|
@ -46,7 +47,7 @@ function deleteObject(objName) {
|
||||||
*/
|
*/
|
||||||
let obj = currentObjectsByName[objName]
|
let obj = currentObjectsByName[objName]
|
||||||
delete currentObjectsByName[objName]
|
delete currentObjectsByName[objName]
|
||||||
currentObjects[obj.type].splice(currentObjects.indexOf(obj),1)
|
currentObjects[obj.type].splice(currentObjects[obj.type].indexOf(obj),1)
|
||||||
obj.delete()
|
obj.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -187,7 +187,7 @@ class DrawableObject {
|
||||||
* Callback method when one of the properties of the object is updated.
|
* Callback method when one of the properties of the object is updated.
|
||||||
*/
|
*/
|
||||||
update() {
|
update() {
|
||||||
for(var req of this.requiredBy) {
|
for(let req of this.requiredBy) {
|
||||||
req.update()
|
req.update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue