Documentation
Everything you need to get started with Closyr — as a web solver, self-hosted server, CLI tool, or library.
Getting Started
Closyr is written in Rust. You need a working Rust toolchain to build from source.
# Install Rust (if you haven't already)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Clone the repository
git clone https://github.com/closyr/closyr.git
cd closyr
# Build in release mode
cargo build --release
The release build enables optimizations including SIMD vectorization and link-time optimization. Debug builds work but are significantly slower.
Running the Server
The default binary starts a web server with the solver UI and REST API.
# Start the server (default port 3000)
cargo run --release
# Or specify a custom port
cargo run --release -- --port 8080
Once running, open http://localhost:3000 in your browser. The server provides:
- The web solver UI at
/solver - A REST API at
/api/solvefor programmatic access - Server-Sent Events for real-time progress streaming
- Multi-threaded parallel evolution using all available CPU cores
Using the Web Solver
The Solver page is a full-featured UI for interactive symbolic regression.
1. Input your data
Enter x/y values manually, upload a CSV file, draw data points with the brush tool, or select from preset datasets (polynomial, trigonometric, physics benchmarks). Multi-variable datasets are supported via CSV upload.
2. Choose WASM or Server mode
WASM mode runs entirely in your browser — no server needed, data stays private. Server mode uses multi-threaded parallel evolution for faster results on larger datasets. Toggle between them with the mode switch.
3. Watch results evolve
The solver shows real-time charts: fitness progress over iterations, a Pareto front of accuracy vs. complexity, and a best-fit overlay on your data. Discovered formulas are rendered in LaTeX. You can pause, resume, or stop the solver at any time.
Command-Line (SRBench CLI)
The srbench binary accepts JSON on stdin and outputs JSON on stdout,
making it easy to integrate into scripts and pipelines.
# Build the CLI binary
cargo build --release --bin srbench
# Run on a simple dataset (x^2)
echo '{"xs":[1,2,3,4,5],"ys":[1,4,9,16,25],"iterations":100,"population":50,"max_leafs":20}' \
| ./target/release/srbench
{
"xs": [1.0, 2.0, 3.0],
"ys": [1.0, 4.0, 9.0],
"timeout_secs": 3600,
"iterations": 1000,
"population": 100,
"max_leafs": 30,
"populations": 31,
"ncycles_per_iteration": 380
}
{
"formula": "x ^ 2",
"predictions": [1.0, 4.0, 9.0],
"score": 0.0,
"complexity": 3
}
All fields except xs and ys have defaults.
The population parameter is the total across all populations
(each lagoon gets population / populations members).
Multi-Variable Example (3 variables)
For multi-variable regression, pass xs as a 2D array where each row
is a data point with one value per variable. Optionally provide
var_names to label the variables.
# 3-variable dataset: y = x1 + 2*x2 + 3*x3
echo '{
"xs": [[1,0,0],[0,1,0],[0,0,1],[1,1,0],[1,0,1],[0,1,1],[1,1,1],[2,1,3]],
"ys": [1, 2, 3, 3, 4, 5, 6, 13],
"var_names": ["x1","x2","x3"],
"iterations": 200,
"population": 100,
"max_leafs": 20
}' | ./target/release/srbench
{
"xs": [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
[1, 1, 0],
[1, 0, 1],
[0, 1, 1],
[1, 1, 1],
[2, 1, 3]
],
"ys": [1, 2, 3, 3, 4, 5, 6, 13],
"var_names": ["x1", "x2", "x3"],
"iterations": 200,
"population": 100,
"max_leafs": 20
}
{
"formula": "x1 + 2 * x2 + 3 * x3",
"predictions": [1, 2, 3, 3, 4, 5, 6, 13],
"score": 0.0,
"complexity": 9
}
Each row of xs has 3 values corresponding to
x1, x2, x3.
Without var_names, variables default to
x, x2, x3, etc.
Python Integration
Closyr includes an sklearn-compatible Python wrapper for use in data science workflows and SRBench benchmarking.
# Build the Rust binary first
cargo build --release --bin srbench
# Create a venv and install the wrapper
python3 -m venv .venv
source .venv/bin/activate
pip install -e srbench_wrapper
from srbench_wrapper import ClosyrRegressor
import numpy as np
est = ClosyrRegressor(iterations=100, population=50, max_leafs=20)
X = np.array([[1], [2], [3], [4], [5]])
y = np.array([1, 4, 9, 16, 25])
est.fit(X, y)
print("Formula:", est.formula_)
print("Predictions:", est.predict(X))
The wrapper follows the sklearn estimator interface: fit(X, y),
predict(X), and exposes the discovered formula via
est.formula_.
WASM Embedding
The closyr-wasm crate compiles the solver to WebAssembly for use in web applications.
# Build WASM (sequential, stable Rust)
bash build_wasm.sh
# Build with Web Worker parallelism (nightly Rust)
bash build_wasm_parallel.sh
import init, { solve } from './pkg/closyr_wasm.js';
await init();
const result = solve(JSON.stringify({
xs: [1, 2, 3, 4, 5],
ys: [1, 4, 9, 16, 25],
iterations: 100,
population: 50,
max_leafs: 20
}));
const { formula, predictions, score } = JSON.parse(result);
Two build modes are available:
- Sequential (
build_wasm.sh) — works on stable Rust, single-threaded - Parallel (
build_wasm_parallel.sh) — requires nightly Rust, uses Web Workers viawasm-bindgen-rayonand SharedArrayBuffer
The parallel build requires the server to send Cross-Origin-Opener-Policy: same-origin
and Cross-Origin-Embedder-Policy: require-corp headers.
Configuration Reference
These parameters can be passed via the CLI JSON input, the Python wrapper constructor, or the web solver's settings panel.
| Parameter | Default | Description |
|---|---|---|
| iterations | 1000 | Number of evolution iterations to run |
| population | 100 | Total population size across all lagoons |
| populations | 31 | Number of independent lagoons (sub-populations) |
| max_leafs | 30 | Maximum expression complexity (leaf count) |
| ncycles_per_iteration | 380 | Mutation cycles per lagoon per iteration |
| timeout_secs | 3600 | Maximum wall-clock time in seconds |
| scoring | MSE | Scoring method: MSE, MAE, LogCosh, or RSquared |
Higher population and iterations values
increase the chance of finding a good fit but take longer. Reducing
max_leafs constrains solutions to simpler formulas.