npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

scalar-autograd

v0.1.9

Published

Scalar-based reverse-mode automatic differentiation in TypeScript.

Downloads

28

Readme

ScalarAutograd for TypeScript

A tiny scalar autograd engine for TypeScript/JavaScript.

Scautograd enables automatic differentiation for scalar operations, similar to what you'd find in PyTorch's autograd, but designed for TypeScript codebases. This makes it useful for building and training small neural networks, performing optimization, or experimenting with gradient-based techniques—entirely in the browser or Node.js.

Features

  • Scalar Value objects for tracking data, gradients, and computation graph.
  • Backpropagation via .backward() to compute gradients automatically.
  • Clean, TypeScript-first API.
  • Does NOT handle matrices or tensors, just scalars.

Installation

Simply copy the files in this folder into your project, or import as a local module if desired.

Basic Usage

import { V } from './V';

// Basic differentiation using static V API
const x = V.W(2.0); // differentiable variable
const y = V.W(3.0);
const z = V.add(V.mul(x, y), V.pow(x, 2)); // z = x*y + x^2
z.backward();
console.log('dz/dx:', x.grad); // Output: dz/dx = y + 2*x = 3 + 2*2 = 7
console.log('dz/dy:', y.grad); // Output: dz/dy = x = 2

Example: Tiny Gradient Descent

const a = V.W(5);
const b = V.W(-3);
const c = V.sin(V.mul(a, b)); // f = sin(a * b)
c.backward();
console.log(a.grad, b.grad); // Gradients w.r.t. a and b

Example: Solving for Parameters via Backpropagation

Here's how you can use Scautograd's backpropagation and a simple optimizer to fit a linear regression model (y = 2x + 3):

import { V } from './V';
import { SGD } from './Optimizers';

// Initialize parameters
let w = V.W(Math.random(), "w");
let b = V.W(Math.random(), "b");

// Example data: y = 2x + 3
const samples = [
  { x: 1, y: 5 },
  { x: 2, y: 7 },
  { x: 3, y: 9 },
];

const opt = new SGD([w, b], { learningRate: 0.1 });

for (let epoch = 0; epoch < 300; ++epoch) {
  let losses = [];
  for (const sample of samples) {
    const x = V.C(sample.x, "x");
    const pred = V.add(V.mul(w, x), b);
    const target = V.C(sample.y, "target");
    const loss = V.pow(V.sub(pred, target), 2);
    losses.push(loss);
  }
  const totalLoss = V.mean(losses);
  opt.zeroGrad();
  totalLoss.backward();
  opt.step();
  if (totalLoss.data < 1e-4) break;
}

console.log('Fitted w:', w.data); // ~2
console.log('Fitted b:', b.data); // ~3

This pattern—forward pass, backward for gradients, and calling optimizer.step()—applies to more complex optimization tasks and neural networks as well!

Example: Nonlinear Least Squares Solver

For problems where you need to minimize the sum of squared residuals, the built-in Levenberg-Marquardt solver is much faster than gradient descent:

import { V } from './V';

// Fit a circle to noisy points
const params = [V.W(0), V.W(0), V.W(5)]; // cx, cy, radius

// Generate noisy circle data
const points = Array.from({ length: 50 }, (_, i) => {
  const angle = (i / 50) * 2 * Math.PI;
  return {
    x: 10 * Math.cos(angle) + (Math.random() - 0.5) * 0.5,
    y: 10 * Math.sin(angle) + (Math.random() - 0.5) * 0.5,
  };
});

const result = V.nonlinearLeastSquares(
  params,
  ([cx, cy, r]) => {
    // Compute residual for each point (distance from circle)
    return points.map(p => {
      const dx = V.sub(p.x, cx);
      const dy = V.sub(p.y, cy);
      const dist = V.sqrt(V.add(V.square(dx), V.square(dy)));
      return V.sub(dist, r);
    });
  },
  {
    maxIterations: 100,
    costTolerance: 1e-6,
    verbose: true,
  }
);

console.log('Circle fitted in', result.iterations, 'iterations');
console.log('Center:', params[0].data, params[1].data);
console.log('Radius:', params[2].data);

The Levenberg-Marquardt algorithm typically converges 100-1000x faster than gradient descent for least squares problems.

Choosing the Right Optimizer

ScalarAutograd provides three categories of optimizers, each suited for different problem types:

1. Gradient Descent Optimizers (SGD, Adam, AdamW)

Best for: Training neural networks, iterative refinement, online learning

const opt = new Adam([w, b], { learningRate: 0.01 });
for (let epoch = 0; epoch < 1000; epoch++) {
  const loss = computeLoss();
  opt.zeroGrad();
  loss.backward();
  opt.step();
}

Pros: Simple, works on any differentiable objective, good for streaming data Cons: Slow convergence, requires tuning learning rate and iterations

2. Levenberg-Marquardt (V.nonlinearLeastSquares)

Best for: Nonlinear least squares: minimizing Σ rᵢ(x)²

const result = V.nonlinearLeastSquares(
  params,
  (p) => points.map(pt => residualFunction(p, pt)), // Returns array of residuals
  { maxIterations: 100 }
);

Use when:

  • Problem is naturally formulated as sum of squared residuals
  • You have overdetermined systems (more equations than unknowns)
  • Examples: curve fitting, calibration, parameter estimation, circle/sphere fitting

Pros: 10-100x faster than gradient descent, exploits Jacobian structure Cons: Only works for least squares problems, requires residual formulation

3. L-BFGS (lbfgs)

Best for: General unconstrained optimization

import { lbfgs } from 'scalar-autograd';

const result = lbfgs(
  params,
  (p) => computeObjective(p), // Returns single Value (the cost)
  { maxIterations: 100 }
);

Use when:

  • Objective has no special structure (not sum-of-squares)
  • High-dimensional problems (100s-1000s of parameters)
  • Memory constrained (stores only ~10 recent gradient pairs)
  • Examples: energy minimization, ML losses, geometric optimization, developable surfaces

Pros: Memory efficient, handles non-quadratic objectives well, faster than gradient descent Cons: Not as fast as LM for least squares, requires smooth objectives

Quick Decision Guide

Can you write your objective as f(x) = Σ rᵢ(x)² ?
├─ YES → Use V.nonlinearLeastSquares() (Levenberg-Marquardt)
│         Fastest for curve fitting, calibration, parameter estimation
│
└─ NO → Is it a general smooth objective?
    ├─ YES → Use lbfgs() for large-scale or L-BFGS for efficiency
    │         Good for energy minimization, geometric optimization
    │
    └─ NO → Use Adam/AdamW for training neural networks
              Good for online learning, streaming data

API Overview

  • Core Value construction:
    • V.C(data, label?) — constant (non-differentiable), e.g. for data/inputs.
    • V.W(data, label?) — weight/parameter (differentiable).
  • Operators:
    • Basic: V.add(a, b), V.sub(a, b), V.mul(a, b), V.div(a, b), V.pow(a, n), V.powValue(a, b).
    • Reductions: V.sum(array), V.mean(array)
    • Trig: V.sin(x), V.cos(x), V.tan(x), ...
    • Activations: V.relu(x), V.tanh(x), V.sigmoid(x), etc.
    • Comparison: V.eq(a, b), V.gt(a, b), ... (outputs constant Values; never has grad)
  • Backward:
    • .backward() — trigger automatic differentiation from this node.
    • .grad — access the computed gradient after backward pass.
  • Optimizers:
    • SGD, Adam, AdamW - E.g. const opt = new SGD([w, b], {learningRate: 0.01})
  • Losses:
    • Losses.mse(), Losses.mae(), Losses.binaryCrossEntropy(), Losses.categoricalCrossEntropy(), Losses.huber(), Losses.tukey()
  • Advanced Optimization:
    • V.nonlinearLeastSquares(params, residualFn, options) — Levenberg-Marquardt solver for nonlinear least squares problems (minimizing Σ rᵢ²)
    • lbfgs(params, objectiveFn, options) — L-BFGS optimizer for general unconstrained optimization
  • Vector utilities:
    • Vec2, Vec3 — Differentiable 2D/3D vectors with dot, cross, normalize operations

All API operations work with both Value and raw number inputs (numbers are automatically wrapped as non-grad constants).

Testing

To run the test suite and verify the correctness of ScalarAutograd, execute the following command in your project directory:

npm run test

Deploy to npm

Start "Git Bash" terminal Type ./release.sh


License

MIT