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.

Terminal
# 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.

Terminal
# 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:

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.

Terminal
# 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
Input (JSON on stdin)
{
  "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
}
Output (JSON on stdout)
{
  "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.

Terminal
# 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
Input (3 variables, 8 data points)
{
  "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
}
Output
{
  "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.

Terminal
# 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
Python
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.

Terminal
# Build WASM (sequential, stable Rust)
bash build_wasm.sh

# Build with Web Worker parallelism (nightly Rust)
bash build_wasm_parallel.sh
JavaScript
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:

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.