GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
pinv.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include "defun.h"
31 #include "error.h"
32 #include "errwarn.h"
33 #include "ovl.h"
34 #include "ops.h"
35 #include "ov-re-diag.h"
36 #include "ov-cx-diag.h"
37 #include "ov-flt-re-diag.h"
38 #include "ov-flt-cx-diag.h"
39 #include "ov-perm.h"
40 
42 
43 DEFUN (pinv, args, ,
44  doc: /* -*- texinfo -*-
45 @deftypefn {} {@var{B} =} pinv (@var{A})
46 @deftypefnx {} {@var{B} =} pinv (@var{A}, @var{tol})
47 Return the @nospell{Moore-Penrose} pseudoinverse of @var{A}.
48 
49 Singular values less than @var{tol} are ignored.
50 
51 If the second argument is omitted, it is taken to be
52 
53 @example
54 tol = max ([rows(@var{x}), columns(@var{x})]) * norm (@var{x}) * eps
55 @end example
56 
57 @seealso{inv, ldivide}
58 @end deftypefn */)
59 {
60  int nargin = args.length ();
61 
62  if (nargin < 1 || nargin > 2)
63  print_usage ();
64 
65  octave_value arg = args(0);
66 
67  if (! arg.isnumeric ())
68  err_wrong_type_arg ("pinv", arg);
69 
70  if (arg.isempty ())
71  return ovl (Matrix ());
72 
73  octave_value retval;
74 
75  bool isfloat = arg.is_single_type ();
76 
77  if (arg.is_diag_matrix ())
78  {
79  if (isfloat)
80  {
81  float tol = 0.0;
82  if (nargin == 2)
83  tol = args(1).float_value ();
84 
85  if (tol < 0.0)
86  error ("pinv: TOL must be greater than zero");
87 
88  if (arg.isreal ())
89  retval = arg.float_diag_matrix_value ().pseudo_inverse (tol);
90  else
91  retval = arg.float_complex_diag_matrix_value ().pseudo_inverse (tol);
92  }
93  else
94  {
95  double tol = 0.0;
96  if (nargin == 2)
97  tol = args(1).double_value ();
98 
99  if (tol < 0.0)
100  error ("pinv: TOL must be greater than zero");
101 
102  if (arg.isreal ())
103  retval = arg.diag_matrix_value ().pseudo_inverse (tol);
104  else
105  retval = arg.complex_diag_matrix_value ().pseudo_inverse (tol);
106  }
107  }
108  else if (arg.is_perm_matrix ())
109  {
110  retval = arg.perm_matrix_value ().inverse ();
111  }
112  else if (isfloat)
113  {
114  float tol = 0.0;
115  if (nargin == 2)
116  tol = args(1).float_value ();
117 
118  if (tol < 0.0)
119  error ("pinv: TOL must be greater than zero");
120 
121  if (arg.isreal ())
122  {
124 
125  retval = m.pseudo_inverse (tol);
126  }
127  else if (arg.iscomplex ())
128  {
130 
131  retval = m.pseudo_inverse (tol);
132  }
133  else
134  err_wrong_type_arg ("pinv", arg);
135  }
136  else
137  {
138  double tol = 0.0;
139  if (nargin == 2)
140  tol = args(1).double_value ();
141 
142  if (tol < 0.0)
143  error ("pinv: TOL must be greater than zero");
144 
145  if (arg.isreal ())
146  {
147  Matrix m = arg.matrix_value ();
148 
149  retval = m.pseudo_inverse (tol);
150  }
151  else if (arg.iscomplex ())
152  {
154 
155  retval = m.pseudo_inverse (tol);
156  }
157  else
158  err_wrong_type_arg ("pinv", arg);
159  }
160 
161  return retval;
162 }
163 
164 /*
165 %!shared a, b, tol, hitol, d, u, x, y
166 %! old_state = rand ("state");
167 %! restore_state = onCleanup (@() rand ("state", old_state));
168 %! rand ("state", 42); # initialize generator to make behavior reproducible
169 %! a = reshape (rand*[1:16], 4, 4); # Rank 2 matrix
170 %! b = pinv (a);
171 %! tol = 4e-14;
172 %! hitol = 40* sqrt (eps);
173 %! d = diag ([rand, rand, hitol, hitol]);
174 %! u = rand (4); # Could be singular by freak accident
175 %! x = inv (u)*d*u;
176 %! y = pinv (x, sqrt (eps));
177 
178 ## Verify Penrose conditions for pseudoinverse
179 %!assert (a*b*a, a, tol)
180 %!assert (b*a*b, b, tol)
181 %!assert ((b*a)', b*a, tol)
182 %!assert ((a*b)', a*b, tol)
183 %!assert (x*y*x, x, -hitol)
184 %!assert (y*x*y, y, -hitol)
185 %!assert ((x*y)', x*y, hitol)
186 %!assert ((y*x)', y*x, hitol)
187 
188 ## Clear shared variables
189 %!shared
190 
191 ## Test pinv for Diagonal matrices
192 %!test
193 %! x = diag ([3 2 1 0 -0.5]);
194 %! y = pinv (x);
195 %! assert (typeinfo (y)(1:8), "diagonal");
196 %! assert (isa (y, "double"));
197 %! assert (diag (y), [1/3, 1/2, 1, 0 1/-0.5]');
198 %! y = pinv (x, 1);
199 %! assert (diag (y), [1/3 1/2 1 0 0]');
200 %! y = pinv (x, 2);
201 %! assert (diag (y), [1/3 1/2 0 0 0]');
202 
203 ## Basic test for integer inputs
204 %!assert (pinv (int32 (2)), 0.5)
205 %!assert (pinv (uint32 (2)), 0.5)
206 %!assert (pinv (int64 (2)), 0.5)
207 %!assert (pinv (uint64 (2)), 0.5)
208 
209 ## Test special case of 0 scalars and vectors
210 %!assert (pinv (0), 0)
211 %!assert (pinv ([0, 0, 0]), [0; 0; 0])
212 %!assert (pinv (single (0)), single (0))
213 %!assert (pinv (single ([0, 0, 0])), single ([0; 0; 0]))
214 %!assert (pinv (complex (0,0)), 0)
215 %!assert (pinv (complex ([0,0,0], [0,0,0])), [0; 0; 0])
216 %!assert (pinv (complex (single (0),0)), single (0))
217 %!assert (pinv (complex (single ([0,0,0]), [0,0,0])), single ([0; 0; 0]))
218 
219 ## Test input validation
220 %!error <wrong type argument> pinv ("Hello World")
221 %!error <wrong type argument> pinv ({1})
222 %!error <wrong type argument> pinv (true)
223 
224 */
225 
226 OCTAVE_END_NAMESPACE(octave)
ComplexDiagMatrix pseudo_inverse(double tol=0.0) const
Definition: CDiagMatrix.cc:356
DiagMatrix pseudo_inverse(double tol=0.0) const
Definition: dDiagMatrix.cc:279
FloatComplexDiagMatrix pseudo_inverse(float tol=0.0f) const
FloatDiagMatrix pseudo_inverse(float tol=0.0f) const
Definition: fDiagMatrix.cc:257
Definition: dMatrix.h:42
PermMatrix inverse() const
Definition: PermMatrix.cc:114
bool is_diag_matrix() const
Definition: ov.h:631
DiagMatrix diag_matrix_value(bool force=false) const
Definition: ov.h:910
bool isreal() const
Definition: ov.h:738
bool isnumeric() const
Definition: ov.h:750
FloatDiagMatrix float_diag_matrix_value(bool force=false) const
Definition: ov.h:913
ComplexMatrix complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:871
FloatComplexDiagMatrix float_complex_diag_matrix_value(bool force=false) const
Definition: ov.h:920
bool is_perm_matrix() const
Definition: ov.h:634
bool is_single_type() const
Definition: ov.h:698
bool isempty() const
Definition: ov.h:601
ComplexDiagMatrix complex_diag_matrix_value(bool force=false) const
Definition: ov.h:916
FloatMatrix float_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:856
bool iscomplex() const
Definition: ov.h:741
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:853
FloatComplexMatrix float_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:875
PermMatrix perm_matrix_value() const
Definition: ov.h:923
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage(void)
Definition: defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void() error(const char *fmt,...)
Definition: error.cc:988
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:166
T octave_idx_type m
Definition: mx-inlines.cc:781
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:219