Adding object properties usable in expressions

This commit is contained in:
Ad5001 2022-10-17 22:30:59 +02:00
parent fad5325501
commit 6b535dd8a2
Signed by: Ad5001
GPG key ID: 7251B1AF90B960F9
6 changed files with 30 additions and 17 deletions

View file

@ -194,6 +194,7 @@ function evaluate(tokens, expr, values) {
nstack.push(f(resolveExpression(n1, values), resolveExpression(n2, values), resolveExpression(n3, values)));
}
} else if (type === IVAR) {
// Check for variable value
if (item.value in expr.functions) {
nstack.push(expr.functions[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();
if (f.apply && f.call) {
nstack.push(f.apply(undefined, args));
} else if(f.execute) {
// Objects & expressions execution
nstack.push(f.execute.apply(undefined, args));
} else {
throw new Error(f + ' is not a function');
throw new Error(f + ' cannot be executed');
}
} else if (type === IFUNDEF) {
// Create closure to keep references to arguments and expression

View file

@ -22,7 +22,9 @@
.import "../utils.js" as Utils
.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,
"π": Math.PI,
"inf": Infinity,
@ -33,18 +35,21 @@ var evalVariables = { // Variables not provided by expr-eval.js, needs to be pro
}
var currentVars = {}
var currentObjectsByName = {} // Mirror of currentObjectsByName in objects.js
const parser = new ExprEval.Parser()
parser.consts = Object.assign({}, parser.consts, evalVariables)
// Function definition
parser.functions.integral = function(a, b, f, variable) {
// https://en.wikipedia.org/wiki/Simpson%27s_rule
// Simpler, faster than tokenizing the expression
f = parser.parse(f).toJSFunction(variable, currentVars)
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) {
f = parser.parse(f).toJSFunction(variable, currentVars)
return (f(x+DERIVATION_PRECISION/2)-f(x-DERIVATION_PRECISION/2))/DERIVATION_PRECISION
}

View file

@ -30,23 +30,25 @@ class Expression {
this.expr = expr
this.calc = C.parser.parse(expr).simplify()
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)
}
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) {
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)
}
simplify(x) {
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());
if(str != undefined && str.match(/^\d*\.\d+$/)) {
if(str.split('.')[1].split('0').length > 7) {

View file

@ -39,7 +39,7 @@ class Sequence extends Expr.Expression {
if(['string', 'number'].includes(typeof this.calcValues[n])) {
let parsed = C.parser.parse(this.calcValues[n].toString()).simplify()
this.latexValues[n] = Latex.expression(parsed.tokens)
this.calcValues[n] = parsed.evaluate(C.evalVariables)
this.calcValues[n] = parsed.evaluate()
}
this.valuePlus = parseInt(valuePlus)
}
@ -65,9 +65,10 @@ class Sequence extends Expr.Expression {
cache(n = 1) {
var str = Utils.simplifyExpression(this.calc.substitute('n', n-this.valuePlus).toString())
var expr = C.parser.parse(str).simplify()
var l = {'n': n-this.valuePlus} // Just in case, add n (for custom functions)
l[this.name] = this.calcValues
C.currentVars = Object.assign(l, C.evalVariables)
C.currentVars = Object.assign(
{'n': n-this.valuePlus, [this.name]: this.calcValues}, // Just in case, add n (for custom functions)
C.currentObjectsByName
)
this.calcValues[n] = expr.evaluate(C.currentVars)
}

View file

@ -19,14 +19,15 @@
.pragma library
.import "utils.js" as Utils
.import "mathlib.js" as MathLib
.import "math/common.js" as MathCommons
.import "parameters.js" as P
var types = {}
var currentObjects = {}
var currentObjectsByName = {}
MathCommons.currentObjectsByName = currentObjectsByName // Required for using objects in variables.
function renameObject(oldName, newName) {
/**
* Renames an object from its old name to the new one.
@ -46,7 +47,7 @@ function deleteObject(objName) {
*/
let obj = 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()
}

View file

@ -187,7 +187,7 @@ class DrawableObject {
* Callback method when one of the properties of the object is updated.
*/
update() {
for(var req of this.requiredBy) {
for(let req of this.requiredBy) {
req.update()
}
}