svd.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include "CmplxSVD.h"
00028 #include "dbleSVD.h"
00029 #include "fCmplxSVD.h"
00030 #include "floatSVD.h"
00031 
00032 #include "defun-dld.h"
00033 #include "error.h"
00034 #include "gripes.h"
00035 #include "oct-obj.h"
00036 #include "pr-output.h"
00037 #include "utils.h"
00038 #include "variables.h"
00039 
00040 static int Vsvd_driver = SVD::GESVD;
00041 
00042 DEFUN_DLD (svd, args, nargout,
00043   "-*- texinfo -*-\n\
00044 @deftypefn  {Loadable Function} {@var{s} =} svd (@var{A})\n\
00045 @deftypefnx {Loadable Function} {[@var{U}, @var{S}, @var{V}] =} svd (@var{A})\n\
00046 @deftypefnx {Loadable Function} {[@var{U}, @var{S}, @var{V}] =} svd (@var{A}, @var{econ})\n\
00047 @cindex singular value decomposition\n\
00048 Compute the singular value decomposition of @var{A}\n\
00049 @tex\n\
00050 $$\n\
00051  A = U S V^{\\dagger}\n\
00052 $$\n\
00053 @end tex\n\
00054 @ifnottex\n\
00055 \n\
00056 @example\n\
00057 A = U*S*V'\n\
00058 @end example\n\
00059 \n\
00060 @end ifnottex\n\
00061 \n\
00062 The function @code{svd} normally returns only the vector of singular values.\n\
00063 When called with three return values, it computes\n\
00064 @tex\n\
00065 $U$, $S$, and $V$.\n\
00066 @end tex\n\
00067 @ifnottex\n\
00068 @var{U}, @var{S}, and @var{V}.\n\
00069 @end ifnottex\n\
00070 For example,\n\
00071 \n\
00072 @example\n\
00073 svd (hilb (3))\n\
00074 @end example\n\
00075 \n\
00076 @noindent\n\
00077 returns\n\
00078 \n\
00079 @example\n\
00080 @group\n\
00081 ans =\n\
00082 \n\
00083   1.4083189\n\
00084   0.1223271\n\
00085   0.0026873\n\
00086 @end group\n\
00087 @end example\n\
00088 \n\
00089 @noindent\n\
00090 and\n\
00091 \n\
00092 @example\n\
00093 [u, s, v] = svd (hilb (3))\n\
00094 @end example\n\
00095 \n\
00096 @noindent\n\
00097 returns\n\
00098 \n\
00099 @example\n\
00100 @group\n\
00101 u =\n\
00102 \n\
00103   -0.82704   0.54745   0.12766\n\
00104   -0.45986  -0.52829  -0.71375\n\
00105   -0.32330  -0.64901   0.68867\n\
00106 \n\
00107 s =\n\
00108 \n\
00109   1.40832  0.00000  0.00000\n\
00110   0.00000  0.12233  0.00000\n\
00111   0.00000  0.00000  0.00269\n\
00112 \n\
00113 v =\n\
00114 \n\
00115   -0.82704   0.54745   0.12766\n\
00116   -0.45986  -0.52829  -0.71375\n\
00117   -0.32330  -0.64901   0.68867\n\
00118 @end group\n\
00119 @end example\n\
00120 \n\
00121 If given a second argument, @code{svd} returns an economy-sized\n\
00122 decomposition, eliminating the unnecessary rows or columns of @var{U} or\n\
00123 @var{V}.\n\
00124 @seealso{svd_driver, svds, eig}\n\
00125 @end deftypefn")
00126 {
00127   octave_value_list retval;
00128 
00129   int nargin = args.length ();
00130 
00131   if (nargin < 1 || nargin > 2 || nargout == 2 || nargout > 3)
00132     {
00133       print_usage ();
00134       return retval;
00135     }
00136 
00137   octave_value arg = args(0);
00138 
00139   octave_idx_type nr = arg.rows ();
00140   octave_idx_type nc = arg.columns ();
00141 
00142   if (arg.ndims () != 2)
00143     {
00144       error ("svd: A must be a 2-D matrix");
00145       return retval;
00146     }
00147 
00148   bool isfloat = arg.is_single_type ();
00149 
00150   SVD::type type = ((nargout == 0 || nargout == 1)
00151                     ? SVD::sigma_only
00152                     : (nargin == 2) ? SVD::economy : SVD::std);
00153 
00154   SVD::driver driver = static_cast<SVD::driver> (Vsvd_driver);
00155 
00156   if (nr == 0 || nc == 0)
00157     {
00158       if (isfloat)
00159         {
00160           switch (type)
00161             {
00162             case SVD::std:
00163               retval(2) = FloatDiagMatrix (nc, nc, 1.0f);
00164               retval(1) = FloatMatrix (nr, nc);
00165               retval(0) = FloatDiagMatrix (nr, nr, 1.0f);
00166               break;
00167             case SVD::economy:
00168               retval(2) = FloatDiagMatrix (0, nc, 1.0f);
00169               retval(1) = FloatMatrix (0, 0);
00170               retval(0) = FloatDiagMatrix (nr, 0, 1.0f);
00171               break;
00172             case SVD::sigma_only: default:
00173               retval(0) = FloatMatrix (0, 1);
00174               break;
00175             }
00176         }
00177       else
00178         {
00179           switch (type)
00180             {
00181             case SVD::std:
00182               retval(2) = DiagMatrix (nc, nc, 1.0);
00183               retval(1) = Matrix (nr, nc);
00184               retval(0) = DiagMatrix (nr, nr, 1.0);
00185               break;
00186             case SVD::economy:
00187               retval(2) = DiagMatrix (0, nc, 1.0);
00188               retval(1) = Matrix (0, 0);
00189               retval(0) = DiagMatrix (nr, 0, 1.0);
00190               break;
00191             case SVD::sigma_only: default:
00192               retval(0) = Matrix (0, 1);
00193               break;
00194             }
00195         }
00196     }
00197   else
00198     {
00199       if (isfloat)
00200         {
00201           if (arg.is_real_type ())
00202             {
00203               FloatMatrix tmp = arg.float_matrix_value ();
00204 
00205               if (! error_state)
00206                 {
00207                   if (tmp.any_element_is_inf_or_nan ())
00208                     {
00209                       error ("svd: cannot take SVD of matrix containing Inf or NaN values");
00210                       return retval;
00211                     }
00212 
00213                   FloatSVD result (tmp, type, driver);
00214 
00215                   FloatDiagMatrix sigma = result.singular_values ();
00216 
00217                   if (nargout == 0 || nargout == 1)
00218                     {
00219                       retval(0) = sigma.diag ();
00220                     }
00221                   else
00222                     {
00223                       retval(2) = result.right_singular_matrix ();
00224                       retval(1) = sigma;
00225                       retval(0) = result.left_singular_matrix ();
00226                     }
00227                 }
00228             }
00229           else if (arg.is_complex_type ())
00230             {
00231               FloatComplexMatrix ctmp = arg.float_complex_matrix_value ();
00232 
00233               if (! error_state)
00234                 {
00235                   if (ctmp.any_element_is_inf_or_nan ())
00236                     {
00237                       error ("svd: cannot take SVD of matrix containing Inf or NaN values");
00238                       return retval;
00239                     }
00240 
00241                   FloatComplexSVD result (ctmp, type, driver);
00242 
00243                   FloatDiagMatrix sigma = result.singular_values ();
00244 
00245                   if (nargout == 0 || nargout == 1)
00246                     {
00247                       retval(0) = sigma.diag ();
00248                     }
00249                   else
00250                     {
00251                       retval(2) = result.right_singular_matrix ();
00252                       retval(1) = sigma;
00253                       retval(0) = result.left_singular_matrix ();
00254                     }
00255                 }
00256             }
00257         }
00258       else
00259         {
00260           if (arg.is_real_type ())
00261             {
00262               Matrix tmp = arg.matrix_value ();
00263 
00264               if (! error_state)
00265                 {
00266                   if (tmp.any_element_is_inf_or_nan ())
00267                     {
00268                       error ("svd: cannot take SVD of matrix containing Inf or NaN values");
00269                       return retval;
00270                     }
00271 
00272                   SVD result (tmp, type, driver);
00273 
00274                   DiagMatrix sigma = result.singular_values ();
00275 
00276                   if (nargout == 0 || nargout == 1)
00277                     {
00278                       retval(0) = sigma.diag ();
00279                     }
00280                   else
00281                     {
00282                       retval(2) = result.right_singular_matrix ();
00283                       retval(1) = sigma;
00284                       retval(0) = result.left_singular_matrix ();
00285                     }
00286                 }
00287             }
00288           else if (arg.is_complex_type ())
00289             {
00290               ComplexMatrix ctmp = arg.complex_matrix_value ();
00291 
00292               if (! error_state)
00293                 {
00294                   if (ctmp.any_element_is_inf_or_nan ())
00295                     {
00296                       error ("svd: cannot take SVD of matrix containing Inf or NaN values");
00297                       return retval;
00298                     }
00299 
00300                   ComplexSVD result (ctmp, type, driver);
00301 
00302                   DiagMatrix sigma = result.singular_values ();
00303 
00304                   if (nargout == 0 || nargout == 1)
00305                     {
00306                       retval(0) = sigma.diag ();
00307                     }
00308                   else
00309                     {
00310                       retval(2) = result.right_singular_matrix ();
00311                       retval(1) = sigma;
00312                       retval(0) = result.left_singular_matrix ();
00313                     }
00314                 }
00315             }
00316           else
00317             {
00318               gripe_wrong_type_arg ("svd", arg);
00319               return retval;
00320             }
00321         }
00322     }
00323 
00324   return retval;
00325 }
00326 
00327 /*
00328 
00329 %!assert(svd ([1, 2; 2, 1]), [3; 1], sqrt (eps));
00330 
00331 %!test
00332 %! [u, s, v] = svd ([1, 2; 2, 1]);
00333 %! x = 1 / sqrt (2);
00334 %! assert (u, [-x, -x; -x, x], sqrt (eps));
00335 %! assert (s, [3, 0; 0, 1], sqrt (eps));
00336 %! assert (v, [-x, x; -x, -x], sqrt (eps));
00337 
00338 %!test
00339 %! a = [1, 2, 3; 4, 5, 6];
00340 %! [u, s, v] = svd (a);
00341 %! assert (u * s * v', a, sqrt (eps));
00342 
00343 %!test
00344 %! a = [1, 2; 3, 4; 5, 6];
00345 %! [u, s, v] = svd (a);
00346 %! assert (u * s * v', a, sqrt (eps));
00347 
00348 %!test
00349 %! a = [1, 2, 3; 4, 5, 6];
00350 %! [u, s, v] = svd (a, 1);
00351 %! assert (u * s * v', a, sqrt (eps));
00352 
00353 %!test
00354 %! a = [1, 2; 3, 4; 5, 6];
00355 %! [u, s, v] = svd (a, 1);
00356 %! assert (u * s * v', a, sqrt (eps));
00357 
00358 %!assert(svd (single([1, 2; 2, 1])), single([3; 1]), sqrt (eps('single')));
00359 
00360 %!test
00361 %! [u, s, v] = svd (single([1, 2; 2, 1]));
00362 %! x = single (1 / sqrt (2));
00363 %! assert (u, [-x, -x; -x, x], sqrt (eps('single')));
00364 %! assert (s, single([3, 0; 0, 1]), sqrt (eps('single')));
00365 %! assert (v, [-x, x; -x, -x], sqrt (eps('single')));
00366 
00367 %!test
00368 %! a = single([1, 2, 3; 4, 5, 6]);
00369 %! [u, s, v] = svd (a);
00370 %! assert (u * s * v', a, sqrt (eps('single')));
00371 
00372 %!test
00373 %! a = single([1, 2; 3, 4; 5, 6]);
00374 %! [u, s, v] = svd (a);
00375 %! assert (u * s * v', a, sqrt (eps('single')));
00376 
00377 %!test
00378 %! a = single([1, 2, 3; 4, 5, 6]);
00379 %! [u, s, v] = svd (a, 1);
00380 %! assert (u * s * v', a, sqrt (eps('single')));
00381 
00382 %!test
00383 %! a = single([1, 2; 3, 4; 5, 6]);
00384 %! [u, s, v] = svd (a, 1);
00385 %! assert (u * s * v', a, sqrt (eps('single')));
00386 
00387 %!test
00388 %! a = zeros (0, 5);
00389 %! [u, s, v] = svd (a);
00390 %! assert (size (u), [0, 0]);
00391 %! assert (size (s), [0, 5]);
00392 %! assert (size (v), [5, 5]);
00393 
00394 %!test
00395 %! a = zeros (5, 0);
00396 %! [u, s, v] = svd (a, 1);
00397 %! assert (size (u), [5, 0]);
00398 %! assert (size (s), [0, 0]);
00399 %! assert (size (v), [0, 0]);
00400 
00401 %!error <Invalid call to svd> svd ();
00402 %!error <Invalid call to svd> svd ([1, 2; 4, 5], 2, 3);
00403 %!error <Invalid call to svd> [u, v] = svd ([1, 2; 3, 4]);
00404 
00405 */
00406 
00407 DEFUN_DLD (svd_driver, args, nargout,
00408   "-*- texinfo -*-\n\
00409 @deftypefn  {Loadable Function} {@var{val} =} svd_driver ()\n\
00410 @deftypefnx {Loadable Function} {@var{old_val} =} svd_driver (@var{new_val})\n\
00411 @deftypefnx {Loadable Function} {} svd_driver (@var{new_val}, \"local\")\n\
00412 Query or set the underlying @sc{lapack} driver used by @code{svd}.\n\
00413 Currently recognized values are \"gesvd\" and \"gesdd\".  The default\n\
00414 is \"gesvd\".\n\
00415 \n\
00416 When called from inside a function with the \"local\" option, the variable is\n\
00417 changed locally for the function and any subroutines it calls.  The original\n\
00418 variable value is restored when exiting the function.\n\
00419 @seealso{svd}\n\
00420 @end deftypefn")
00421 {
00422   static const char *driver_names[] = { "gesvd", "gesdd", 0 };
00423 
00424   return SET_INTERNAL_VARIABLE_CHOICES (svd_driver, driver_names);
00425 }
00426 
00427 /*
00428 %!test
00429 %! A = [1+1i, 1-1i, 0; 0, 2, 0; 1i, 1i, 1+2i];
00430 %! old_driver = svd_driver ("gesvd");
00431 %! [U1, S1, V1] = svd (A);
00432 %! svd_driver ("gesdd");
00433 %! [U2, S2, V2] = svd (A);
00434 %! assert (U1, U2, 5*eps);
00435 %! assert (S1, S2, 5*eps);
00436 %! assert (V1, V2, 5*eps);
00437 %! svd_driver (old_driver);
00438 */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines