> your AI agent picks dependencies from memory; give it dated facts — try starlog.dev ↗ vet your agent's deps ↗ vibe-coding is fine. vibe-importing isn’t. — try starlog.dev ↗ vibe-importing isn’t fine ↗ your agent has never seen your private packages — try starlog.dev ↗ facts for private packages ↗ a linter for the dependencies your AI agent picks — try starlog.dev ↗ a linter for agent deps ↗

Back to Articles

KlongPy: Array Programming with Automatic Differentiation for the Quant-Turned-ML-Engineer

[ View on GitHub ]

KlongPy: Array Programming with Automatic Differentiation for the Quant-Turned-ML-Engineer

Hook

What if you could express a complete gradient descent optimizer in two lines of code instead of ten, using mathematical notation that reads like the equations in your textbook? That's the promise of array languages meeting modern machine learning.

Context

The Python ML ecosystem has a readability problem hiding in plain sight. Implementing gradient descent, backpropagation, or optimization algorithms requires verbose imperative loops that obscure the underlying mathematics. You write for i in range(len(data)): when you're thinking "sum over all elements." You nest conditionals and maintain state when the mathematical operation is a single compact expression.

KlongPy bridges this gap by bringing Klong—an APL-family array language—into Python's ML ecosystem. It's not just another NumPy wrapper; it's a domain-specific language compiler that treats arrays as first-class citizens and automatic differentiation as a primitive operation. The project positions itself at the intersection of three communities: quantitative finance professionals familiar with kdb+/Q, ML researchers who think in mathematical notation, and scientists tired of translating clean equations into messy loops. With support for NumPy, PyTorch (CPU/CUDA/MPS), and integrations for IPC, web servers, and DuckDB, it's architected as "kdb+/Q for the Python ML era"—complete with gradients.

Technical Insight

KlongPy's architecture revolves around an expression compiler that transforms Klong syntax into backend-neutral intermediate representation, then generates platform-specific Python code. This isn't simple syntax sugar—it fundamentally changes how you express computational workflows.

Consider a standard gradient descent implementation in PyTorch. The conventional approach requires explicit parameter updates, gradient zeroing, and backward passes scattered across multiple lines. Here's the KlongPy equivalent:

from klongpy import klong

# Define loss function with automatic differentiation
loss := {((y - (w *' x)) ^ 2) % #y}
w_grad := loss :> w  # Gradient as a first-class operation
w := w - (0.01 * w_grad)  # Parameter update

The :> operator is the key innovation—it's gradient computation as an array primitive. In traditional PyTorch, you'd write loss.backward(), manually track which tensors need gradients, call optimizer.zero_grad(), and update parameters through an optimizer object. KlongPy compresses this to a single operator that returns the gradient as just another array you can manipulate.

The backend abstraction layer reveals non-obvious performance tradeoffs. For a running maximum operation (scan), the PyTorch backend is 362x faster than NumPy because it compiles to native tensor methods rather than falling back to Python interpreter loops. But for simple element-wise operations like addition, NumPy is 2.3x faster (0.066ms vs 0.155ms) due to PyTorch's tensor wrapper overhead. This means backend selection isn't just about "NumPy for CPU, PyTorch for GPU"—it's about operation type.

The expression caching system is particularly clever. KlongPy memoizes the compiled IR and generated Python code, so repeatedly executing the same Klong expression pays the compilation cost only once. For REPL-driven development or iterative algorithm refinement, this transforms the user experience from sluggish to interactive.

Beyond pure computation, KlongPy inherits kdb+/Q's batteries-included philosophy. It includes IPC primitives for inter-process communication, a built-in web server for exposing array computations as HTTP endpoints, and DuckDB integration for columnar storage. This isn't just an array language—it's a data infrastructure toolkit that treats databases and network protocols as language primitives. You can write a complete ML inference server with persistence in a dozen lines of Klong code, something that would require Flask, SQLAlchemy, and extensive glue code in standard Python.

The symbolic differentiation fallback deserves mention. When PyTorch's autograd isn't available or applicable, KlongPy falls back to numeric differentiation. This graceful degradation means you can write gradient-based code without worrying about which backend supports which operations—the system handles it automatically, though at a performance cost.

Gotcha

The elephant in the room is syntax. If you're not familiar with APL-family languages, Klong code looks like line noise. +/ means "sum" (reduce with plus), +\ means "running sum" (scan with plus), and :> means "gradient with respect to." There's no keyword to grep for, no Stack Overflow post to copy-paste. The learning curve is a vertical wall, and your team's onboarding time will reflect that. Code reviews become exercises in deciphering hieroglyphics unless everyone has internalized the operator semantics.

Performance characteristics are counterintuitive and backend-dependent. That 2.3x overhead on simple PyTorch operations means you can't blindly choose PyTorch and expect wins everywhere. If your workload is primarily element-wise math without gradients, NumPy is faster. If you need scans, reductions, or GPU acceleration, PyTorch dominates. Profiling becomes mandatory rather than optional, and the "right" backend might change as your algorithm evolves. The 315-star GitHub count also signals a small community—expect to read source code when documentation falls short, and be prepared for potential abandonment if the maintainer moves on.

Verdict

Use KlongPy if you're building gradient-based optimization systems (portfolio allocation, hyperparameter tuning, custom neural architectures) and your team has APL/Q expertise or mathematical sophistication that values notational density. It shines for interactive exploration where you're translating papers into code and want the implementation to mirror the equations. Quants migrating kdb+/Q knowledge to Python ML will find it immediately productive. Skip it for production ML pipelines serving millions of requests (use PyTorch/JAX directly for ecosystem maturity), teams without array programming experience (the syntax learning curve kills velocity), or simple data processing where NumPy's explicitness is an asset. The 10:1 code compression is compelling only if reading the compressed code is actually faster than reading the expanded version—and for most Python developers, it isn't.