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))); 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

View file

@ -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
} }

View file

@ -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) {

View file

@ -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)
} }

View file

@ -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()
} }

View file

@ -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()
} }
} }