Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sympy parsing workaround for specific tokens #5178

Merged
merged 11 commits into from
Oct 18, 2024
Merged
37 changes: 33 additions & 4 deletions packages/client/hmi-client/src/python/PyodideWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,36 +52,60 @@ pyodide.runPython(`

postMessage(true);

// There are certain symbols or tokens that cause sympy parse to fallover - eg lambda
// These provides encoding/encoding functions to get around these problems.
const encodeParseExpr = (v: string) => {
let expr = v.toString().replaceAll('lambda', 'XXlambdaXX');
expr = expr.replaceAll('Ci', 'XXCiXX');
expr = expr.replaceAll('S', 'XXSXX');
return expr;
};
const revertParseExpr = (v: string) => {
let resultStr = v.replaceAll('XXlambdaXX', 'lambda');
resultStr = resultStr.replaceAll('XXSXX', 'S');
resultStr = resultStr.replaceAll('XXCiXX', 'Ci');
return resultStr;
};

const evaluateExpression = (expressionStr: string, symbolsTable: Object) => {
// if number-like, return as is
if (!Number.isNaN(parseFloat(expressionStr))) {
return expressionStr;
}
const subs: any[] = [];
Object.keys(symbolsTable).forEach((key) => {
subs.push(`${key}: ${symbolsTable[key]}`);
subs.push(`${encodeParseExpr(key)}: ${symbolsTable[key]}`);
});

const skeys = Object.keys(symbolsTable);
pyodide.runPython(`
${skeys.join(',')} = sympy.symbols('${skeys.join(' ')}')
${skeys.map(encodeParseExpr).join(',')} = sympy.symbols('${skeys.map(encodeParseExpr).join(' ')}')
`);

expressionStr = encodeParseExpr(expressionStr);
const result = pyodide.runPython(`
eq = sympy.S("${expressionStr}", locals=_clash)
eq.evalf(subs={${subs.join(', ')}})
`);
return result.toString();

return revertParseExpr(result.toString());
};

const parseExpression = (expr: string) => {
const output = {
mathml: '',
pmathml: '',
latex: '',
freeSymbols: []
freeSymbols: [] as any[]
};

if (!expr || expr.length === 0) {
return output;
}

// Special cases
expr = encodeParseExpr(expr);

// function to convert expression to presentation mathml
let result = pyodide.runPython(`
eq = sympy.S("${expr}", locals=_clash)
Expand Down Expand Up @@ -115,6 +139,11 @@ const parseExpression = (expr: string) => {
`);
output.freeSymbols = result.toJs();

output.latex = revertParseExpr(output.latex);
output.mathml = revertParseExpr(output.mathml);
output.pmathml = revertParseExpr(output.pmathml);
output.freeSymbols = output.freeSymbols.map(revertParseExpr);

return output;
};

Expand Down