Skip to content

Commit

Permalink
support of functionDefinition in DBSolve export
Browse files Browse the repository at this point in the history
  • Loading branch information
metelkin committed Jun 20, 2024
1 parent 0100b5b commit d3aabf5
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 19 deletions.
4 changes: 2 additions & 2 deletions cases/24-define-function/src/index.heta
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
math: f4(x)^2
};

/*
// throws error
#defineFunction f6 {
};

/*
// ref to wrong function
#defineFunction f7 {
arguments: [x,y],
Expand Down Expand Up @@ -68,7 +68,7 @@

c1 @Compartment .= 2;
s1 @Species {compartment: c1} .= 100;
r1 @Reaction {actors: s1=} := k1 * pow7(1.1) * c1;
r1 @Reaction {actors: s1=} := k1 * f5(1.1, k1) * pow(1.1, 2) * c1;

k1 @Const = 0.1;

Expand Down
16 changes: 15 additions & 1 deletion src/core/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,24 @@ class Expression {
let clonedMath = this.exprParsed.cloneDeep();
let expr = new Expression(clonedMath);
expr._logger = this._logger;
return expr;
}
// substitute user defined functions by their content, return Expression
substituteByDefinitions() {
let transformed = this.exprParsed.transform((node) => {
if (node.type === 'FunctionNode' && node.fnObj && !node.fnObj.isCore) {
return node.fnObj.substitute(node.args);
} else {
return node;
}
});

let expr = new Expression(transformed);
expr._logger = this._logger;

return expr;
}
updateReferences(q = {}){
updateReferences(q = {}) {
this.exprParsed.traverse((node , path/*, parent*/) => {
if (node.type === 'SymbolNode' && path !== 'fn') { // transform only SymbolNode
let oldRef = node.name;
Expand Down
21 changes: 21 additions & 0 deletions src/core/function-def.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,27 @@ class FunctionDef extends Top {
static get validate() {
return ajv.compile(schema);
}
// get Node (from mathjs) by substitution
substitute(nodes = []) {
// check arguments
if (this.arguments.length > nodes.length) {
throw new TypeError(`Function "${this.id}" requires minimum ${this.arguments.length} arguments, got ${nodes.length}`);
}

// substitute arguments by nodes
let transformed = this.math.exprParsed.transform((node) => {
let argIndex = this.arguments.indexOf(node.name);
if (node.type === 'SymbolNode' && argIndex !== -1) {
return nodes[argIndex];
} else if (node.type === 'FunctionNode' && node.fnObj && !node.fnObj.isCore) {
return node.fnObj.substitute(node.args);
} else {
return node;
}
});

return transformed;
}
bind() {
// super.bind();
let {logger, functionDefStorage} = this._container;
Expand Down
23 changes: 14 additions & 9 deletions src/dbsolve-export/expression.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
const { Expression } = require('../core/expression');

Expression.prototype.toSLVString = function(powTransform = 'keep') {
Expression.prototype.toSLVString = function(powTransform = 'keep', substituteByDefinitions = true) {
let tree = substituteByDefinitions ? this.substituteByDefinitions().exprParsed : this.exprParsed;

if (['keep', 'operator', 'function'].indexOf(powTransform) === -1) {
throw new TypeError('powTransform must be one of values: "keep", "operator", "function".');
}

let SLVStringHandler = (node, options) => {

// OperatorNode
if (node.type==='OperatorNode' && node.fn==='pow' && powTransform==='function') {
return `pow(${node.args[0].toString(options)}, ${node.args[1].toString(options)})`;
}

// FunctionNode
if (node.type==='FunctionNode' && node.fn.name==='pow' && powTransform==='operator') {
if (node.args[0].type==='OperatorNode') {
var arg0 = `(${node.args[0].toString(options)})`;
Expand Down Expand Up @@ -132,15 +138,15 @@ Expression.prototype.toSLVString = function(powTransform = 'keep') {
.map((arg) => arg.toString(options));
return `log(${args[0]}) / log(2)`;
}
// piecewise function
if (node.type === 'FunctionNode' && node.fn.name === 'piecewise') {
let msg = `DBS and SLV formats do not support "piecewise" function, got "${node.toString()}"`;
this._logger.error(msg);
let args = node.args
.map((arg) => arg.toString(options));
return `piecewise(${args.join(',')})`;
}
// ternary operator

// ConditionalNode: ternary operator
if (node.type === 'ConditionalNode') {
let condition = _removeParenthesis(node.condition);
let trueExpr = node.trueExpr.toString(options);
Expand Down Expand Up @@ -181,12 +187,11 @@ Expression.prototype.toSLVString = function(powTransform = 'keep') {
}
};

return this.exprParsed
.toString({
parenthesis: 'keep',
implicit: 'show',
handler: SLVStringHandler
});
return tree.toString({
parenthesis: 'keep',
implicit: 'show',
handler: SLVStringHandler
});
};

/* remove parenthesis from top */
Expand Down
7 changes: 0 additions & 7 deletions src/dbsolve-export/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,6 @@ class DBSolveExport extends AbstractExport{
makeText() {
let logger = this._container.logger;

// display that function definition is not supported
let userDefinedFunctions = [...this._container.functionDefStorage]
.filter(([id, functionDef]) => !functionDef.isCore)
.map(([id, functionDef]) => id);
if (userDefinedFunctions.length > 0) {
logger.warn(`User defined functions: ${userDefinedFunctions.join(', ')} are presented in platform but not supported by DBSolve export.`);
}

let selectedNamespaces = this.selectedNamespaces();

Expand Down

0 comments on commit d3aabf5

Please sign in to comment.