a project by Yinka Vaughan

qforge

A neural network framework written from scratch in ~2,000 lines of C99. Zero dependencies — no BLAS, no PyTorch, just raw matrix math, backprop, and an SGD optimizer built by hand. Two finance applications on top: a reinforcement-learning trading agent that beats buy-and-hold, and a synthetic market data generator that preserves the statistical signatures of real returns.

Watch it run

Recorded terminal sessions. They autoplay when this section scrolls into view and loop. Click any demo to switch; the playback controls let you scrub or pause.

What am I looking at?
  • DQN trader — A 6-feature → 64 → 32 → 3 Q-network trains for 300 episodes on a simulated price series with regime changes. Buys, sells, and holds based on price, position, P&L, volatility, and lagged returns. Compares final policy to a buy-and-hold baseline.
  • Market generator — A 5 → 32 → 16 → 1 MLP trains on GARCH(1,1)-simulated S&P 500 daily returns, then generates a new return series. The table compares stylized facts: fat tails, volatility clustering, and negative skewness all survive.
  • Benchmarks — Wall-clock timing of matmul, transpose, element-wise ops, and full forward+backward+SGD training steps across multiple sizes.
  • XOR — Classic 2 → 4 → 1 MLP convergence test. Trains to < 0.01 MSE in well under a second.

Run it yourself

The exact same C code, compiled to WebAssembly with Emscripten and executed in a Web Worker. No server — all computation happens locally in your browser.

tweak hyperparameters — defaults match the recorded demos

XOR

DQN trader

The other demos run with fixed defaults — their parameters aren't tunable yet.

↑ Pick a demo. Output is read-only — scroll with your mouse wheel over the terminal, or hit stop to kill a running demo.

How it works

 Tensor       →  matrix algebra (multiply, transpose, add, hadamard)
   ↓
 Activation   →  ReLU, Sigmoid, Tanh, Softmax (+ derivatives)
   ↓
 Loss         →  MSE, Cross-Entropy (+ derivatives, ε-clamped)
   ↓
 Layer        →  Dense layer: forward + backward, Xavier/He init
   ↓
 Network      →  Sequential model — stack layers, train, predict
   ↓
 Optimizer    →  SGD with momentum (per-layer velocity buffers)

Correctness

Every layer is test-driven. Backpropagation is independently verified against central finite differences (dL/dw ≈ [L(w+ε) − L(w−ε)] / 2ε) — max relative error ≤ 2.3 × 10⁻⁷ across four architectures.

Numerical stability

Sigmoid branches on sign of input. Softmax subtracts row-max before exp(). Cross-entropy clamps predictions to [ε, 1−ε]. Weights init via Xavier or He, auto-selected by activation type.

Memory safety

Every tensor op returns a freshly allocated tensor; ownership is explicit. Verified leak-free with AddressSanitizer on the full test suite plus all example binaries.

Performance

Plain C with -O2, no SIMD intrinsics or BLAS. 64×64 matmul: 0.22 ms (2.4 GFLOP/s). A full forward + backward + SGD step on a 16→32→1 net: 0.011 ms.

The code

Six modules, ~2,000 lines, built bottom-up TDD over 14 commits. Every function has a test before it has an implementation.

qforge/
├── include/                    # public headers
│   ├── tensor.h                  matrix math
│   ├── activation.h              ReLU, Sigmoid, Tanh, Softmax
│   ├── loss.h                    MSE, Cross-Entropy
│   ├── layer.h                   dense layer (forward + backward)
│   ├── network.h                 sequential model
│   └── optimizer.h               SGD + momentum
├── src/                        # implementations (one .c per header)
├── tests/                      # 51 unit tests
│   └── test_harness.h            zero-dependency test framework
├── examples/
│   ├── xor.c                     classic AI proof-of-concept
│   ├── benchmark.c               performance measurement
│   ├── gradient_check.c          finite-difference verification
│   ├── market_generator.c        synthetic market data
│   └── dqn_trader.c              reinforcement-learning trader
└── web/                        # this page (asciinema + WASM build)

Read the source on GitHub →