Main Content

fixed.svd

Fixed-point singular value decomposition

Description

example

S = fixed.svd(A) returns the singular values of matrix A in descending order.

example

[U,S,V] = fixed.svd(A) performs a singular value decomposition of matrix A such that A = U*S*V'. S is a diagonal matrix of the same dimension as A with nonnegative diagonal elements in decreasing order. U and V are unitary matrices.

example

[U,S,V] = fixed.svd(A,0) produces an economy-size decomposition of A. If A is an m-by-n matrix, then:

  • m > n — Only the first n columns of U are computed, and S is n-by-n.

  • m <= nfixed.svd(A,0) is equivalent to fixed.svd(A).

example

[U,S,V] = fixed.svd(A,'econ') produces a different economy-size decomposition of A. If A is an m-by-n matrix, then:

  • m >= nfixed.svd(A,'econ') is equivalent to fixed.svd(A,0).

  • m < n — Only the first m columns of V are computed, and S is m-by-m.

example

[___] = fixed.svd(___,sigmaForm) optionally specifies the output format for the singular values. You can use this option with any of the previous input or output combinations. Specify 'vector' to return the singular values as a column vector. Specify 'matrix' to return the singular values in a diagonal matrix.

Examples

collapse all

Compute the singular values of a full rank scaled-double matrix.

A = [1 0 1; -1 -2 0; 0 1 -1];

Define fixed-point types that will never overflow. First, use the fixed.singularValueUpperBound function to determine the upper bound on the singular values. Then define the integer length based on the value of the upper bound, with one additional bit for the sign and another additional bit for intermediate CORDIC growth. Compute the fraction length based on the integer length and the desired word length.

svdUpperBound = fixed.singularValueUpperBound(3,3,max(abs(A(:))))
integerLength = ceil(log2(svdUpperBound)) + 2
wordLength = 16
fractionLength = wordLength - integerLength

Cast the matrix A to the scaled-double type.

T.A = fi([],1,wordLength,fractionLength,'DataType','ScaledDouble');
A = cast(A,'like',T.A)
A = 

     1     0     1
    -1    -2     0
     0     1    -1


          DataTypeMode: Scaled double: binary point scaling
            Signedness: Signed
            WordLength: 16
        FractionLength: 11

Compute the singular values.

s = fixed.svd(A)
s = 

    2.4605
    1.6996
    0.2391


          DataTypeMode: Scaled double: binary point scaling
            Signedness: Signed
            WordLength: 16
        FractionLength: 11

The singular values are returned in a column vector in decreasing order, and have the same data type as A.

Find the singular value decomposition of the rectangular fixed-point matrix A.

Define the rectangular matrix A.

m = 4;
n = 2;
A = 10*randn(m,n);

Define fixed-point types that will never overflow. First, use the fixed.singularValueUpperBound function to determine the upper bound on the singular values. Then define the integer length based on the value of the upper bound, with one additional bit for the sign and another additional bit for intermediate CORDIC growth. Compute the fraction length based on the integer length and the desired word length.

svdUpperBound = fixed.singularValueUpperBound(m,n,max(abs(A(:))));
integerLength = ceil(log2(svdUpperBound)) + 2;
wordLength = 32;
fractionLength = wordLength - integerLength;

Cast the matrix A to the signed fixed-point type.

T.A = fi([],1,wordLength,fractionLength,'DataType','Fixed');
A = cast(A,'like',T.A)
A = 

   15.4421  -10.6158
    0.8593   23.5046
  -14.9159   -6.1560
   -7.4230    7.4808

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 23

Find the singular value decomposition of the fixed-point matrix A.

[U,S,V] = fixed.svd(A)
U = 

    0.5447   -0.4890    0.6086    0.3061
   -0.7662   -0.4192    0.4466   -0.1942
    0.0163    0.7393    0.6558   -0.1519
   -0.3405    0.1964         0    0.9195

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 30

S = 

   28.2808         0
         0   21.8173
         0         0
         0         0

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 23

V = 

    0.3549   -0.9349
   -0.9349   -0.3549

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 30

Confirm the relation A = U*S*V'.

U*S*V'
ans = 

   15.4421  -10.6158
    0.8593   23.5046
  -14.9159   -6.1560
   -7.4230    7.4808

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 99
        FractionLength: 83

Calculate the complete and economy-size decomposition of a rectangular fixed-point matrix.

Define the matrix A.

A = [1 2; 3 4; 5 6; 7 8];

Define fixed-point types that will never overflow. First, use the fixed.singularValueUpperBound function to determine the upper bound on the singular values. Then define the integer length based on the value of the upper bound, with one additional bit for the sign and another additional bit for intermediate CORDIC growth. Compute the fraction length based on the integer length and the desired word length.

svdUpperBound = fixed.singularValueUpperBound(4,2,max(abs(A(:))));
integerLength = ceil(log2(svdUpperBound)) + 2;
wordLength = 32;
fractionLength = wordLength - integerLength;

Cast the matrix A to the signed fixed-point type.

T.A = fi([],1,wordLength,fractionLength,'DataType','Fixed');
A = cast(A,'like',T.A)
A = 

     1     2
     3     4
     5     6
     7     8

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 25

Compute the complete decomposition.

[U,S,V] = fixed.svd(A)
U = 

   -0.1525    0.8226   -0.4082    0.3651
   -0.3499    0.4214    0.8165   -0.1826
   -0.5474    0.0201   -0.4082   -0.7303
   -0.7448   -0.3812         0    0.5477

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 30

S = 

   14.2691         0
         0    0.6268
         0         0
         0         0

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 25

V = 

   -0.6414   -0.7672
   -0.7672    0.6414

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 30

Compute the economy-size decomposition.

[U,S,V] = fixed.svd(A,'econ')
U = 

   -0.1525    0.8226
   -0.3499    0.4214
   -0.5474    0.0201
   -0.7448   -0.3812

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 30

S = 

   14.2691         0
         0    0.6268

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 25

V = 

   -0.6414   -0.7672
   -0.7672    0.6414

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 30

Since A is 4-by-2, fixed.svd(A,'econ') returns fewer columns in U and fewer rows in S compared to a complete decomposition. Extra rows of zeros in S are excluded, along with the corresponding columns in U that would multiply with those zeros in the expression A = U*S*V'.

Create a 3-by-3 magic square matrix and calculate the singular value decomposition. By default, the fixed.svd function returns the singular values in a diagonal matrix when you specify multiple outputs.

Define the matrix A.

m = 3; n = m;
A = magic(m);

Define fixed-point types that will never overflow. First, use the fixed.singularValueUpperBound function to determine the upper bound on the singular values. Then define the integer length based on the value of the upper bound, with one additional bit for the sign and another additional bit for intermediate CORDIC growth. Compute the fraction length based on the integer length and the desired word length.

svdUpperBound = fixed.singularValueUpperBound(m,n,max(abs(A(:))));
integerLength = ceil(log2(svdUpperBound)) + 2;
wordLength = 32;
fractionLength = wordLength - integerLength;

Cast the matrix A to the signed fixed-point type.

T.A = fi([],1,wordLength,fractionLength,'DataType','Fixed');
A = cast(A,'like',T.A)
A = 

     8     1     6
     3     5     7
     4     9     2

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 25

Compute the singular value decomposition.

[U,S,V] = fixed.svd(A)
U = 

    0.5774    0.7071    0.4082
    0.5774   -0.0000   -0.8165
    0.5774   -0.7071    0.4082

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 30

S = 

   15.0000         0         0
         0    6.9282         0
         0         0    3.4641

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 25

V = 

    0.5774    0.4082    0.7071
    0.5774   -0.8165    0.0000
    0.5774    0.4082   -0.7071

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 30

Specify the 'vector' option to return the singular values in a column vector.

[U,S,V] = fixed.svd(A,'vector')
U = 

    0.5774    0.7071    0.4082
    0.5774   -0.0000   -0.8165
    0.5774   -0.7071    0.4082

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 30

S = 

   15.0000
    6.9282
    3.4641

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 25

V = 

    0.5774    0.4082    0.7071
    0.5774   -0.8165    0.0000
    0.5774    0.4082   -0.7071

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 30

If you specify one output argument, such as S = fixed.svd(A), then fixed.svd switches behavior to return the singular values in a column vector by default. In that case, you can specify the 'matrix' option to return the singular values as a diagonal matrix.

Compute the fixed-point singular value decomposition, verify the results, and generate purely-integer C code.

Define the input matrix A.

rng('default');
m = 10; n = 4;
A = 10*randn(m,n);

The fixed.svd function also accepts complex inputs.

A = 10*complex(rand(m,n),rand(m,n));

Define fixed-point types that will never overflow. Use the fixed.singularValueUpperBound function to determine the upper bound on the singular values. Define the integer length based on the value of the upper bound, with one additional bit for the sign and another additional bit for intermediate CORDIC growth. Compute the fraction length based on the integer length and the desired word length.

svdUpperBound = fixed.singularValueUpperBound(m,n,max(abs(A(:))));
integerLength = ceil(log2(svdUpperBound)) + 2;
wordLength = 32;
fractionLength = wordLength - integerLength;

Specify the desired data type for the input matrix A.

dataType = 'Fixed';
T.A = fi([],1,wordLength,fractionLength,'DataType',dataType);
disp(T.A)
T = 

  struct with fields:

    A: [0×0 embedded.fi]

[]

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 22

Cast the matrix A to the signed fixed-point type.

A = cast(A,'like',T.A);

Generate a MATLAB® executable (MEX) file for execution speed. Use the 'econ' flag to compute the economy-size singular-value decomposition. Use the 'vector' flag to return the singular values as a vector, s. The flags must be constant for code generation. Use the -nargout 3 flag to indicate to the codegen function that it is to generate code for the three-output syntax.

codegen +fixed/svd -o fixedSVD -args {A,coder.Constant('econ'),coder.Constant('vector')} -nargout 3
Code generation successful.

Run the MEX file.

[U,s,V] = fixedSVD(A,'econ','vector')
U = 

   -0.1125   -0.2967   -0.3376    0.0734
    0.5462    0.1609    0.4313   -0.1777
   -0.1650    0.4846    0.1004   -0.4510
    0.0834    0.0250   -0.6150   -0.3866
    0.2233    0.5125   -0.4713   -0.0149
   -0.2651   -0.1176    0.1186   -0.5239
   -0.0964   -0.0185   -0.0812   -0.2699
    0.2060    0.1754    0.1886   -0.1957
    0.4435   -0.5827   -0.0487   -0.4123
    0.5350    0.0589   -0.1759    0.2331

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 30

s = 

   66.4423
   46.0313
   28.0940
   22.4663

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 22

V = 

    0.7503   -0.5375   -0.3611    0.1334
    0.5419    0.2510    0.5298   -0.6022
   -0.1966   -0.0349   -0.6328   -0.7481
   -0.3238   -0.8043    0.4341   -0.2446

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 30

Verify the singular values. Since singular values are unique, you can use the svd function to verify that fixed.svd gives a comparable result within the precision of the selected fixed-point type.

sExpected = svd(double(A))
singularValueRelativeError = norm(double(s)-double(sExpected))/norm(double(sExpected))
sExpected =

   66.4423
   46.0313
   28.0939
   22.4663


singularValueRelativeError =

   6.6157e-07

Singular vectors are not unique. You can verify the singular vectors by confirming that A ≈ U*S*V' and that the singular vector matrices are orthonormal.

First, expand the singular value vector s into matrix S.

S = zeros(size(U,2),size(V,2),'like',s);
for i = 1:min(m,n)
    S(i,i) = s(i);
end

S
S = 

   66.4423         0         0         0
         0   46.0313         0         0
         0         0   28.0940         0
         0         0         0   22.4663

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 22

Verify that U*S*V' is approximately equal to A.

decompositionRelativeError = norm(double(U*S*V')-double(A))/norm(double(A))
decompositionRelativeError =

   9.8773e-07

U and V are orthonormal. Verify that U'U and V'V are approximately equal to the identity matrix.

UtransposeU = double(U'*U)
VtransposeV = double(V'*V)
UtransposeU =

    1.0000   -0.0000   -0.0000   -0.0000
   -0.0000    1.0000    0.0000    0.0000
   -0.0000    0.0000    1.0000   -0.0000
   -0.0000    0.0000   -0.0000    1.0000


VtransposeV =

    1.0000   -0.0000    0.0000   -0.0000
   -0.0000    1.0000   -0.0000   -0.0000
    0.0000   -0.0000    1.0000   -0.0000
   -0.0000   -0.0000   -0.0000    1.0000

Generate C code. If the input is fixed point, you can verify that the generated C code consists only of integer types.

cfg = coder.config('lib');

if isfi(A) && isfixed(A)
    cfg.PurelyIntegerCode = true;
end

codegen +fixed/svd -args {A, coder.Constant('econ'), coder.Constant('vector')} -config cfg -nargout 3 -launchreport
Code generation successful: View report

The MATLAB code for fixed.svd does not appear in the code generation report because fixed.svd is a MATLAB toolbox function.

Input Arguments

collapse all

Input matrix, specified as a matrix. A can be a signed fixed-point fi, a signed scaled double fi, double, or single data type.

Data Types: single | double | fi
Complex Number Support: Yes

Output format of singular values, specified as one of these values:

  • 'vector'S is a column vector. This behavior is the default when you specify one output, S = fixed.svd(A).

  • 'matrix'S is a diagonal matrix. This behavior is the default when you specify multiple outputs, [U,S,V] = fixed.svd(A).

Example: [U,S,V] = fixed.svd(X,'vector') returns S as a column vector instead of a diagonal matrix.

Example: S = fixed.svd(X,'matrix') returns S as a diagonal matrix instead of a column vector.

Data Types: char | string

Output Arguments

collapse all

Left singular vectors, returned as the columns of a matrix.

For fixed-point and scaled-double inputs, U is returned as a signed fixed-point or scaled-double fi with the same word length as A and fraction length equal to two less than the word length. One of these integer bits is used for the sign. The other integer bit allows +1 to be represented exactly.

For floating-point input, U has the same data type as A.

Singular values, returned as a diagonal matrix or column vector. The singular values are nonnegative and returned in decreasing order. The singular values S have the same data type as A.

Right singular vectors, returned as the columns of a matrix.

For fixed-point input and scaled-double inputs, V is returned as a signed fixed-point or scaled-double fi with the same word length as A and fraction length equal to two less than the word length. One of these integer bits is used for the sign. The other integer bit allows +1 to be represented exactly.

For floating-point input, V has the same data type as A. One of these integer bits is used for the sign, and the other integer bit is so that +1 can be represented exactly.

Tips

The fixed.svd function allows full control over the fixed-point types. fixed.svd computes in-place in the same data type as the input, which may overflow but will produce efficient code. The svd function adjusts the data type of a fixed-point input to avoid overflow and increase precision.

Extended Capabilities

Version History

Introduced in R2022b

See Also

|