Expand description

Least Squares

Compute a least-squares solution to the equation Ax = b. Compute a vector x such that the 2-norm |b - A x| is minimized.

Finding the least squares solutions is implemented as traits, meaning that to solve A x = b for a matrix A and a RHS b, we call let result = A.least_squares(&b);. This returns a result of type LeastSquaresResult, the solution for the least square problem is in result.solution.

There are three traits, LeastSquaresSvd with the method least_squares, which operates on immutable references, LeastSquaresInto with the method least_squares_into, which takes ownership over both the array A and the RHS b and LeastSquaresSvdInPlace with the method least_squares_in_place, which operates on mutable references for A and b and destroys these when solving the least squares problem. LeastSquaresSvdInto and LeastSquaresSvdInPlace avoid an extra allocation for A and b which LeastSquaresSvd has do perform to preserve the values in A and b.

All methods use the Lapacke family of methods *gelsd which solves the least squares problem using the SVD with a divide-and-conquer strategy.

The traits are implemented for value types f32, f64, c32 and c64 and vector or matrix right-hand-sides (ArrayBase<S, Ix1> or ArrayBase<S, Ix2>).

Example

use approx::AbsDiffEq; // for abs_diff_eq
use ndarray::{array, Array1, Array2};
use ndarray_linalg::{LeastSquaresSvd, LeastSquaresSvdInto, LeastSquaresSvdInPlace};

let a: Array2<f64> = array![
    [1., 1., 1.],
    [2., 3., 4.],
    [3., 5., 2.],
    [4., 2., 5.],
    [5., 4., 3.]
];
// solving for a single right-hand side
let b: Array1<f64> = array![-10., 12., 14., 16., 18.];
let expected: Array1<f64> = array![2., 1., 1.];
let result = a.least_squares(&b).unwrap();
assert!(result.solution.abs_diff_eq(&expected, 1e-12));

// solving for two right-hand sides at once
let b_2: Array2<f64> =
    array![[-10., -3.], [12., 14.], [14., 12.], [16., 16.], [18., 16.]];
let expected_2: Array2<f64> = array![[2., 1.], [1., 1.], [1., 2.]];
let result_2 = a.least_squares(&b_2).unwrap();
assert!(result_2.solution.abs_diff_eq(&expected_2, 1e-12));

// using `least_squares_in_place` which overwrites its arguments
let mut a_3 = a.clone();
let mut b_3 = b.clone();
let result_3 = a_3.least_squares_in_place(&mut b_3).unwrap();

// using `least_squares_into` which consumes its arguments
let result_4 = a.least_squares_into(b).unwrap();
// `a` and `b` have been moved, no longer valid

Structs

Result of a LeastSquares computation

Traits

Solve least squares for immutable references

Solve least squares for mutable references, overwriting the input fields in the process

Solve least squares for owned matrices