GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
pinv.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2018 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include "defun.h"
28 #include "error.h"
29 #include "errwarn.h"
30 #include "ovl.h"
31 #include "ops.h"
32 #include "ov-re-diag.h"
33 #include "ov-cx-diag.h"
34 #include "ov-flt-re-diag.h"
35 #include "ov-flt-cx-diag.h"
36 #include "ov-perm.h"
37 
38 DEFUN (pinv, args, ,
39  doc: /* -*- texinfo -*-
40 @deftypefn {} {} pinv (@var{x})
41 @deftypefnx {} {} pinv (@var{x}, @var{tol})
42 Return the @nospell{Moore-Penrose} pseudoinverse of @var{x}.
43 
44 Singular values less than @var{tol} are ignored.
45 
46 If the second argument is omitted, it is taken to be
47 
48 @example
49 tol = max ([rows(@var{x}), columns(@var{x})]) * norm (@var{x}) * eps
50 @end example
51 
52 @seealso{inv, ldivide}
53 @end deftypefn */)
54 {
55  int nargin = args.length ();
56 
58  print_usage ();
59 
60  octave_value arg = args(0);
61 
62  if (arg.isempty ())
63  return ovl (Matrix ());
64 
66 
67  bool isfloat = arg.is_single_type ();
68 
69  if (arg.is_diag_matrix ())
70  {
71  if (isfloat)
72  {
73  float tol = 0.0;
74  if (nargin == 2)
75  tol = args(1).float_value ();
76 
77  if (tol < 0.0)
78  error ("pinv: TOL must be greater than zero");
79 
80  if (arg.isreal ())
82  else
84  }
85  else
86  {
87  double tol = 0.0;
88  if (nargin == 2)
89  tol = args(1).double_value ();
90 
91  if (tol < 0.0)
92  error ("pinv: TOL must be greater than zero");
93 
94  if (arg.isreal ())
96  else
98  }
99  }
100  else if (arg.is_perm_matrix ())
101  {
103  }
104  else if (isfloat)
105  {
106  float tol = 0.0;
107  if (nargin == 2)
108  tol = args(1).float_value ();
109 
110  if (tol < 0.0)
111  error ("pinv: TOL must be greater than zero");
112 
113  if (arg.isreal ())
114  {
116 
117  retval = m.pseudo_inverse (tol);
118  }
119  else if (arg.iscomplex ())
120  {
122 
123  retval = m.pseudo_inverse (tol);
124  }
125  else
126  err_wrong_type_arg ("pinv", arg);
127  }
128  else
129  {
130  double tol = 0.0;
131  if (nargin == 2)
132  tol = args(1).double_value ();
133 
134  if (tol < 0.0)
135  error ("pinv: TOL must be greater than zero");
136 
137  if (arg.isreal ())
138  {
139  Matrix m = arg.matrix_value ();
140 
141  retval = m.pseudo_inverse (tol);
142  }
143  else if (arg.iscomplex ())
144  {
146 
147  retval = m.pseudo_inverse (tol);
148  }
149  else
150  err_wrong_type_arg ("pinv", arg);
151  }
152 
153  return retval;
154 }
155 
156 /*
157 %!shared a, b, tol, hitol, d, u, x, y
158 %! old_state = rand ("state");
159 %! restore_state = onCleanup (@() rand ("state", old_state));
160 %! rand ("state", 42); # initialize generator to make behavior reproducible
161 %! a = reshape (rand*[1:16], 4, 4); # Rank 2 matrix
162 %! b = pinv (a);
163 %! tol = 4e-14;
164 %! hitol = 40*sqrt (eps);
165 %! d = diag ([rand, rand, hitol, hitol]);
166 %! u = rand (4); # Could be singular by freak accident
167 %! x = inv (u)*d*u;
168 %! y = pinv (x, sqrt (eps));
169 
170 ## Verify Penrose conditions for pseudoinverse
171 %!assert (a*b*a, a, tol)
172 %!assert (b*a*b, b, tol)
173 %!assert ((b*a)', b*a, tol)
174 %!assert ((a*b)', a*b, tol)
175 %!assert (x*y*x, x, -hitol)
176 %!assert (y*x*y, y, -hitol)
177 %!assert ((x*y)', x*y, hitol)
178 %!assert ((y*x)', y*x, hitol)
179 
180 ## Clear shared variables
181 %!shared
182 
183 ## Test pinv for Diagonal matrices
184 %!test
185 %! x = diag ([3 2 1 0 -0.5]);
186 %! y = pinv (x);
187 %! assert (typeinfo (y)(1:8), "diagonal");
188 %! assert (isa (y, "double"));
189 %! assert (diag (y), [1/3, 1/2, 1, 0 1/-0.5]');
190 %! y = pinv (x, 1);
191 %! assert (diag (y), [1/3 1/2 1 0 0]');
192 %! y = pinv (x, 2);
193 %! assert (diag (y), [1/3 1/2 0 0 0]');
194 
195 ## Test special case of 0 scalars and vectors
196 %!assert (pinv (0), 0)
197 %!assert (pinv ([0, 0, 0]), [0; 0; 0])
198 %!assert (pinv (single (0)), single (0))
199 %!assert (pinv (single ([0, 0, 0])), single ([0; 0; 0]))
200 %!assert (pinv (complex (0,0)), 0)
201 %!assert (pinv (complex ([0,0,0], [0,0,0])), [0; 0; 0])
202 %!assert (pinv (complex (single (0),0)), single (0))
203 %!assert (pinv (complex (single ([0,0,0]), [0,0,0])), single ([0; 0; 0]))
204 */
Matrix pseudo_inverse(double tol=0.0) const
Definition: dMatrix.cc:676
bool isempty(void) const
Definition: ov.h:529
OCTINTERP_API void print_usage(void)
Definition: defun.cc:54
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:53
void error(const char *fmt,...)
Definition: error.cc:578
DiagMatrix diag_matrix_value(bool force=false) const
Definition: ov.h:891
FloatDiagMatrix float_diag_matrix_value(bool force=false) const
Definition: ov.h:894
FloatDiagMatrix pseudo_inverse(float tol=0.0f) const
Definition: fDiagMatrix.cc:255
FloatComplexMatrix pseudo_inverse(float tol=0.0) const
Definition: fCMatrix.cc:978
FloatMatrix float_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:837
bool is_perm_matrix(void) const
Definition: ov.h:574
octave_value arg
Definition: pr-output.cc:3244
FloatComplexMatrix float_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:856
ComplexDiagMatrix pseudo_inverse(double tol=0.0) const
Definition: CDiagMatrix.cc:334
FloatMatrix pseudo_inverse(float tol=0.0) const
Definition: fMatrix.cc:682
OCTAVE_EXPORT octave_value_list isfloat
Definition: data.cc:3212
ComplexDiagMatrix complex_diag_matrix_value(bool force=false) const
Definition: ov.h:897
bool is_single_type(void) const
Definition: ov.h:651
PermMatrix inverse(void) const
Definition: PermMatrix.cc:111
octave_value retval
Definition: data.cc:6246
Definition: dMatrix.h:36
FloatComplexDiagMatrix pseudo_inverse(float tol=0.0f) const
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:162
bool isreal(void) const
Definition: ov.h:703
FloatComplexDiagMatrix float_complex_diag_matrix_value(bool force=false) const
Definition: ov.h:901
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).isinteger())
ComplexMatrix pseudo_inverse(double tol=0.0) const
Definition: CMatrix.cc:975
args.length() nargin
Definition: file-io.cc:589
bool iscomplex(void) const
Definition: ov.h:710
bool is_diag_matrix(void) const
Definition: ov.h:571
PermMatrix perm_matrix_value(void) const
Definition: ov.h:904
ComplexMatrix complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:852
DiagMatrix pseudo_inverse(double tol=0.0) const
Definition: dDiagMatrix.cc:255
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:834