Backporch
Patterns · one idea, four languages
← About

Patterns

A working portfolio of quick syntax and abstract pattern designs. Each card is one algorithm, written idiomatically in Python, C, C++, and C# — the logic is identical, so the tabs isolate exactly one thing: how each language carries state, memory, and abstraction. Built as I take C / C++ / C# from novice toward fluent, one pattern at a time.

Flagship

svm-cpp — a soft-margin SVM in C++

Beyond the snippets: a full, from-scratch support vector machine (SMO) in modern C++ — the port of this site's browser classifier — with pybind11 Python bindings and a scikit-learn benchmark. The core is dependency-free, and every number below is build-and-test verified.

modelaccuracyfitpredict
svmcpp (C++)1.00052.1 ms0.05 ms
scikit-learn1.0001.1 ms0.26 ms

Concentric circles, RBF. Accuracy parity; the honest trade — a teaching SMO trains slower than libsvm, predicts leaner.

C++17 · SMO · pybind11 · CMake · MIT

View the repository →

Welford's online mean & variance

Compute a running mean and variance in a single pass, in O(1) memory — never holding the data. The engine behind the streaming-stats tool: point it at a column of a huge CSV and it never loads the column. Same recurrence in every language; watch how each one carries the state.

from dataclasses import dataclass

@dataclass
class RunningStats:
    """Welford's algorithm — running mean & variance, O(1) memory."""
    n: int = 0
    mean: float = 0.0
    m2: float = 0.0

    def update(self, x: float) -> None:
        self.n += 1
        delta = x - self.mean
        self.mean += delta / self.n
        self.m2 += delta * (x - self.mean)   # uses the *new* mean

    @property
    def variance(self) -> float:
        return self.m2 / self.n if self.n else float("nan")

# stream a column without ever loading it into memory
stats = RunningStats()
for x in read_column("changeovers.csv", "duration_min"):
    stats.update(x)
print(stats.mean, stats.variance)

A dataclass holds the state; a @property computes variance on demand. Readable and terse — at the cost of every number being a boxed float object.

The perceptron — a single neuron that learns

A single neuron: it weights its inputs, adds a bias, and fires (1) or stays quiet (0). The perceptron learning rule nudges the weights toward the right answer one labeled example at a time — the seed of every neural network. Same predict-and-update in every language; watch how each one holds the weight vector and threads it through predict and train_step.

from dataclasses import dataclass

@dataclass
class Perceptron:
    """A single neuron: y = step(w . x + b), trained by the perceptron rule."""
    weights: list[float]
    bias: float = 0.0
    lr: float = 0.1

    def predict(self, x: list[float]) -> int:
        z = self.bias + sum(w * xi for w, xi in zip(self.weights, x))
        return 1 if z > 0 else 0

    def train_step(self, x: list[float], target: int) -> None:
        error = target - self.predict(x)          # -1, 0, or +1
        for i, xi in enumerate(x):
            self.weights[i] += self.lr * error * xi
        self.bias += self.lr * error

# learn the logical AND of two inputs
p = Perceptron(weights=[0.0, 0.0])
data = [([0, 0], 0), ([0, 1], 0), ([1, 0], 0), ([1, 1], 1)]
for _ in range(10):
    for x, target in data:
        p.train_step(x, target)
print([p.predict(x) for x, _ in data])

A dataclass carries the mutable weight vector and bias while a comprehension does the dot product — terse and dynamically typed, at the cost of every number being a boxed Python float.

A tiny neural network — one hidden layer, forward pass

The forward pass of the smallest thing that is honestly a neural net: 3 inputs feed a 4-unit hidden layer through ReLU, then a single sigmoid output — a matrix-vector product and a nonlinearity, done twice. It is the exact kernel every deep-learning framework scales up to billions of parameters. Same arithmetic in every language; watch how each one stores the weight matrices and threads them through the loops.

from dataclasses import dataclass
from math import exp

def relu(z: float) -> float:
    return z if z > 0.0 else 0.0

def sigmoid(z: float) -> float:
    return 1.0 / (1.0 + exp(-z))

@dataclass
class MLP:
    """One hidden layer: 3 inputs -> 4 relu units -> 1 sigmoid output."""
    w1: list[list[float]]   # 4 x 3 hidden weights
    b1: list[float]         # 4 hidden biases
    w2: list[float]         # 4 output weights
    b2: float

    def forward(self, x: list[float]) -> float:
        h = [relu(sum(w * xi for w, xi in zip(row, x)) + b)
             for row, b in zip(self.w1, self.b1)]
        return sigmoid(sum(w * hj for w, hj in zip(self.w2, h)) + self.b2)

# load trained weights and score one feature vector
net = MLP(*load_weights("mlp.npz"))
print(net.forward([0.4, -1.2, 0.8]))

A dataclass carries the weight matrices as nested lists, and comprehensions with zip make each layer read like its own summation — at the cost of boxing every float into a Python object.

A transform pipeline — passing behavior around

A preprocessing pipeline: an ordered list of double->double steps (center, scale, clip01) threaded through a value, one after another. The interesting part is not the arithmetic — it is that behavior itself becomes data you can store, reorder, and pass around. Watch how each language makes a function first-class: a list of callables, an array of function pointers, a vector of std::function, an array of Func<> folded with LINQ.

from dataclasses import dataclass, field
from functools import reduce
from typing import Callable

Step = Callable[[float], float]

def center(x: float) -> float: return x - 50.0
def scale(x: float)  -> float: return x / 20.0
def clip01(x: float) -> float: return min(1.0, max(0.0, x))

@dataclass
class Pipeline:
    """An ordered list of double->double steps; behavior stored as data."""
    steps: list[Step] = field(default_factory=list)

    def run(self, x: float) -> float:
        # thread x through every step, left to right
        return reduce(lambda acc, f: f(acc), self.steps, x)

# functions are first-class: pass them around, stash them in a list
pipe = Pipeline([center, scale, clip01])
for x in read_column("changeovers.csv", "duration_min"):
    print(pipe.run(x))

Functions are ordinary objects, so the pipeline is just a list you build and reduce over — behavior and data are the same kind of thing.

Sparklines — a chart with no library

Turn a row of numbers into a tiny inline bar chart — eight Unicode block glyphs, no plotting library, no image, just a string you can drop into a log line or a terminal. Scan for the range, scale each value into one of eight levels, look up the glyph, and join. Watch how each language builds that string: Python and C# index straight into one glyph string, while C and C++ concatenate an array of UTF-8 block strings a few bytes at a time.

from typing import Sequence

BLOCKS = "▁▂▃▄▅▆▇█"   # eight levels: lower one-eighth block .. full block

def sparkline(values: Sequence[float]) -> str:
    """Render a row of numbers as a no-library bar chart."""
    lo, hi = min(values), max(values)          # one scan for the range
    span = (hi - lo) or 1.0                     # all-equal -> flat, no /0
    top = len(BLOCKS) - 1                        # 7
    glyphs = []
    for v in values:
        idx = round((v - lo) / span * top)      # scale into 0..7
        glyphs.append(BLOCKS[idx])              # index straight into the string
    return "".join(glyphs)

# glance at a column's shape without importing a plotting library
print(sparkline(read_column("changeovers.csv", "duration_min")))
print(sparkline([3, 9, 5, 1, 7, 8, 2]))         # -> ▃█▅▁▆▇▂

A pure function over a Sequence; string indexing turns glyph lookup into a one-liner and ''.join builds the result without ever handling a raw byte.