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

refactor: perform dimensional analysis and numerical evaluation in same pass (WIP) #312

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b108310
refactor: simplify logic for preventing unit canceling
mgreminger Jan 3, 2025
c9f5f73
refactor: move all multiplication dimensional analysis logic to place…
mgreminger Jan 3, 2025
4128bdf
refactor: remove unused variable
mgreminger Jan 3, 2025
0aa0e43
refactor: eliminate need for unitless expression pass
mgreminger Jan 5, 2025
439bee2
fix: fix user function regressions
mgreminger Jan 6, 2025
e60bb21
fix: fix matrix indexing regression
mgreminger Jan 6, 2025
014090a
fix: fix code generation regression
mgreminger Jan 6, 2025
f184195
fix: fix intermediate result rendering regression
mgreminger Jan 6, 2025
8c61541
refactor: remove unnecessary lines
mgreminger Jan 7, 2025
87f8bf0
fix: fix plot label regression
mgreminger Jan 7, 2025
569a0a0
refactor: reduce complexity for dims need values logic
mgreminger Jan 7, 2025
f6ca302
tests: increase timeout for symbolic expression error test
mgreminger Jan 7, 2025
2f053c2
refactor: remove unused unitless sub query code from python code
mgreminger Jan 7, 2025
9d69544
refactor: remove unused unitless subquery code from javascript code
mgreminger Jan 7, 2025
0e447db
fix: apply evalf to exponents
mgreminger Jan 7, 2025
771036f
fix: only convert exponent to float for numeric base and exp
mgreminger Jan 7, 2025
0255ce2
fix: only switch to floating point exponents for very large rationals
mgreminger Jan 8, 2025
14ecb9c
feat: add result to DimValues dict
mgreminger Jan 8, 2025
3643dc2
fix: fix typescript compiler error
mgreminger Jan 8, 2025
0ba5eba
tests: add test for nested function calls with exponents and units
mgreminger Jan 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
425 changes: 156 additions & 269 deletions public/dimensional_analysis.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/MathCell.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@
const currentResultLatex = getLatexResult(createSubQuery(sympyVar), subResults.get(sympyVar), numberConfig);
let newLatex: string;
if (currentResultLatex.error) {
newLatex = String.raw`\text{${currentResultLatex.error}}`;
newLatex = String.raw`\text{${currentResultLatex.error.startsWith("Dimension Error:") ? "Dimension Error" : currentResultLatex.error}}`;
} else {
newLatex = ` ${currentResultLatex.resultLatex}${currentResultLatex.resultUnitsLatex} `;
}
Expand Down
2 changes: 0 additions & 2 deletions src/cells/FluidCell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,10 +294,8 @@ export default class FluidCell extends BaseCell {
name: this.mathField.statement.name,
sympy: `${fluidFuncName}(0,0)`,
params: [],
isUnitlessSubExpression: false,
isFunctionArgument: false,
isFunction: false,
unitlessSubExpressions: [],
implicitParams: [],
functions: [],
arguments: [],
Expand Down
143 changes: 29 additions & 114 deletions src/parser/LatexToSympy.ts

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/parser/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export const BUILTIN_FUNCTION_MAP = new Map([
['stdevp', '_stdevp']
]);

export const BUILTIN_FUNCTION_NEEDS_VALUES= new Set(['range',]);

export const COMPARISON_MAP = new Map([
["<", "_StrictLessThan"],
["\\le", "_LessThan"],
Expand Down
22 changes: 3 additions & 19 deletions src/parser/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export type BlankStatement = {
type: "blank";
params: [];
implicitParams: [];
unitlessSubExpressions: [];
isFromPlotCell: false;
};

Expand Down Expand Up @@ -87,10 +86,8 @@ type BaseAssignmentStatement = {
name: string;
sympy: string;
params: string[];
isUnitlessSubExpression: false;
isFunctionArgument: false;
isFunction: false;
unitlessSubExpressions: UnitlessSubExpression[];
};

export type UserFunction = Omit<BaseAssignmentStatement, "isFunction"> & {
Expand All @@ -110,17 +107,9 @@ export type UserFunctionRange = Omit<UserFunction, "isRange"> & {
};


export type UnitlessSubExpression = Omit<BaseAssignmentStatement, "isUnitlessSubExpression"> & {
isUnitlessSubExpression: true;
unitlessContext: string;
isFunctionArgument: false;
isFunction: false;
};

export type FunctionArgumentAssignment = Pick<BaseAssignmentStatement,
"type" | "name" | "sympy" |
"params" | "unitlessSubExpressions"> & {
isUnitlessSubExpression: false;
"params"> & {
isFunctionArgument: true;
isFunction: false;
};
Expand Down Expand Up @@ -168,13 +157,11 @@ export type EqualityStatement = Omit<AssignmentStatement, "type" | "name"> & {
type BaseQueryStatement = {
type: "query";
sympy: string;
unitlessSubExpressions: UnitlessSubExpression[];
implicitParams: ImplicitParameter[];
params: string[];
functions: (UserFunction | UserFunctionRange | FunctionUnitsQuery)[];
arguments: (FunctionArgumentAssignment | FunctionArgumentQuery) [];
localSubs: (LocalSubstitution | LocalSubstitutionRange)[];
isUnitlessSubExpression: false;
isFunctionArgument: false;
isFunction: false;
isUnitsQuery: false;
Expand Down Expand Up @@ -264,7 +251,6 @@ export type ScatterQueryStatement = {
arguments: (FunctionArgumentAssignment | FunctionArgumentQuery) [];
localSubs: (LocalSubstitution | LocalSubstitutionRange)[];
implicitParams: ImplicitParameter[];
unitlessSubExpressions: UnitlessSubExpression[];
equationIndex: number;
cellNum: number;
isFromPlotCell: boolean;
Expand Down Expand Up @@ -298,9 +284,8 @@ export type CodeFunctionRawQuery = BaseQueryStatement & {
isCodeFunctionRawQuery: true;
}

export type FunctionArgumentQuery = Pick<BaseQueryStatement, "type" | "sympy" | "params" | "unitlessSubExpressions" > & {
export type FunctionArgumentQuery = Pick<BaseQueryStatement, "type" | "sympy" | "params" > & {
name: string;
isUnitlessSubExpression: false;
isFunctionArgument: true;
isFunction: false;
isUnitsQuery: false;
Expand All @@ -310,9 +295,8 @@ export type FunctionArgumentQuery = Pick<BaseQueryStatement, "type" | "sympy" |
isCodeFunctionRawQuery: false;
};

export type FunctionUnitsQuery = Pick<BaseQueryStatement, "type" | "sympy" | "params" | "unitlessSubExpressions" > & {
export type FunctionUnitsQuery = Pick<BaseQueryStatement, "type" | "sympy" | "params" > & {
units: '';
isUnitlessSubExpression: false;
isFunctionArgument: false;
isFunction: false;
isUnitsQuery: true;
Expand Down
5 changes: 2 additions & 3 deletions src/parser/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,13 @@ export function applyEdits(source: string, pendingEdits: (Insertion | Replacemen
export function createSubQuery(name: string): SubQueryStatement {
return {
type: "query",
unitlessSubExpressions: [],
implicitParams: [],
params: [name],
functions: [],
arguments: [],
localSubs: [],
units: "",
unitsLatex: "",
isUnitlessSubExpression: false,
isFunctionArgument: false,
isFunction: false,
isUnitsQuery: false,
Expand All @@ -112,4 +110,5 @@ export function createSubQuery(name: string): SubQueryStatement {
isCodeFunctionQuery: false,
isCodeFunctionRawQuery: false
};
}
}

16 changes: 16 additions & 0 deletions tests/test_basic.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,22 @@ test('Test function notation with exponents and units', async () => {

});

test('Test function notation with exponents and units and nested functions', async () => {

await page.setLatex(0, String.raw`t\left(s=y\left(x=2\left\lbrack in\right\rbrack\right)\cdot1\left\lbrack in\right\rbrack\right)=`);
await page.click('#add-math-cell');
await page.setLatex(1, String.raw`t=2^{\frac{s}{1\left\lbrack in\right\rbrack}}`);
await page.click('#add-math-cell');
await page.setLatex(2, String.raw`y=3^{\frac{x}{1\left\lbrack in\right\rbrack}}`);

await page.waitForSelector('text=Updating...', {state: 'detached'});

let content = await page.textContent('#result-value-0');
expect(parseLatexFloat(content)).toBeCloseTo(512, precision-1);
content = await page.textContent('#result-units-0');
expect(content).toBe('');
});


test('Test function notation with integrals', async () => {

Expand Down
13 changes: 11 additions & 2 deletions tests/test_matrix_functions.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,17 @@
expect(content).toBe(String.raw`\begin{bmatrix} 0\left\lbrack m\right\rbrack \\ 1\left\lbrack m\right\rbrack \\ 2\left\lbrack m\right\rbrack \\ 3\left\lbrack m\right\rbrack \\ 4\left\lbrack m\right\rbrack \\ 5\left\lbrack m\right\rbrack \end{bmatrix}`);
});

test('Test range input needs to be unitless', async () => {
await page.setLatex(0, String.raw`\mathrm{range}\left(1\left\lbrack m\right\rbrack,2\left\lbrack m\right\rbrack,.1\left\lbrack m\right\rbrack\right)=`);
test('Test range with consistent units', async () => {
await page.setLatex(0, String.raw`\mathrm{range}\left(1\left\lbrack m\right\rbrack,2\left\lbrack m\right\rbrack,1\left\lbrack m\right\rbrack\right)=`);

await page.waitForSelector('text=Updating...', {state: 'detached'});

let content = await page.textContent(`#result-value-0`);
expect(content).toBe(String.raw`\begin{bmatrix} 1\left\lbrack m\right\rbrack \\ 2\left\lbrack m\right\rbrack \end{bmatrix}`);
});

test('Test range with inconsistent units', async () => {
await page.setLatex(0, String.raw`\mathrm{range}\left(1\left\lbrack m\right\rbrack,2\left\lbrack s\right\rbrack,1\left\lbrack m\right\rbrack\right)=`);

await page.waitForSelector('text=Updating...', {state: 'detached'});

Expand Down Expand Up @@ -402,7 +411,7 @@

await page.waitForSelector('text=Updating...', {state: 'detached'});

let content = await page.textContent(`#result-value-0`);

Check failure on line 414 in tests/test_matrix_functions.spec.mjs

View workflow job for this annotation

GitHub Actions / test

[firefox] › test_matrix_functions.spec.mjs:409:1 › Test count function for symbolic row vector

3) [firefox] › test_matrix_functions.spec.mjs:409:1 › Test count function for symbolic row vector TimeoutError: page.textContent: Timeout 120000ms exceeded. Call log: - waiting for locator('#result-value-0') 412 | await page.waitForSelector('text=Updating...', {state: 'detached'}); 413 | > 414 | let content = await page.textContent(`#result-value-0`); | ^ 415 | expect(parseLatexFloat(content)).toBeCloseTo(3, precision); 416 | 417 | content = await page.textContent('#result-units-0'); at /home/runner/work/EngineeringPaper.xyz/EngineeringPaper.xyz/tests/test_matrix_functions.spec.mjs:414:28
expect(parseLatexFloat(content)).toBeCloseTo(3, precision);

content = await page.textContent('#result-units-0');
Expand Down
9 changes: 9 additions & 0 deletions tests/test_number_format.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ test('Test symbolic format', async () => {
await page.locator('#add-math-cell').click();
await page.setLatex(2, String.raw`\frac{-3\left\lbrack mm\right\rbrack}{\sqrt2}=`);

// symbolic expression with fractional exponent
await page.locator('#add-math-cell').click();
await page.setLatex(3, String.raw`3.0^{.500}=`);

await page.waitForSelector('text=Updating...', {state: 'detached'});

// check all values rendered as floating point values first
Expand All @@ -69,6 +73,9 @@ test('Test symbolic format', async () => {
content = await page.textContent('#result-units-2');
expect(content).toBe('m');

content = await page.textContent('#result-value-3');
expect(parseLatexFloat(content)).toBeCloseTo(sqrt(3), precision);

// switch to symbolic formatting
await page.getByRole('button', { name: 'Sheet Settings' }).click();
await page.locator('label').filter({ hasText: 'Display Symbolic Results' }).click();
Expand All @@ -87,6 +94,8 @@ test('Test symbolic format', async () => {
content = await page.textContent('#result-units-2');
expect(content).toBe('m');

content = await page.textContent('#result-value-3');
expect(content).toBe(String.raw`\sqrt{3}`);
});

test('Test disabling automatic expressions simplification', async () => {
Expand Down
Loading