README.md

June 24, 2026 · View on GitHub

 ███████╗████████╗██████╗ ██╗   ██╗██╗  ██╗███████╗
 ██╔════╝╚══██╔══╝██╔══██╗╚██╗ ██╔╝██║ ██╔╝██╔════╝
 ███████╗   ██║   ██████╔╝ ╚████╔╝ █████╔╝ █████╗
 ╚════██║   ██║   ██╔══██╗  ╚██╔╝  ██╔═██╗ ██╔══╝
 ███████║   ██║   ██║  ██║   ██║   ██║  ██╗███████╗
 ╚══════╝   ╚═╝   ╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝╚══════╝
                  [ p o l a r s ]

CI License: MIT stryke

[POLARS + NDARRAY + LINALG + FFT + RANDOM // STRYKE PACKAGE]

"The full pandas + numpy surface in one cdylib. No core bloat."

pandas DataFrame + Series + Index + IO, numpy ndarray + ufuncs + linalg + random + fft + polynomial + masked arrays + datetime64 — all in a single cdylib, dlopened in-process by stryke via use Polars. Opt-in package, kept out of the stryke core binary so the daily-driver install stays slim. Created by MenkeTechnologies.

strykelang · MenkeTechnologiesMeta · stryke-arrow · stryke-duckdb · stryke-parquet

Read the Docs · Engineering Report


Table of Contents


[0x00] Why a Package, Not a Builtin

stryke's core stays small on purpose — most one-liner / awk-replacement work doesn't need 200 transitive crates of pandas + numpy machinery. The full DataFrame + ndarray + linalg + FFT surface hits a different scale:

TierPropertiesThis package
Core builtins (~40 MB stryke)small deps, used everywherestring, math, regex, parallel ops, scipy-class math
Package tier (opt-in)heavy deps, narrow use casesparquet, arrow, big-ML, cloud SDKs, full pandas + numpy

stryke-polars ships as a local stryke package + a Rust cdylib (libstryke_polars.{dylib,so}) loaded on demand. The stryke side is a thin JSON-pipe wrapper; the heavy polars/ndarray/nalgebra/rustfft code lives in the cdylib and is loaded on first use Polars. Core stryke is never linked against any of them.

[0x01] Install

From source (development):

git clone https://github.com/MenkeTechnologies/stryke-polars
cd stryke-polars
make install        # cargo build --release && s pkg install -g .

From a published GitHub release:

s pkg install -g github:MenkeTechnologies/stryke-polars

[0x02] Quick Start

use Polars

val $v = Polars::version()
p "stryke-polars $v->{version} (polars $v->{polars}, ndarray $v->{ndarray})"

Working DataFrame / groupby examples live in examples/ (discover.stk, groupby.stk); the full per-family surface is exercised by the suites in t/.

[0x03] Surface

46 wrapper modules in lib/, 1,505 stryke-side fns total (grep -c '^fn ' lib/*.stk), each calling a polars__* cdylib export:

ModulePackageFns
Series.stkPolars::Series206
NdArray.stkPolars::NdArray124
DataFrame.stkPolars::DataFrame122
Ufunc.stkPolars::Ufunc70
Index.stkPolars::Index69
NdArrayExt.stkPolars::NdArrayExt68
UfuncExt.stkPolars::UfuncExt66
Masked.stkPolars::Masked61
DataFrameExt.stkPolars::DataFrameExt47
DateTime64.stkPolars::DateTime6442
Image.stkPolars::Image42
Categorical.stkPolars::Categorical35
Dist.stkPolars::Dist35
Signal.stkPolars::Signal35
Bit.stkPolars::Bit31
IO.stkPolars::IO29
Text.stkPolars::Text27
Stat.stkPolars::Stat24
Stattest.stkPolars::Stattest24
Misc.stkPolars::Misc23
Metric.stkPolars::Metric23
GroupBy.stkPolars::GroupBy21
Random.stkPolars::Random20
RandomExt.stkPolars::RandomExt20
Linalg.stkPolars::Linalg19
LinalgExt.stkPolars::LinalgExt18
Window.stkPolars::Window17
Fmt.stkPolars::Fmt18
Json.stkPolars::Json14
Graph.stkPolars::Graph13
TS.stkPolars::TS13
Geo.stkPolars::Geo12
Bool.stkPolars::Bool11
Sparse.stkPolars::Sparse15
PolynomialExt.stkPolars::PolynomialExt10
Set.stkPolars::Set10
FFT.stkPolars::FFT8
Encoding.stkPolars::Encoding8
Polynomial.stkPolars::Polynomial7
Interp.stkPolars::Interp6
Checksum.stkPolars::Checksum7
Cluster.stkPolars::Cluster5
FFTExt.stkPolars::FFTExt5
Hash.stkPolars::Hash18
Opt.stkPolars::Opt5
Polars.stkPolars (root: version, _decode)2

[0x04] API Reference

Per-family .stk wrappers live in lib/ — one module per family, listed with fn counts in [0x03]. Per-fn docs live inline as ## doc comments above each wrapper fn.

[0x05] FFI Layer

Each polars__* export takes a single *const c_char (NUL-terminated JSON args) and returns a *mut c_char (NUL-terminated JSON result). The cdylib owns the returned allocation; the stryke side must release it via the cdylib-exported stryke_free_cstring. stryke's rust_ffi::load_cdylib wires this automatically.

JSON envelope on success is the per-fn shape (see [0x04]). JSON envelope on error is {"error": "<message>"}. Panics inside the cdylib are caught and surfaced as errors.

[0x06] Backing Crates

SubsystemBacking crate(s)
DataFrame / Series / Index / pandas IOpolars (full feature set)
ndarray + ufuncsndarray + rayon
linalgnalgebra
randomrand + rand_distr + ndarray-rand + rand_chacha
fftrustfft + realfft
polynomialhand-rolled on ndarray (recurrence formulas)
masked arraysndarray (mask vec parallel to data)
datetime64 / timedelta64chrono + chrono-tz
Decimal dtyperust_decimal

Parquet / Arrow IO routes through stryke-arrow to share a single arrow-rs link in-process — stryke-polars does not link arrow-rs directly to avoid dlsym conflicts.

[0x07] Naming Convention

Stryke-side wrappers are namespaced packages — use Polars::DataFrame gives Polars::DataFrame::head, use Polars::Linalg gives Polars::Linalg::*, etc. (one package per lib/*.stk module).

cdylib-side FFI symbols are flat, prefixed polars__ (double-underscore namespace) plus a per-family verb prefix: polars__df_<verb> for DataFrame, polars__sr_<verb> for Series, polars__arr_<verb> for ndarray, polars__np_<verb> for ufuncs, polars__linalg_<verb> / polars__rand_<verb> / polars__fft_<verb> / polars__poly_<verb> / polars__ma_<verb> / polars__dt64_<verb> for the namespaced families, polars__pd_read_<fmt> / polars__pd_to_<fmt> for IO.

[0x08] Phases

The surface landed in numbered phases (each phase one git commit / one CI green / one release tag). The original P0–P5 plan — scaffold, DataFrame, Series + Index + IO, groupby / accessors / Categorical, ndarray + ufuncs, then linalg / random / fft / polynomial / masked / datetime64 — has shipped, and the surface has since expanded well past it (image, signal, distributions, stat tests, text, graph, geo, sparse, and more — see the module table in [0x03]).

[0x09] Tests

  • cargo test — Rust-side unit tests per src/*.rs (each phase adds its own).
  • s test t/ — stryke-side integration tests against the installed cdylib.
  • tests/*.sh — contract gates (final newline, badges, https links, h2 sections, shell-shebang, etc.) wired into CI.

Per-fn correctness is gated by reference checks against pandas/numpy where possible (numerical tolerance for floats, exact match for ints/bools/strings).

[0x0A] Dev Workflow

make release        # cargo build --release (default target)
make test           # cargo test + stryke t/
make install        # release + s pkg install -g .
cargo fmt --all     # required before every push (CI gate)
cargo clippy --all-targets --locked -- -D warnings

[0x0B] Layout

stryke-polars/
├── Cargo.toml              # crate-type=cdylib, deps
├── stryke.toml             # package meta + FFI exports + scripts
├── src/
│   ├── lib.rs              # FFI plumbing + version export
│   ├── df.rs               # DataFrame + .str/.dt accessors
│   ├── sr.rs / more_sr.rs  # Series
│   ├── idx.rs              # Index
│   ├── io.rs               # pandas IO
│   ├── cat.rs              # Categorical
│   ├── nd.rs / more_nd.rs  # ndarray, ufuncs, linalg, random, fft, polynomial
│   ├── ma.rs               # masked arrays
│   ├── dt64.rs             # datetime64 / timedelta64
│   ├── img.rs              # image ops
│   ├── signal.rs           # signal processing + windows
│   ├── stattest.rs         # stat tests, distributions, interpolation
│   └── extras{,2,3,4}.rs   # groupby, stat, set, bool, cluster, geo, graph, text, json, … expansion families
├── lib/                    # 46 stryke-side .stk wrapper modules (see [0x03])
├── tests/                  # contract gates (shell)
├── t/                      # stryke integration tests
├── examples/
├── docs/                   # GitHub Pages content
├── .github/workflows/
│   ├── ci.yml
│   └── release.yml
├── Makefile
├── LICENSE
└── README.md

[0xFF] License

MIT. See LICENSE.