View Raw SPL
/*****************************************************************************
* *
* SVDDIV.SPL Copyright (C) 1999-2018 DSP Development Corporation *
* All Rights Reserved *
* *
* Author: Randy Race *
* *
* Synopsis: Solves A *^ c = x using singular value decomposition *
* *
* Revisions: 18 Jun 1999 RRR Creation *
* 21 Mar 2000 RRR use input matrix column size *
* 18 Jan 2010 RRR use faster economy SVD mode *
* 26 Sep 2018 RRR "econ" fix *
* *
*****************************************************************************/
#include
#if @HELP_SVDDIV
SVDDIV
Purpose: Solves for c in A *^ c = y using singular value decomposition
Syntax: SVDDIV(A, y, tol)
A - input array, the basis function design matrix
y - input series, the Y output series
tol - optional real, threshold at which to zero out singular
values. If not specified, all singular values are used.
Returns: A series or array
Example:
x = {-1, 1, 1.5, 3};
y = {6, 2, 2.25, 6};
c1 = polyfit(y, x, 2);
c2 = svddiv(ravel(ones(length(x),1), x, x^2), y);
c1 == c2 == {3, -2, 1};
The first method uses POLYFIT to fit a quadratic
polynomial to the data points. As shown, SVDDIV produces
the same result. The fitted equation becomes:
y(x) = 3 -2 * x + x^2
Example:
W1: gnorm(100,.01)
W2: 5*w1 + 3*sin(w1) - 2*w1^3
W3: ravel(w1, sin(w1), w1^3)
W4: svddiv(W3, w2)
W4 == {5, 3, -2}, the coefficients of W2.
In this example, we wish to find the coefficients of the
relation:
y(x) = c1 * x + c2 * sin(x) + c3 * x^3
Notice that although each term is not necessarily linear,
the equation as a whole is a linear combination of terms.
SVDDIV solves the set of simultaneous equations to yield:
c1 == 5
c2 == 3
c3 == -2
Remarks:
For the least squares problem, we wish to find the coefficients
c that minimize:
|A *^c - y|^2
Where A is the design matrix and y is the output vector.
This quantity is minimized to 0 when:
A *^ c = y
SVDDIV solves the set of simultaneous equations as
specified by A and y. Given the matrix equation:
A *^ c = y
SVDDIV calculates:
c = V *^ diag(diag(1/W)) *^ (transpose(U) *^ b)
where
A = U *^ W *^ transpose(V)
as calculated by SVD. By specifying TOL, singular values
less than TOL are eliminated and SVDDIV essentially
calculates a least squares fit. A typical value for TOL
is EPS. See [1] for further details.
See LINFIT for a least squares method that uses faster QR
decomposition, direct normal equations or SVD.
See Also:
*^
LINFIT
QR
SVD
References:
[1] Press, Flannery, Teukolsky, Vetterling
Numerical Recipes in C
2nd Edition
Cambridge Press, 1988, 1992
pp. 676-679
#endif
/* solve A *^ c = y using singular value decomposition */
svddiv(A, y, tol)
{
local m, n, c, u, w, v, sing_edit = TRUE, coefstd;
if (argc < 3)
{
if (argc < 2) error("svddiv - two input matrices required");
sing_edit = FALSE;
}
/* get num rows & columns */
(m, n) = size(A);
/* SVD matrices - use economy sized matrix where u is NxM */
(u, w, v) = svd(A, "econ");
/* get diagonal elements */
w = diag(extract(w, 1, n));
/* convert to diagonal matrix, edit singular values if necessary */
if (sing_edit)
{
/* edit singular values, if w < tol then 1/w = 0 */
w = diag((1 / w) * (w > tol));
}
else
{
/* use inverse of computed singular values */
w = diag(1 / w);
}
/* solve the system */
c = v *^ (w *^ (transposeconj(u) *^ y));
if (outargc > 1)
{
/* return coefficient stdev, note that w already inversed */
coefstd = sqrt(transpose(colsum((transpose(v) * diag(w)) ^ 2)));
return(c, coefstd);
}
else
{
return(c);
}
}