GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
inv.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1996-2022 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
41OCTAVE_NAMESPACE_BEGIN
42
43DEFUN (inv, args, nargout,
44 doc: /* -*- texinfo -*-
45@deftypefn {} {@var{x} =} inv (@var{A})
46@deftypefnx {} {[@var{x}, @var{rcond}] =} inv (@var{A})
47@deftypefnx {} {[@dots{}] =} inverse (@dots{})
48Compute the inverse of the square matrix @var{A}.
49
50Return an estimate of the reciprocal condition number if requested,
51otherwise warn of an ill-conditioned matrix if the reciprocal condition
52number is small.
53
54In general it is best to avoid calculating the inverse of a matrix directly.
55For example, it is both faster and more accurate to solve systems of
56equations (@var{A}*@math{x} = @math{b}) with
57@code{@var{y} = @var{A} \ @math{b}}, rather than
58@code{@var{y} = inv (@var{A}) * @math{b}}.
59
60If called with a sparse matrix, then in general @var{x} will be a full
61matrix requiring significantly more storage. Avoid forming the inverse of a
62sparse matrix if possible.
63
64@code{inverse} is an alias and may be used identically in place of @code{inv}.
65@seealso{ldivide, rdivide, pinv}
66@end deftypefn */)
67{
68 if (args.length () != 1)
69 print_usage ();
70
71 octave_value arg = args(0);
72
73 if (arg.isempty ())
74 return ovl (Matrix ());
75
76 if (arg.rows () != arg.columns ())
77 err_square_matrix_required ("inverse", "A");
78
79 octave_value result;
80 octave_idx_type info;
81 double rcond = 0.0;
82 float frcond = 0.0;
83 bool isfloat = arg.is_single_type ();
84
85 if (arg.is_diag_matrix ())
86 {
87 rcond = 1.0;
88 frcond = 1.0f;
89 if (arg.iscomplex ())
90 {
91 if (isfloat)
92 {
93 result = arg.float_complex_diag_matrix_value ().inverse (info);
94 if (info == -1)
95 frcond = 0.0f;
96 else if (nargout > 1)
97 frcond = arg.float_complex_diag_matrix_value ().rcond ();
98 }
99 else
100 {
101 result = arg.complex_diag_matrix_value ().inverse (info);
102 if (info == -1)
103 rcond = 0.0;
104 else if (nargout > 1)
105 rcond = arg.complex_diag_matrix_value ().rcond ();
106 }
107 }
108 else
109 {
110 if (isfloat)
111 {
112 result = arg.float_diag_matrix_value ().inverse (info);
113 if (info == -1)
114 frcond = 0.0f;
115 else if (nargout > 1)
116 frcond = arg.float_diag_matrix_value ().rcond ();
117 }
118 else
119 {
120 result = arg.diag_matrix_value ().inverse (info);
121 if (info == -1)
122 rcond = 0.0;
123 else if (nargout > 1)
124 rcond = arg.diag_matrix_value ().rcond ();
125 }
126 }
127 }
128 else if (arg.is_perm_matrix ())
129 {
130 info = 0;
131 rcond = 1.0;
132 result = arg.perm_matrix_value ().inverse ();
133 }
134 else if (isfloat)
135 {
136 if (arg.isreal ())
137 {
139
140 MatrixType mattyp = args(0).matrix_type ();
141 result = m.inverse (mattyp, info, frcond, true, true);
142 args(0).matrix_type (mattyp);
143 }
144 else if (arg.iscomplex ())
145 {
147
148 MatrixType mattyp = args(0).matrix_type ();
149 result = m.inverse (mattyp, info, frcond, true, true);
150 args(0).matrix_type (mattyp);
151 }
152 }
153 else
154 {
155 if (arg.isreal ())
156 {
157 if (arg.issparse ())
158 {
160
161 MatrixType mattyp = args(0).matrix_type ();
162 result = m.inverse (mattyp, info, rcond, true, true);
163 args(0).matrix_type (mattyp);
164 }
165 else
166 {
167 Matrix m = arg.matrix_value ();
168
169 MatrixType mattyp = args(0).matrix_type ();
170 result = m.inverse (mattyp, info, rcond, true, true);
171 args(0).matrix_type (mattyp);
172 }
173 }
174 else if (arg.iscomplex ())
175 {
176 if (arg.issparse ())
177 {
179
180 MatrixType mattyp = args(0).matrix_type ();
181 result = m.inverse (mattyp, info, rcond, true, true);
182 args(0).matrix_type (mattyp);
183 }
184 else
185 {
187
188 MatrixType mattyp = args(0).matrix_type ();
189 result = m.inverse (mattyp, info, rcond, true, true);
190 args(0).matrix_type (mattyp);
191 }
192 }
193 else
194 err_wrong_type_arg ("inv", arg);
195 }
196
197 octave_value_list retval (nargout > 1 ? 2 : 1);
198
199 retval(0) = result;
200 if (nargout > 1)
201 retval(1) = (isfloat ? octave_value (frcond) : octave_value (rcond));
202
203 if (nargout < 2)
204 {
205 bool is_singular;
206
207 if (isfloat)
208 is_singular = ((frcond + 1.0f == 1.0f) || octave::math::isnan (frcond))
209 && ! arg.is_scalar_type ();
210 else
211 is_singular = ((rcond + 1.0 == 1.0) || octave::math::isnan (rcond))
212 && ! arg.is_scalar_type ();
213
214 if (info == -1 || is_singular)
215 warn_singular_matrix (isfloat ? frcond : rcond);
216 }
217
218 return retval;
219}
220
221/*
222## Basic test for double/single matrices
223%!assert (inv ([1, 2; 3, 4]), [-2, 1; 1.5, -0.5], 5*eps)
224%!test
225%! [xinv, rcond] = inv ([1,2;3,4]);
226%! assert (xinv, [-2, 1; 1.5, -0.5], 5*eps);
227%! assert (isa (rcond, "double"));
228
229%!assert (inv (single ([1, 2; 3, 4])), single ([-2, 1; 1.5, -0.5]),
230%! 5*eps ("single"))
231%!test
232%! [xinv, rcond] = inv (single ([1,2;3,4]));
233%! assert (xinv, single ([-2, 1; 1.5, -0.5]), 5*eps ("single"));
234%! assert (isa (rcond, "single"));
235
236## Normal scalar cases
237%!assert (inv (2), 0.5)
238%!test
239%! [xinv, rcond] = inv (2);
240%! assert (xinv, 0.5);
241%! assert (rcond, 1);
242%!assert (inv (single (2)), single (0.5))
243%!test
244%! [xinv, rcond] = inv (single (2));
245%! assert (xinv, single (0.5));
246%! assert (rcond, single (1));
247%!assert (inv (complex (1, -1)), 0.5+0.5i)
248%!test
249%! [xinv, rcond] = inv (complex (1, -1));
250%! assert (xinv, 0.5+0.5i);
251%! assert (rcond, 1);
252%!assert (inv (complex (single (1), -1)), single (0.5+0.5i))
253%!test
254%! [xinv, rcond] = inv (complex (single (1), -1));
255%! assert (xinv, single (0.5+0.5i));
256%! assert (rcond, single (1));
257
258## Test special inputs
259## Empty matrix
260%!assert (inv (zeros (2,0)), [])
261
262## Scalar "0"
263%!assert (inv (0), Inf)
264%!test
265%! [xinv, rcond] = inv (0);
266%! assert (xinv, Inf);
267%! assert (rcond, 0);
268%!assert (inv (single (0)), single (Inf))
269%!test
270%! [xinv, rcond] = inv (single (0));
271%! assert (xinv, single (Inf));
272%! assert (rcond, single (0));
273%!assert (inv (complex (0, 0)), Inf)
274%!test
275%! [xinv, rcond] = inv (complex (0, 0));
276%! assert (xinv, Inf);
277%! assert (rcond, 0);
278%!assert (inv (complex (single (0), 0)), single (Inf))
279%!test
280%! [xinv, rcond] = inv (complex (single (0), 0));
281%! assert (xinv, single (Inf));
282%! assert (rcond, single (0));
283## NOTE: Matlab returns +Inf for -0 input, but it returns -Inf for 1/-0.
284## These should be the same, and in Octave they are.
285%!assert (inv (-0), -Inf)
286%!test
287%! [xinv, rcond] = inv (-0);
288%! assert (xinv, -Inf);
289%! assert (rcond, 0);
290
291## Scalar "Inf"
292%!assert (inv (Inf), 0)
293%!test
294%! [xinv, rcond] = inv (Inf);
295%! assert (xinv, 0);
296%! assert (rcond, 0);
297%!assert (inv (single (Inf)), single (0))
298%!test
299%! [xinv, rcond] = inv (single (Inf));
300%! assert (xinv, single (0));
301%! assert (rcond, single (0));
302%!assert (inv (complex (1, Inf)), 0)
303%!test
304%! [xinv, rcond] = inv (complex (1, Inf));
305%! assert (xinv, 0);
306%! assert (rcond, 0);
307%!assert (inv (complex (single (1), Inf)), single (0))
308%!test
309%! [xinv, rcond] = inv (complex (single (1), Inf));
310%! assert (xinv, single (0));
311%! assert (rcond, single (0));
312
313## Scalar "NaN"
314%!assert (inv (NaN), NaN)
315%!test
316%! [xinv, rcond] = inv (NaN);
317%! assert (xinv, NaN);
318%! assert (rcond, NaN);
319%!assert (inv (single (NaN)), single (NaN))
320%!test
321%! [xinv, rcond] = inv (single (NaN));
322%! assert (xinv, single (NaN));
323%! assert (rcond, single (NaN));
324%!assert (inv (complex (1, NaN)), complex (NaN, NaN))
325%!test
326%! [xinv, rcond] = inv (complex (1, NaN));
327%! assert (xinv, complex (NaN, NaN));
328%! assert (rcond, NaN);
329%!assert (inv (complex (single (1), NaN)), complex (single (NaN), NaN))
330%!test
331%! [xinv, rcond] = inv (complex (single (1), NaN));
332%! assert (xinv, complex (single (NaN), NaN));
333%! assert (rcond, single (NaN));
334
335## Matrix special values
336## Matrix of all zeroes
337%!warning <matrix singular> assert (inv (zeros (2,2)), Inf (2,2))
338%!test
339%! [xinv, rcond] = inv (zeros (2,2));
340%! assert (xinv, Inf (2,2));
341%! assert (rcond, 0);
342## Matrix of all Inf
343%!warning <rcond = > assert (inv (Inf (2,2)), NaN (2,2))
344%!test
345%! [xinv, rcond] = inv (Inf (2,2));
346%! assert (xinv, NaN (2,2));
347%! assert (rcond, NaN);
348## Matrix of all NaN
349%!warning <rcond = > assert (inv (NaN (2,2)), NaN (2,2))
350%!test
351%! [xinv, rcond] = inv (NaN (2,2));
352%! assert (xinv, NaN (2,2));
353%! assert (rcond, NaN);
354
355## Special diagonal matrices
356%!test
357%! fail ("A = inv (diag ([1, 0, 1]))", "warning", "matrix singular");
358%! assert (A, diag ([Inf, Inf, Inf]));
359
360## Special sparse matrices
361%!testif HAVE_UMFPACK <*56232>
362%! fail ("A = inv (sparse ([1, 2;0 ,0]))", "warning", "matrix singular");
363%! assert (A, sparse ([Inf, Inf; 0, 0]));
364
365%!testif HAVE_UMFPACK <*56232>
366%! fail ("A = inv (sparse ([1i, 2;0 ,0]))", "warning", "matrix singular");
367%! assert (A, sparse ([Inf, Inf; 0, 0]));
368
369%!testif HAVE_UMFPACK <*56232>
370%! fail ("A = inv (sparse ([1, 0, 0; 0, 0, 0; 0, 0, 1]))", "warning", "matrix singular");
371%! assert (A, sparse ([Inf, 0, 0; 0, 0, 0; 0, 0, Inf]));
372
373%!error inv ()
374%!error inv ([1, 2; 3, 4], 2)
375%!error <must be a square matrix> inv ([1, 2; 3, 4; 5, 6])
376%!error <inverse of the null matrix not defined> inv (sparse (2, 2, 0))
377%!error <inverse of the null matrix not defined> inv (diag ([0, 0]))
378%!error <inverse of the null matrix not defined> inv (diag (complex ([0, 0])))
379*/
380
381DEFALIAS (inverse, inv);
382
383OCTAVE_NAMESPACE_END
OCTAVE_API double rcond(void) const
Definition: CDiagMatrix.cc:507
OCTAVE_API ComplexDiagMatrix inverse(octave_idx_type &info) const
Definition: CDiagMatrix.cc:311
OCTAVE_API ComplexMatrix inverse(void) const
Definition: CMatrix.cc:737
OCTAVE_API DiagMatrix inverse(void) const
Definition: dDiagMatrix.cc:227
OCTAVE_API double rcond(void) const
Definition: dDiagMatrix.cc:345
OCTAVE_API FloatComplexDiagMatrix inverse(octave_idx_type &info) const
OCTAVE_API float rcond(void) const
OCTAVE_API FloatComplexMatrix inverse(void) const
Definition: fCMatrix.cc:740
OCTAVE_API FloatDiagMatrix inverse(void) const
Definition: fDiagMatrix.cc:227
OCTAVE_API float rcond(void) const
Definition: fDiagMatrix.cc:323
OCTAVE_API FloatMatrix inverse(void) const
Definition: fMatrix.cc:457
Definition: dMatrix.h:42
OCTAVE_API Matrix inverse(void) const
Definition: dMatrix.cc:451
OCTAVE_API PermMatrix inverse(void) const
Definition: PermMatrix.cc:114
OCTAVE_API SparseComplexMatrix inverse(void) const
Definition: CSparse.cc:660
OCTAVE_API SparseMatrix inverse(void) const
Definition: dSparse.cc:603
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:945
bool isreal(void) const
Definition: ov.h:783
bool issparse(void) const
Definition: ov.h:798
DiagMatrix diag_matrix_value(bool force=false) const
Definition: ov.h:955
FloatDiagMatrix float_diag_matrix_value(bool force=false) const
Definition: ov.h:958
ComplexMatrix complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:916
octave_idx_type rows(void) const
Definition: ov.h:590
FloatComplexDiagMatrix float_complex_diag_matrix_value(bool force=false) const
Definition: ov.h:965
bool is_scalar_type(void) const
Definition: ov.h:789
bool is_diag_matrix(void) const
Definition: ov.h:676
octave_idx_type columns(void) const
Definition: ov.h:592
ComplexDiagMatrix complex_diag_matrix_value(bool force=false) const
Definition: ov.h:961
FloatMatrix float_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:901
PermMatrix perm_matrix_value(void) const
Definition: ov.h:968
bool isempty(void) const
Definition: ov.h:646
bool is_single_type(void) const
Definition: ov.h:743
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:898
bool is_perm_matrix(void) const
Definition: ov.h:679
FloatComplexMatrix float_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:920
bool iscomplex(void) const
Definition: ov.h:786
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:949
OCTINTERP_API 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
#define DEFALIAS(alias, name)
Macro to define an alias for another existing function name.
Definition: defun.h:160
void err_square_matrix_required(const char *fcn, const char *name)
Definition: errwarn.cc:122
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:166
bool isnan(bool)
Definition: lo-mappers.h:178
void warn_singular_matrix(double rcond)
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211