Files
symclaw/docs/API.md
T

363 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SymClaw API Reference
## Rust API (`symclaw-core`)
### `symclaw_core::parser::parse`
Parse a mathematical expression string into an AST.
```rust
pub fn parse(input: &str) -> Result<Arc<Expr>, ParseError>
```
**Supported syntax:**
- Arithmetic: `+`, `-`, `*`, `/`, `^` (with standard precedence)
- Implicit multiplication: `2x`, `3(x+1)`, `xy`
- Functions: `sin`, `cos`, `tan`, `exp`, `ln`, `log`, `sqrt`, `abs`, `sinh`, `cosh`, `tanh`, `asin`, `acos`, `atan`
- Constants: `pi`, `e`
- Parentheses: `(`, `)`
```rust
use symclaw_core::parser::parse;
let expr = parse("2*x^2 + 3*x - 5").unwrap();
let expr = parse("sin(x^2) * exp(-x)").unwrap();
let expr = parse("(x + 1)/(x - 1)").unwrap();
```
**Errors:** Returns `ParseError` with byte offset and description for malformed input.
---
### `symclaw_core::simplify::simplify`
Simplify an expression to canonical form using the algebraic pipeline.
```rust
pub fn simplify(expr: &Expr) -> Arc<Expr>
```
Applies: constant folding, identity elimination, like-term collection, canonical ordering. Does *not* invoke e-graph saturation (use `simplify_egraph` for that).
```rust
use symclaw_core::{parser::parse, simplify::simplify};
let expr = parse("x + 0 + 2*x + 3").unwrap();
let result = simplify(&expr);
// → 3*x + 3
```
---
### `symclaw_core::egraph::simplify_egraph`
Deep simplification via equality saturation.
```rust
pub fn simplify_egraph(expr: &Expr) -> Arc<Expr>
```
Inserts the expression into an e-graph, applies 30+ rewrite rules until saturation, then extracts the smallest equivalent expression. More powerful than `simplify()` but slower (~10-100× depending on expression complexity).
```rust
use symclaw_core::{parser::parse, egraph::simplify_egraph};
let expr = parse("sin(x)^2 + cos(x)^2").unwrap();
let result = simplify_egraph(&expr);
// → 1
```
---
### `symclaw_core::egraph::explain_equivalence`
Prove that two expressions are equivalent by returning the chain of rewrite rules.
```rust
pub fn explain_equivalence(a: &Expr, b: &Expr) -> Option<Vec<String>>
```
Returns `None` if the expressions are not equivalent within the saturation budget.
```rust
use symclaw_core::{parser::parse, egraph::explain_equivalence};
let a = parse("(x+1)^2").unwrap();
let b = parse("x^2 + 2*x + 1").unwrap();
let steps = explain_equivalence(&a, &b).unwrap();
for step in &steps {
println!("{step}");
}
```
---
### `symclaw_core::differentiate::differentiate`
Compute the symbolic derivative of an expression.
```rust
pub fn differentiate(expr: &Expr, var: Symbol) -> Arc<Expr>
```
Supports all elementary functions with chain rule. Result is automatically simplified.
```rust
use symclaw_core::{parser::parse, differentiate::differentiate};
let expr = parse("sin(x^2)").unwrap();
let deriv = differentiate(&expr, "x".into());
// → 2*x*cos(x^2)
// Higher-order
let second = differentiate(&deriv, "x".into());
// Partial derivatives
let expr = parse("x^2 * y + y^3").unwrap();
let dx = differentiate(&expr, "x".into()); // → 2*x*y
let dy = differentiate(&expr, "y".into()); // → x^2 + 3*y^2
```
---
### `symclaw_core::integrate::integrate`
Compute the symbolic indefinite integral.
```rust
pub fn integrate(expr: &Expr, var: Symbol) -> Option<Arc<Expr>>
```
Returns `None` when no closed-form antiderivative is found. Does not include the constant of integration.
```rust
use symclaw_core::{parser::parse, integrate::integrate};
let expr = parse("x^2").unwrap();
let result = integrate(&expr, "x".into());
// → Some(x^3/3)
let expr = parse("sin(x) * cos(x)").unwrap();
let result = integrate(&expr, "x".into());
// → Some(sin(x)^2/2)
```
**Strategies applied:** linearity, power rule, known antiderivatives, u-substitution, integration by parts.
---
### `symclaw_core::solve::solve`
Solve the equation `expr = 0` for the given variable.
```rust
pub fn solve(expr: &Expr, var: Symbol) -> Vec<Arc<Expr>>
```
Returns all found solutions as simplified expressions. Empty vector if no solutions are found.
```rust
use symclaw_core::{parser::parse, solve::solve};
// Quadratic
let expr = parse("x^2 - 5*x + 6").unwrap();
let solutions = solve(&expr, "x".into());
// → [2, 3]
// Linear
let expr = parse("3*x + 7").unwrap();
let solutions = solve(&expr, "x".into());
// → [-7/3]
// Transcendental
let expr = parse("exp(x) - 1").unwrap();
let solutions = solve(&expr, "x".into());
// → [0]
```
---
### `symclaw_core::series::taylor`
Compute the Taylor series expansion of an expression.
```rust
pub fn taylor(expr: &Expr, var: Symbol, point: &Expr, order: u32) -> Arc<Expr>
```
Expands `expr` around `point` to the given `order`. Uses fast-path for known functions, falls back to repeated differentiation.
```rust
use symclaw_core::{parser::parse, series::taylor};
let expr = parse("sin(x)").unwrap();
let zero = parse("0").unwrap();
let series = taylor(&expr, "x".into(), &zero, 5);
// → x - x^3/6 + x^5/120
let expr = parse("exp(x)").unwrap();
let series = taylor(&expr, "x".into(), &zero, 4);
// → 1 + x + x^2/2 + x^3/6 + x^4/24
```
---
### `symclaw_core::eval::eval`
Numerically evaluate an expression with variable substitution.
```rust
pub fn eval(expr: &Expr, vars: &HashMap<Symbol, f64>) -> Result<f64, EvalError>
```
```rust
use std::collections::HashMap;
use symclaw_core::{parser::parse, eval::eval};
let expr = parse("x^2 + y").unwrap();
let mut vars = HashMap::new();
vars.insert("x".into(), 3.0);
vars.insert("y".into(), 1.0);
let result = eval(&expr, &vars).unwrap();
// → 10.0
```
**Errors:** `EvalError::UndefinedVariable` if a variable has no binding, `EvalError::DomainError` for operations like `ln(-1)`.
---
### `symclaw_core::latex::to_latex`
Render an expression as a LaTeX string.
```rust
pub fn to_latex(expr: &Expr) -> String
```
```rust
use symclaw_core::{parser::parse, latex::to_latex};
let expr = parse("x^2/(2*y) + sqrt(z)").unwrap();
let latex = to_latex(&expr);
// → "\\frac{x^{2}}{2 y} + \\sqrt{z}"
```
Handles fractions (`\frac`), square roots (`\sqrt`), Greek letters, subscripts, and proper spacing.
---
## WASM API (`symclaw-wasm`)
All WASM functions accept and return strings. Import via:
```javascript
import init, * as symclaw from 'symclaw-wasm';
await init();
```
| Function | Signature | Description |
|---|---|---|
| `parse(input)` | `string → string` | Parse and echo canonical form |
| `simplify(input)` | `string → string` | Simplify expression |
| `differentiate(expr, var)` | `(string, string) → string` | Symbolic derivative |
| `integrate(expr, var)` | `(string, string) → string \| null` | Symbolic integral |
| `solve(expr, var)` | `(string, string) → string` | JSON array of solutions |
| `taylor(expr, var, point, order)` | `(string, string, string, number) → string` | Taylor expansion |
| `eval_expr(expr, vars_json)` | `(string, string) → number` | Numeric evaluation |
| `to_latex(expr)` | `string → string` | LaTeX rendering |
| `simplify_egraph(expr)` | `string → string` | E-graph simplification |
| `explain(a, b)` | `(string, string) → string \| null` | Equivalence proof (JSON) |
| `plot_data(expr, var, start, end, steps)` | `(...) → string` | JSON array of [x, y] points |
| `version()` | `() → string` | Engine version |
---
## Skill Protocol (JSON-RPC)
The `symclaw-skill` binary reads JSON objects from stdin (one per line) and writes responses to stdout.
### `simplify`
```json
// Request
{"action": "simplify", "expr": "x^2 + 2*x + 1"}
// Response
{"success": true, "result": "(x + 1)^2", "latex": "(x + 1)^{2}"}
```
### `differentiate`
```json
// Request
{"action": "differentiate", "expr": "sin(x^2)", "var": "x"}
// "var" defaults to "x" if omitted
// Response
{"success": true, "result": "2*x*cos(x^2)", "latex": "2 x \\cos(x^{2})"}
```
### `integrate`
```json
// Indefinite
{"action": "integrate", "expr": "x^2", "var": "x"}
{"success": true, "result": "x^3/3", "latex": "\\frac{x^{3}}{3}"}
// Definite
{"action": "integrate", "expr": "x^2", "var": "x", "lower": "0", "upper": "1"}
{"success": true, "result": "1/3", "latex": "\\frac{1}{3}"}
```
### `solve`
```json
{"action": "solve", "expr": "x^2 - 5*x + 6", "var": "x"}
{"success": true, "solutions": ["2", "3"], "latex_solutions": ["2", "3"]}
```
### `taylor`
```json
{"action": "taylor", "expr": "sin(x)", "var": "x", "point": "0", "order": 5}
{"success": true, "result": "x - x^3/6 + x^5/120", "latex": "x - \\frac{x^{3}}{6} + \\frac{x^{5}}{120}"}
```
### `eval`
```json
{"action": "eval", "expr": "x^2 + y", "vars": {"x": 3.0, "y": 1.0}}
{"success": true, "value": 10.0}
```
### `latex`
```json
{"action": "latex", "expr": "x^2/(2*y) + sqrt(z)"}
{"success": true, "latex": "\\frac{x^{2}}{2 y} + \\sqrt{z}"}
```
### `plot_data`
```json
{"action": "plot_data", "expr": "sin(x)", "var": "x", "start": -6.283, "end": 6.283, "steps": 200}
{"success": true, "points": [[-6.283, 0.0016], ..., [6.283, -0.0016]]}
```
### Error Response
All actions return this format on failure:
```json
{"success": false, "error": "Parse error at byte 5: unexpected token ')'"}
```
### Canvas Actions
The skill also supports canvas rendering via the `skill.json` manifest:
- **`canvas/manipulate.html`** — Interactive plot with parameter sliders. The gateway loads this in an iframe and passes expression + parameter ranges. WASM evaluates client-side.
- **`canvas/result.html`** — Formatted result display with LaTeX rendering via KaTeX.
These are triggered by the OpenClaw gateway when the skill returns canvas-compatible data, not by direct JSON-RPC calls.