# 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, 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 ``` 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 ``` 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> ``` 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 ``` 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> ``` 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> ``` 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 ``` 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) -> Result ``` ```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.