Class LeastSquares

java.lang.Object
org.horizon36596.simloop.fit.LeastSquares

public final class LeastSquares extends Object
Linear least squares, written out: find the x that makes A x as close as possible to b, in the sense of the smallest sum of squared differences. Horizon (FTC 36596) SimLoop.

How. By a QR factorisation built from Householder reflections, rather than by the normal equations (A^T A) x = A^T b. Both give the same answer on well-behaved data; QR stays accurate when two columns of A are nearly alike (a robot that barely changed speed, say), where the normal equations square the problem's sensitivity and can lose half the digits. The method, in three steps:

  1. For each column in turn, a reflection H = I - 2 v v^T / (v^T v) is chosen that zeroes everything below the diagonal in that column. Applying the reflections to A leaves an upper-triangular R; applying the same reflections to b gives Q^T b.
  2. Reflections do not change lengths, so minimising |A x - b| is the same as minimising |R x - Q^T b|. Its first n rows can be made exactly zero.
  3. Back-substitution solves those n triangular rows for x.

How sure. Each column is first scaled to unit length, so the answer does not depend on the columns' units, and the diagonal of the scaled R then gives a LeastSquares.Solution.conditionNumber: how nearly one column is a combination of the others. Near 1, every coefficient is pinned down independently; large, the data cannot tell some coefficients apart and small noise moves them a lot even while the residual stays small. LeastSquares.Solution.standardErrors put a number on that, assuming the rows' errors are independent and equal in size: sqrt(diag(s^2 (R^T R)^-1)), with s^2 = RSS / (rows - columns).

Pure and deterministic (domain R5): no clock, no randomness, and the arithmetic runs in a fixed order, so the same data gives the same bits. No library: the repo takes no new dependency for this.

  • Method Details

    • solve

      public static LeastSquares.Solution solve(double[][] a, double[] b, String... columns)
      Solve min |A x - b|.
      Parameters:
      a - the design matrix, a[row][column]; not modified; at least as many rows as columns
      b - the observations, one per row of a; not modified
      columns - a name for each column, used only to say which one is at fault if the fit is refused
      Returns:
      the solution
      Throws:
      IllegalArgumentException - if the shapes disagree, a value is not finite, there are fewer rows than columns, or a column is (numerically) a combination of the others - the data then cannot tell those parameters apart