Skip to content

Commit 7024d9f

Browse files
committed
arch: more free functions
1 parent 3c42155 commit 7024d9f

5 files changed

Lines changed: 201 additions & 12 deletions

File tree

CHANGELOG.md

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,45 @@ ce.function('Add', [1, 'x'], { form: 'structural' }); // bound, not fully canoni
5252
ce.box(['Add', 1, 'x'], { form: ['Number', 'Order'] }); // selective passes
5353
```
5454

55+
#### New Free Functions: `parse()`, `simplify()`, `evaluate()`, `N()`, `assign()`
56+
57+
Top-level free functions are now available for the most common operations. They
58+
use a shared `ComputeEngine` instance created on first call, so no setup is
59+
required.
60+
61+
```ts
62+
import { parse, simplify, evaluate, N, assign } from '@cortex-js/compute-engine';
63+
64+
simplify('x + x + 1'); // 2x + 1
65+
evaluate('2^{11} - 1'); // 2047
66+
N('\\sqrt{2}'); // 1.414213562…
67+
68+
assign('x', 3);
69+
evaluate('x + 2'); // 5
70+
```
71+
72+
Except for `parse()` (which only accepts a LaTeX string), each function accepts
73+
either a LaTeX string or an existing `BoxedExpression`:
74+
75+
```ts
76+
const expr = parse('x + x + 1');
77+
simplify(expr); // same as simplify('x + x + 1')
78+
```
79+
80+
Use `getDefaultEngine()` to access the shared engine for configuration
81+
(precision, angular unit, etc.) or to call methods like `forget()`.
82+
5583
#### `compile()` Is Now a Free Function
5684

5785
The `expr.compile()` method has been replaced by a standalone `compile()`
58-
function with a structured `CompilationResult` return type.
86+
function with a structured `CompilationResult` return type. It accepts either a
87+
LaTeX string or a `BoxedExpression`.
5988

6089
```ts
6190
import { compile } from '@cortex-js/compute-engine';
6291

63-
const result = compile(ce.parse('x^2 + 1'));
92+
// From a LaTeX string
93+
const result = compile('x^2 + 1');
6494
result.run({ x: 3 }); // 10
6595
result.code; // generated source
6696
result.success; // true
@@ -79,24 +109,51 @@ Custom compilation targets can be registered and unregistered dynamically via
79109
while `expandAll()` applies it recursively. Both return `null` if the expression
80110
cannot be expanded.
81111

112+
Both accept a LaTeX string or a `BoxedExpression`, consistent with the other free
113+
functions (`simplify`, `evaluate`, `N`).
114+
82115
```ts
83116
import { expand, expandAll } from '@cortex-js/compute-engine';
84117

118+
// From a LaTeX string
119+
expand('(x+1)^2'); // x^2 + 2x + 1
120+
expandAll('(x+1)(x+2) + (a+b)^2'); // recursive expansion
121+
122+
// From a BoxedExpression
85123
const expr = ce.parse('(x+1)(x+2)');
86124
expand(expr); // x^2 + 3x + 2
87-
expandAll(complexExpr); // recursive expansion
88125

89126
// Returns null when not expandable — use ?? for fallback
90127
const result = expand(expr) ?? expr;
91128
```
92129

130+
#### `solve()` Is a Free Function
131+
132+
A new `solve()` free function is available for solving equations without
133+
explicitly creating a `ComputeEngine` instance. Like the other free functions, it
134+
accepts either a LaTeX string or a `BoxedExpression`.
135+
136+
```ts
137+
import { solve } from '@cortex-js/compute-engine';
138+
139+
// Solve from LaTeX
140+
solve('x^2 - 5x + 6 = 0', 'x'); // [2, 3]
141+
142+
// Solve from a BoxedExpression
143+
const expr = ce.parse('x^2 - 5x + 6 = 0');
144+
solve(expr, 'x'); // [2, 3]
145+
```
146+
93147
#### `factor()` Is a Free Function
94148

95-
Polynomial factoring functions are now standalone free functions.
149+
Polynomial factoring functions are now standalone free functions. `factor()`
150+
accepts a LaTeX string or a `BoxedExpression`. The specialized variants
151+
(`factorPolynomial`, `factorQuadratic`, etc.) accept only a `BoxedExpression`.
96152

97153
```ts
98154
import { factor, factorPolynomial, factorQuadratic } from '@cortex-js/compute-engine';
99155

156+
factor('(2x)(4y)'); // 8xy — from LaTeX
100157
factor(expr); // general factoring
101158
factorPolynomial(expr); // polynomial-specific
102159
factorQuadratic(expr); // quadratic-specific

src/compute-engine.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,18 @@ export { IntervalJavaScriptTarget } from './compute-engine/compilation/interval-
2929
export { IntervalGLSLTarget } from './compute-engine/compilation/interval-glsl-target';
3030
export { BaseCompiler } from './compute-engine/compilation/base-compiler';
3131

32-
export { expand } from './compute-engine/boxed-expression/expand';
33-
export { compile } from './compute-engine/compilation/compile-expression';
34-
3532
// Free functions backed by a lazily-instantiated global engine
3633
export {
3734
parse,
3835
simplify,
3936
evaluate,
4037
N,
4138
assign,
39+
expand,
40+
expandAll,
41+
factor,
42+
solve,
43+
compile,
4244
getDefaultEngine,
4345
} from './compute-engine/free-functions';
4446

src/compute-engine/free-functions.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import type { BoxedExpression, AssignValue, IComputeEngine } from './global-types';
22
import type { LatexString } from './latex-syntax/types';
3+
import { expand as expandExpr, expandAll as expandAllExpr } from './boxed-expression/expand';
4+
import { factor as factorExpr } from './boxed-expression/factor';
5+
import { compile as compileExpr } from './compilation/compile-expression';
36

47
let _defaultEngine: IComputeEngine | null = null;
58

@@ -47,3 +50,53 @@ export function assign(
4750
): void {
4851
getDefaultEngine().assign(arg1 as any, arg2 as any);
4952
}
53+
54+
export function expand(
55+
latex: LatexString | BoxedExpression
56+
): BoxedExpression | null {
57+
const expr =
58+
typeof latex === 'string' ? getDefaultEngine().parse(latex) : latex;
59+
return expandExpr(expr);
60+
}
61+
62+
export function solve(
63+
latex: LatexString | BoxedExpression,
64+
vars?:
65+
| string
66+
| Iterable<string>
67+
| BoxedExpression
68+
| Iterable<BoxedExpression>
69+
):
70+
| null
71+
| ReadonlyArray<BoxedExpression>
72+
| Record<string, BoxedExpression>
73+
| Array<Record<string, BoxedExpression>> {
74+
const expr =
75+
typeof latex === 'string' ? getDefaultEngine().parse(latex) : latex;
76+
return expr.solve(vars);
77+
}
78+
79+
export function expandAll(
80+
latex: LatexString | BoxedExpression
81+
): BoxedExpression | null {
82+
const expr =
83+
typeof latex === 'string' ? getDefaultEngine().parse(latex) : latex;
84+
return expandAllExpr(expr);
85+
}
86+
87+
export function factor(
88+
latex: LatexString | BoxedExpression
89+
): BoxedExpression {
90+
const expr =
91+
typeof latex === 'string' ? getDefaultEngine().parse(latex) : latex;
92+
return factorExpr(expr);
93+
}
94+
95+
export function compile(
96+
latex: LatexString | BoxedExpression,
97+
options?: Parameters<typeof compileExpr>[1]
98+
): ReturnType<typeof compileExpr> {
99+
const expr =
100+
typeof latex === 'string' ? getDefaultEngine().parse(latex) : latex;
101+
return compileExpr(expr, options);
102+
}

src/compute-engine/index.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,23 +176,24 @@ export {
176176
evaluate,
177177
N,
178178
assign,
179+
expand,
180+
expandAll,
181+
factor,
182+
solve,
183+
compile,
179184
getDefaultEngine,
180185
} from './free-functions';
181186

182187
export { validatePattern };
183188

184-
// Export polynomial factoring functions for advanced users
189+
// Export specialized polynomial factoring functions for advanced users
185190
export {
186-
factor,
187191
factorPerfectSquare,
188192
factorDifferenceOfSquares,
189193
factorQuadratic,
190194
factorPolynomial,
191195
};
192196

193-
// Export expression expansion functions
194-
export { expand, expandAll } from './boxed-expression/expand';
195-
196197
// Export compilation types and classes for advanced users
197198
export type {
198199
CompileTarget,

test/compute-engine/workflow-entrypoints.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import {
55
evaluate,
66
N,
77
assign,
8+
expand,
9+
expandAll,
10+
factor,
11+
solve,
12+
compile,
813
getDefaultEngine,
914
} from '../../src/compute-engine';
1015

@@ -89,4 +94,75 @@ describe('Free Functions', () => {
8994
// Reset
9095
getDefaultEngine().forget('w');
9196
});
97+
98+
test('expand() expands a LaTeX string', () => {
99+
const result = expand('(x+1)^2');
100+
expect(result).not.toBeNull();
101+
expect(result!.latex).toBe('x^2+2x+1');
102+
});
103+
104+
test('expand() expands a BoxedExpression', () => {
105+
const expr = parse('(x+1)(x+2)');
106+
const result = expand(expr);
107+
expect(result).not.toBeNull();
108+
expect(result!.latex).toBe('x^2+3x+2');
109+
});
110+
111+
test('solve() solves from a LaTeX string', () => {
112+
const result = solve('x^2 - 5x + 6 = 0', 'x');
113+
expect(result).not.toBeNull();
114+
expect(Array.isArray(result)).toBe(true);
115+
const values = (result as any[]).map((r) => r.valueOf());
116+
expect(values).toContain(2);
117+
expect(values).toContain(3);
118+
});
119+
120+
test('solve() solves from a BoxedExpression', () => {
121+
const expr = parse('x^2 - 5x + 6 = 0');
122+
const result = solve(expr, 'x');
123+
expect(result).not.toBeNull();
124+
expect(Array.isArray(result)).toBe(true);
125+
const values = (result as any[]).map((r) => r.valueOf());
126+
expect(values).toContain(2);
127+
expect(values).toContain(3);
128+
});
129+
130+
test('expandAll() expands from a LaTeX string', () => {
131+
const result = expandAll('(x+1)(x+2) + (a+b)^2');
132+
expect(result).not.toBeNull();
133+
});
134+
135+
test('expandAll() expands from a BoxedExpression', () => {
136+
const expr = parse('(x+1)^2');
137+
const result = expandAll(expr);
138+
expect(result).not.toBeNull();
139+
expect(result!.latex).toBe('x^2+2x+1');
140+
});
141+
142+
test('factor() factors from a LaTeX string', () => {
143+
const result = factor('(2x)(4y)');
144+
expect(result).toBeDefined();
145+
expect(result.latex).toBe('8xy');
146+
});
147+
148+
test('factor() factors from a BoxedExpression', () => {
149+
const expr = parse('(2x)(4y)');
150+
const result = factor(expr);
151+
expect(result).toBeDefined();
152+
expect(result.latex).toBe('8xy');
153+
});
154+
155+
test('compile() compiles from a LaTeX string', () => {
156+
const result = compile('x^2 + 1');
157+
expect(result).toBeDefined();
158+
expect(result.success).toBe(true);
159+
expect(typeof result.code).toBe('string');
160+
});
161+
162+
test('compile() compiles from a BoxedExpression', () => {
163+
const expr = parse('x^2 + 1');
164+
const result = compile(expr);
165+
expect(result).toBeDefined();
166+
expect(result.success).toBe(true);
167+
});
92168
});

0 commit comments

Comments
 (0)