GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
lu.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2023 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 "lu.h"
31 #include "sparse-lu.h"
32 
33 #include "defun.h"
34 #include "error.h"
35 #include "errwarn.h"
36 #include "ovl.h"
37 #include "ov-re-sparse.h"
38 #include "ov-cx-sparse.h"
39 
41 
42 template <typename MT>
43 static octave_value
44 get_lu_l (const math::lu<MT>& fact)
45 {
46  MT L = fact.L ();
47  if (L.issquare ())
49  else
50  return L;
51 }
52 
53 template <typename MT>
54 static octave_value
55 get_lu_u (const math::lu<MT>& fact)
56 {
57  MT U = fact.U ();
58  if (U.issquare () && fact.regular ())
60  else
61  return U;
62 }
63 
64 DEFUN (lu, args, nargout,
65  doc: /* -*- texinfo -*-
66 @deftypefn {} {[@var{L}, @var{U}] =} lu (@var{A})
67 @deftypefnx {} {[@var{L}, @var{U}, @var{P}] =} lu (@var{A})
68 @deftypefnx {} {[@var{L}, @var{U}, @var{P}, @var{Q}] =} lu (@var{S})
69 @deftypefnx {} {[@var{L}, @var{U}, @var{P}, @var{Q}, @var{R}] =} lu (@var{S})
70 @deftypefnx {} {[@dots{}] =} lu (@var{S}, @var{thresh})
71 @deftypefnx {} {@var{y} =} lu (@dots{})
72 @deftypefnx {} {[@dots{}] =} lu (@dots{}, "vector")
73 @cindex LU decomposition
74 Compute the LU@tie{}decomposition of @var{A}.
75 
76 If @var{A} is full then subroutines from @sc{lapack} are used, and if
77 @var{A} is sparse then @sc{umfpack} is used.
78 
79 The result is returned in a permuted form, according to the optional return
80 value @var{P}. For example, given the matrix @code{@var{A} = [1, 2; 3, 4]},
81 
82 @example
83 [@var{L}, @var{U}, @var{P}] = lu (@var{A})
84 @end example
85 
86 @noindent
87 returns
88 
89 @example
90 @group
91 L =
92 
93  1.00000 0.00000
94  0.33333 1.00000
95 
96 U =
97 
98  3.00000 4.00000
99  0.00000 0.66667
100 
101 P =
102 
103  0 1
104  1 0
105 @end group
106 @end example
107 
108 The matrix is not required to be square.
109 
110 When called with two or three output arguments and a sparse input matrix,
111 @code{lu} does not attempt to perform sparsity preserving column permutations.
112 Called with a fourth output argument, the sparsity preserving column
113 transformation @var{Q} is returned, such that
114 @code{@var{P} * @var{A} * @var{Q} = @var{L} * @var{U}}. This is the
115 @strong{preferred} way to call @code{lu} with sparse input matrices.
116 
117 Called with a fifth output argument and a sparse input matrix, @code{lu}
118 attempts to use a scaling factor @var{R} on the input matrix such that
119 @code{@var{P} * (@var{R} \ @var{A}) * @var{Q} = @var{L} * @var{U}}.
120 This typically leads to a sparser and more stable factorization.
121 
122 An additional input argument @var{thresh} that defines the pivoting
123 threshold can be given. @var{thresh} can be a scalar, in which case
124 it defines the @sc{umfpack} pivoting tolerance for both symmetric and
125 unsymmetric cases. If @var{thresh} is a 2-element vector, then the first
126 element defines the pivoting tolerance for the unsymmetric @sc{umfpack}
127 pivoting strategy and the second for the symmetric strategy. By default,
128 the values defined by @code{spparms} are used ([0.1, 0.001]).
129 
130 Given the string argument @qcode{"vector"}, @code{lu} returns the values
131 of @var{P} and @var{Q} as vector values, such that for full matrix,
132 @code{@var{A}(@var{P},:) = @var{L} * @var{U}}, and @code{@var{R}(@var{P},:)
133 * @var{A}(:,@var{Q}) = @var{L} * @var{U}}.
134 
135 With two output arguments, returns the permuted forms of the upper and
136 lower triangular matrices, such that @code{@var{A} = @var{L} * @var{U}}.
137 With one output argument @var{y}, then the matrix returned by the
138 @sc{lapack} routines is returned. If the input matrix is sparse then the
139 matrix @var{L} is embedded into @var{U} to give a return value similar to
140 the full case. For both full and sparse matrices, @code{lu} loses the
141 permutation information.
142 @seealso{luupdate, ilu, chol, hess, qr, qz, schur, svd}
143 @end deftypefn */)
144 {
145  int nargin = args.length ();
146  bool issparse = (nargin > 0 && args(0).issparse ());
147 
148  if (nargin < 1 || (issparse && nargin > 3) || (! issparse && nargin > 2))
149  print_usage ();
150 
151  bool vecout = false;
152  Matrix thresh;
153  int n = 1;
154 
155  while (n < nargin)
156  {
157  if (args(n).is_string ())
158  {
159  std::string tmp = args(n++).string_value ();
160 
161  if (tmp == "vector")
162  vecout = true;
163  else
164  error ("lu: unrecognized string argument");
165  }
166  else
167  {
168  if (! issparse)
169  error ("lu: can not define pivoting threshold THRESH for full matrices");
170 
171  Matrix tmp = args(n++).matrix_value ();
172  if (tmp.numel () == 1)
173  {
174  thresh.resize (1, 2);
175  thresh(0) = tmp(0);
176  thresh(1) = tmp(0);
177  }
178  else if (tmp.numel () == 2)
179  thresh = tmp;
180  else
181  error ("lu: THRESH must be a 1- or 2-element vector");
182  }
183  }
184 
185  octave_value_list retval;
186  bool scale = (nargout == 5);
187 
188  octave_value arg = args(0);
189 
190  octave_idx_type nr = arg.rows ();
191  octave_idx_type nc = arg.columns ();
192 
193  if (issparse)
194  {
195  if (arg.isempty ())
196  return octave_value_list (5, SparseMatrix ());
197 
198  if (arg.isreal ())
199  {
201 
202  if (nargout < 4)
203  {
204  warning_with_id ("Octave:lu:sparse_input",
205  "lu: function may fail when called with less than 4 output arguments and a sparse input");
206 
207  ColumnVector Qinit (nc);
208  for (octave_idx_type i = 0; i < nc; i++)
209  Qinit(i) = i;
210  math::sparse_lu<SparseMatrix> fact (m, Qinit, thresh, false,
211  true);
212 
213  if (nargout < 2)
214  retval(0) = fact.Y ();
215  else
216  {
217  retval.resize (nargout == 3 ? 3 : 2);
218  retval(1)
219  = octave_value (fact.U () * fact.Pc_mat ().transpose (),
221  nc, fact.col_perm ()));
222 
223  PermMatrix P = fact.Pr_mat ();
224  SparseMatrix L = fact.L ();
225 
226  if (nargout == 2)
227  retval(0)
228  = octave_value (P.transpose () * L,
230  nr, fact.row_perm ()));
231  else
232  {
233  retval(0) = L;
234  if (vecout)
235  retval(2) = fact.Pr_vec();
236  else
237  retval(2) = P;
238  }
239  }
240  }
241  else
242  {
243  retval.resize (scale ? 5 : 4);
244  math::sparse_lu<SparseMatrix> fact (m, thresh, scale);
245 
246  retval(0) = octave_value (fact.L (),
248  retval(1) = octave_value (fact.U (),
250 
251  if (vecout)
252  {
253  retval(2) = fact.Pr_vec ();
254  retval(3) = fact.Pc_vec ();
255  }
256  else
257  {
258  retval(2) = fact.Pr_mat ();
259  retval(3) = fact.Pc_mat ();
260  }
261 
262  if (scale)
263  retval(4) = fact.R ();
264  }
265  }
266  else if (arg.iscomplex ())
267  {
269 
270  if (nargout < 4)
271  {
272  warning_with_id ("Octave:lu:sparse_input",
273  "lu: function may fail when called with less than 4 output arguments and a sparse input");
274 
275  ColumnVector Qinit (nc);
276  for (octave_idx_type i = 0; i < nc; i++)
277  Qinit(i) = i;
278  math::sparse_lu<SparseComplexMatrix> fact (m, Qinit, thresh,
279  false, true);
280 
281  if (nargout < 2)
282  retval(0) = fact.Y ();
283  else
284  {
285  retval.resize (nargout == 3 ? 3 : 2);
286  retval(1)
287  = octave_value (fact.U () * fact.Pc_mat ().transpose (),
289  nc, fact.col_perm ()));
290 
291  PermMatrix P = fact.Pr_mat ();
292  SparseComplexMatrix L = fact.L ();
293  if (nargout == 2)
294  retval(0)
295  = octave_value (P.transpose () * L,
297  nr, fact.row_perm ()));
298  else
299  {
300  retval(0) = L;
301  if (vecout)
302  retval(2) = fact.Pr_vec();
303  else
304  retval(2) = P;
305  }
306  }
307  }
308  else
309  {
310  retval.resize (scale ? 5 : 4);
312 
313  retval(0) = octave_value (fact.L (),
315  retval(1) = octave_value (fact.U (),
317 
318  if (vecout)
319  {
320  retval(2) = fact.Pr_vec ();
321  retval(3) = fact.Pc_vec ();
322  }
323  else
324  {
325  retval(2) = fact.Pr_mat ();
326  retval(3) = fact.Pc_mat ();
327  }
328 
329  if (scale)
330  retval(4) = fact.R ();
331  }
332 
333  }
334  else
335  err_wrong_type_arg ("lu", arg);
336  }
337  else
338  {
339  if (arg.isempty ())
340  return octave_value_list (3, Matrix ());
341 
342  if (arg.isreal ())
343  {
344  if (arg.is_single_type ())
345  {
347 
348  math::lu<FloatMatrix> fact (m);
349 
350  switch (nargout)
351  {
352  case 0:
353  case 1:
354  retval = ovl (fact.Y ());
355  break;
356 
357  case 2:
358  {
359  PermMatrix P = fact.P ();
360  FloatMatrix L = P.transpose () * fact.L ();
361  retval = ovl (L, get_lu_u (fact));
362  }
363  break;
364 
365  case 3:
366  default:
367  {
368  if (vecout)
369  retval = ovl (get_lu_l (fact), get_lu_u (fact),
370  fact.P_vec ());
371  else
372  retval = ovl (get_lu_l (fact), get_lu_u (fact),
373  fact.P ());
374  }
375  break;
376  }
377  }
378  else
379  {
380  Matrix m = arg.matrix_value ();
381 
382  math::lu<Matrix> fact (m);
383 
384  switch (nargout)
385  {
386  case 0:
387  case 1:
388  retval = ovl (fact.Y ());
389  break;
390 
391  case 2:
392  {
393  PermMatrix P = fact.P ();
394  Matrix L = P.transpose () * fact.L ();
395  retval = ovl (L, get_lu_u (fact));
396  }
397  break;
398 
399  case 3:
400  default:
401  {
402  if (vecout)
403  retval = ovl (get_lu_l (fact), get_lu_u (fact),
404  fact.P_vec ());
405  else
406  retval = ovl (get_lu_l (fact), get_lu_u (fact),
407  fact.P ());
408  }
409  break;
410  }
411  }
412  }
413  else if (arg.iscomplex ())
414  {
415  if (arg.is_single_type ())
416  {
418 
419  math::lu<FloatComplexMatrix> fact (m);
420 
421  switch (nargout)
422  {
423  case 0:
424  case 1:
425  retval = ovl (fact.Y ());
426  break;
427 
428  case 2:
429  {
430  PermMatrix P = fact.P ();
431  FloatComplexMatrix L = P.transpose () * fact.L ();
432  retval = ovl (L, get_lu_u (fact));
433  }
434  break;
435 
436  case 3:
437  default:
438  {
439  if (vecout)
440  retval = ovl (get_lu_l (fact), get_lu_u (fact),
441  fact.P_vec ());
442  else
443  retval = ovl (get_lu_l (fact), get_lu_u (fact),
444  fact.P ());
445  }
446  break;
447  }
448  }
449  else
450  {
452 
453  math::lu<ComplexMatrix> fact (m);
454 
455  switch (nargout)
456  {
457  case 0:
458  case 1:
459  retval = ovl (fact.Y ());
460  break;
461 
462  case 2:
463  {
464  PermMatrix P = fact.P ();
465  ComplexMatrix L = P.transpose () * fact.L ();
466  retval = ovl (L, get_lu_u (fact));
467  }
468  break;
469 
470  case 3:
471  default:
472  {
473  if (vecout)
474  retval = ovl (get_lu_l (fact), get_lu_u (fact),
475  fact.P_vec ());
476  else
477  retval = ovl (get_lu_l (fact), get_lu_u (fact),
478  fact.P ());
479  }
480  break;
481  }
482  }
483  }
484  else
485  err_wrong_type_arg ("lu", arg);
486  }
487 
488  return retval;
489 }
490 
491 /*
492 %!assert(lu ([1, 2; 3, 4]), [3, 4; 1/3, 2/3], eps)
493 
494 %!test
495 %! [l, u] = lu ([1, 2; 3, 4]);
496 %! assert (l, [1/3, 1; 1, 0], sqrt (eps));
497 %! assert (u, [3, 4; 0, 2/3], sqrt (eps));
498 
499 %!test
500 %! [l, u, p] = lu ([1, 2; 3, 4]);
501 %! assert (l, [1, 0; 1/3, 1], sqrt (eps));
502 %! assert (u, [3, 4; 0, 2/3], sqrt (eps));
503 %! assert (p(:,:), [0, 1; 1, 0], sqrt (eps));
504 
505 %!test
506 %! [l, u, p] = lu ([1, 2; 3, 4], "vector");
507 %! assert (l, [1, 0; 1/3, 1], sqrt (eps));
508 %! assert (u, [3, 4; 0, 2/3], sqrt (eps));
509 %! assert (p, [2;1], sqrt (eps));
510 
511 %!test
512 %! [l, u, p] = lu ([1, 2; 3, 4; 5, 6]);
513 %! assert (l, [1, 0; 1/5, 1; 3/5, 1/2], sqrt (eps));
514 %! assert (u, [5, 6; 0, 4/5], sqrt (eps));
515 %! assert (p(:,:), [0, 0, 1; 1, 0, 0; 0 1 0], sqrt (eps));
516 
517 %!assert (lu (single ([1, 2; 3, 4])), single ([3, 4; 1/3, 2/3]), eps ("single"))
518 
519 %!test
520 %! [l, u] = lu (single ([1, 2; 3, 4]));
521 %! assert (l, single ([1/3, 1; 1, 0]), sqrt (eps ("single")));
522 %! assert (u, single ([3, 4; 0, 2/3]), sqrt (eps ("single")));
523 
524 %!test
525 %! [l, u, p] = lu (single ([1, 2; 3, 4]));
526 %! assert (l, single ([1, 0; 1/3, 1]), sqrt (eps ("single")));
527 %! assert (u, single ([3, 4; 0, 2/3]), sqrt (eps ("single")));
528 %! assert (p(:,:), single ([0, 1; 1, 0]), sqrt (eps ("single")));
529 
530 %!test
531 %! [l, u, p] = lu (single ([1, 2; 3, 4]), "vector");
532 %! assert (l, single ([1, 0; 1/3, 1]), sqrt (eps ("single")));
533 %! assert (u, single ([3, 4; 0, 2/3]), sqrt (eps ("single")));
534 %! assert (p, single ([2;1]), sqrt (eps ("single")));
535 
536 %!test
537 %! [l u p] = lu (single ([1, 2; 3, 4; 5, 6]));
538 %! assert (l, single ([1, 0; 1/5, 1; 3/5, 1/2]), sqrt (eps ("single")));
539 %! assert (u, single ([5, 6; 0, 4/5]), sqrt (eps ("single")));
540 %! assert (p(:,:), single ([0, 0, 1; 1, 0, 0; 0 1 0]), sqrt (eps ("single")));
541 
542 %!testif HAVE_UMFPACK
543 %! Bi = [1 2 3 4 5 2 3 6 7 8 4 5 7 8 9];
544 %! Bj = [1 3 4 5 6 7 8 9 11 12 13 14 15 16 17];
545 %! Bv = [1 1 1 1 1 1 -1 1 1 1 1 -1 1 -1 1];
546 %! B = sparse (Bi, Bj, Bv);
547 %! warning ("off", "Octave:lu:sparse_input", "local");
548 %! [L, U] = lu (B);
549 %! assert (L*U, B);
550 %! [L, U, P] = lu(B);
551 %! assert (P'*L*U, B);
552 %! [L, U, P, Q] = lu (B);
553 %! assert (P'*L*U*Q', B);
554 
555 %!error lu ()
556 %!testif HAVE_UMFPACK
557 %! fail ("[l,u] = lu (sparse (magic (3)))", "warning", "function may fail");
558 %!error <can not define pivoting threshold> lu ([1, 2; 3, 4], 2)
559 
560 */
561 
562 static
563 bool check_lu_dims (const octave_value& l, const octave_value& u,
564  const octave_value& p)
565 {
566  octave_idx_type m = l.rows ();
567  octave_idx_type k = u.rows ();
568  octave_idx_type n = u.columns ();
569 
570  return ((l.ndims () == 2 && u.ndims () == 2 && k == l.columns ())
571  && k == std::min (m, n)
572  && (p.is_undefined () || p.rows () == m));
573 }
574 
575 DEFUN (luupdate, args, ,
576  doc: /* -*- texinfo -*-
577 @deftypefn {} {[@var{L}, @var{U}] =} luupdate (@var{L}, @var{U}, @var{x}, @var{y})
578 @deftypefnx {} {[@var{L}, @var{U}, @var{P}] =} luupdate (@var{L}, @var{U}, @var{P}, @var{x}, @var{y})
579 Given an LU@tie{}factorization of a real or complex matrix
580 @w{@var{A} = @var{L}*@var{U}}, @var{L}@tie{}lower unit trapezoidal and
581 @var{U}@tie{}upper trapezoidal, return the LU@tie{}factorization
582 of @w{@var{A} + @var{x}*@var{y}.'}, where @var{x} and @var{y} are
583 column vectors (rank-1 update) or matrices with equal number of columns
584 (rank-k update).
585 
586 Optionally, row-pivoted updating can be used by supplying a row permutation
587 (pivoting) matrix @var{P}; in that case, an updated permutation matrix is
588 returned. Note that if @var{L}, @var{U}, @var{P} is a pivoted
589 LU@tie{}factorization as obtained by @code{lu}:
590 
591 @example
592 [@var{L}, @var{U}, @var{P}] = lu (@var{A});
593 @end example
594 
595 @noindent
596 then a factorization of @tcode{@var{A}+@var{x}*@var{y}.'} can be obtained
597 either as
598 
599 @example
600 [@var{L1}, @var{U1}] = lu (@var{L}, @var{U}, @var{P}*@var{x}, @var{y})
601 @end example
602 
603 @noindent
604 or
605 
606 @example
607 [@var{L1}, @var{U1}, @var{P1}] = lu (@var{L}, @var{U}, @var{P}, @var{x}, @var{y})
608 @end example
609 
610 The first form uses the unpivoted algorithm, which is faster, but less
611 stable. The second form uses a slower pivoted algorithm, which is more
612 stable.
613 
614 The matrix case is done as a sequence of rank-1 updates; thus, for large
615 enough k, it will be both faster and more accurate to recompute the
616 factorization from scratch.
617 @seealso{lu, cholupdate, qrupdate}
618 @end deftypefn */)
619 {
620  int nargin = args.length ();
621 
622  if (nargin != 4 && nargin != 5)
623  print_usage ();
624 
625  bool pivoted = (nargin == 5);
626 
627  octave_value argl = args(0);
628  octave_value argu = args(1);
629  octave_value argp = (pivoted ? args(2) : octave_value ());
630  octave_value argx = args(2 + pivoted);
631  octave_value argy = args(3 + pivoted);
632 
633  if (! (argl.isnumeric () && argu.isnumeric ()
634  && argx.isnumeric () && argy.isnumeric ()
635  && (! pivoted || argp.is_perm_matrix ())))
636  error ("luupdate: L, U, X, and Y must be numeric");
637 
638  if (! check_lu_dims (argl, argu, argp))
639  error ("luupdate: dimension mismatch");
640 
641  PermMatrix P = (pivoted
642  ? argp.perm_matrix_value ()
643  : PermMatrix::eye (argl.rows ()));
644 
645  if (argl.isreal () && argu.isreal ()
646  && argx.isreal () && argy.isreal ())
647  {
648  // all real case
649  if (argl.is_single_type () || argu.is_single_type ()
650  || argx.is_single_type () || argy.is_single_type ())
651  {
652  FloatMatrix L = argl.float_matrix_value ();
653  FloatMatrix U = argu.float_matrix_value ();
654  FloatMatrix x = argx.float_matrix_value ();
655  FloatMatrix y = argy.float_matrix_value ();
656 
657  math::lu<FloatMatrix> fact (L, U, P);
658  if (pivoted)
659  fact.update_piv (x, y);
660  else
661  fact.update (x, y);
662 
663  if (pivoted)
664  return ovl (get_lu_l (fact), get_lu_u (fact), fact.P ());
665  else
666  return ovl (get_lu_l (fact), get_lu_u (fact));
667  }
668  else
669  {
670  Matrix L = argl.matrix_value ();
671  Matrix U = argu.matrix_value ();
672  Matrix x = argx.matrix_value ();
673  Matrix y = argy.matrix_value ();
674 
675  math::lu<Matrix> fact (L, U, P);
676  if (pivoted)
677  fact.update_piv (x, y);
678  else
679  fact.update (x, y);
680 
681  if (pivoted)
682  return ovl (get_lu_l (fact), get_lu_u (fact), fact.P ());
683  else
684  return ovl (get_lu_l (fact), get_lu_u (fact));
685  }
686  }
687  else
688  {
689  // complex case
690  if (argl.is_single_type () || argu.is_single_type ()
691  || argx.is_single_type () || argy.is_single_type ())
692  {
697 
698  math::lu<FloatComplexMatrix> fact (L, U, P);
699  if (pivoted)
700  fact.update_piv (x, y);
701  else
702  fact.update (x, y);
703 
704  if (pivoted)
705  return ovl (get_lu_l (fact), get_lu_u (fact), fact.P ());
706  else
707  return ovl (get_lu_l (fact), get_lu_u (fact));
708  }
709  else
710  {
715 
716  math::lu<ComplexMatrix> fact (L, U, P);
717  if (pivoted)
718  fact.update_piv (x, y);
719  else
720  fact.update (x, y);
721 
722  if (pivoted)
723  return ovl (get_lu_l (fact), get_lu_u (fact), fact.P ());
724  else
725  return ovl (get_lu_l (fact), get_lu_u (fact));
726  }
727  }
728 }
729 
730 /*
731 %!shared A, u, v, Ac, uc, vc
732 %! A = [0.091364 0.613038 0.999083;
733 %! 0.594638 0.425302 0.603537;
734 %! 0.383594 0.291238 0.085574;
735 %! 0.265712 0.268003 0.238409;
736 %! 0.669966 0.743851 0.445057 ];
737 %!
738 %! u = [0.85082;
739 %! 0.76426;
740 %! 0.42883;
741 %! 0.53010;
742 %! 0.80683 ];
743 %!
744 %! v = [0.98810;
745 %! 0.24295;
746 %! 0.43167 ];
747 %!
748 %! Ac = [0.620405 + 0.956953i 0.480013 + 0.048806i 0.402627 + 0.338171i;
749 %! 0.589077 + 0.658457i 0.013205 + 0.279323i 0.229284 + 0.721929i;
750 %! 0.092758 + 0.345687i 0.928679 + 0.241052i 0.764536 + 0.832406i;
751 %! 0.912098 + 0.721024i 0.049018 + 0.269452i 0.730029 + 0.796517i;
752 %! 0.112849 + 0.603871i 0.486352 + 0.142337i 0.355646 + 0.151496i ];
753 %!
754 %! uc = [0.20351 + 0.05401i;
755 %! 0.13141 + 0.43708i;
756 %! 0.29808 + 0.08789i;
757 %! 0.69821 + 0.38844i;
758 %! 0.74871 + 0.25821i ];
759 %!
760 %! vc = [0.85839 + 0.29468i;
761 %! 0.20820 + 0.93090i;
762 %! 0.86184 + 0.34689i ];
763 %!
764 
765 %!testif HAVE_QRUPDATE_LUU
766 %! [L,U,P] = lu (A);
767 %! [L,U] = luupdate (L,U,P*u,v);
768 %! assert (norm (vec (tril (L)-L), Inf) == 0);
769 %! assert (norm (vec (triu (U)-U), Inf) == 0);
770 %! assert (norm (vec (P'*L*U - A - u*v.'), Inf) < norm (A)*1e1*eps);
771 %!
772 %!testif HAVE_QRUPDATE_LUU
773 %! [L,U,P] = lu (Ac);
774 %! [L,U] = luupdate (L,U,P*uc,vc);
775 %! assert (norm (vec (tril (L)-L), Inf) == 0);
776 %! assert (norm (vec (triu (U)-U), Inf) == 0);
777 %! assert (norm (vec (P'*L*U - Ac - uc*vc.'), Inf) < norm (Ac)*1e1*eps);
778 
779 %!testif HAVE_QRUPDATE_LUU
780 %! [L,U,P] = lu (single (A));
781 %! [L,U] = luupdate (L,U,P* single (u), single (v));
782 %! assert (norm (vec (tril (L)-L), Inf) == 0);
783 %! assert (norm (vec (triu (U)-U), Inf) == 0);
784 %! assert (norm (vec (P'*L*U - single (A) - single (u)* single (v).'), Inf)
785 %! < norm (single (A))*1e1* eps ("single"));
786 %!
787 %!testif HAVE_QRUPDATE_LUU
788 %! [L,U,P] = lu (single (Ac));
789 %! [L,U] = luupdate (L,U,P* single (uc),single (vc));
790 %! assert (norm (vec (tril (L)-L), Inf) == 0);
791 %! assert (norm (vec (triu (U)-U), Inf) == 0);
792 %! assert (norm (vec (P'*L*U - single (Ac) - single (uc)* single (vc).'), Inf)
793 %! < norm (single (Ac))*1e1* eps ("single"));
794 
795 %!testif HAVE_QRUPDATE_LUU
796 %! [L,U,P] = lu (A);
797 %! [L,U,P] = luupdate (L,U,P,u,v);
798 %! assert (norm (vec (tril (L)-L), Inf) == 0);
799 %! assert (norm (vec (triu (U)-U), Inf) == 0);
800 %! assert (norm (vec (P'*L*U - A - u*v.'), Inf) < norm (A)*1e1*eps);
801 %!
802 %!testif HAVE_QRUPDATE_LUU
803 %! [L,U,P] = lu (A);
804 %! [~,ordcols] = max (P,[],1);
805 %! [~,ordrows] = max (P,[],2);
806 %! P1 = eye (size (P))(:,ordcols);
807 %! P2 = eye (size (P))(ordrows,:);
808 %! assert (P1 == P);
809 %! assert (P2 == P);
810 %! [L,U,P] = luupdate (L,U,P,u,v);
811 %! [L,U,P1] = luupdate (L,U,P1,u,v);
812 %! [L,U,P2] = luupdate (L,U,P2,u,v);
813 %! assert (P1 == P);
814 %! assert (P2 == P);
815 %!
816 %!testif HAVE_QRUPDATE_LUU
817 %! [L,U,P] = lu (Ac);
818 %! [L,U,P] = luupdate (L,U,P,uc,vc);
819 %! assert (norm (vec (tril (L)-L), Inf) == 0);
820 %! assert (norm (vec (triu (U)-U), Inf) == 0);
821 %! assert (norm (vec (P'*L*U - Ac - uc*vc.'), Inf) < norm (Ac)*1e1*eps);
822 
823 %!testif HAVE_QRUPDATE_LUU
824 %! [L,U,P] = lu (single (A));
825 %! [L,U,P] = luupdate (L,U,P,single (u),single (v));
826 %! assert (norm (vec (tril (L)-L), Inf) == 0);
827 %! assert (norm (vec (triu (U)-U), Inf) == 0);
828 %! assert (norm (vec (P'*L*U - single (A) - single (u)* single (v).'), Inf)
829 %! < norm (single (A))*1e1* eps ("single"));
830 %!
831 %!testif HAVE_QRUPDATE_LUU
832 %! [L,U,P] = lu (single (Ac));
833 %! [L,U,P] = luupdate (L,U,P,single (uc),single (vc));
834 %! assert (norm (vec (tril (L)-L), Inf) == 0);
835 %! assert (norm (vec (triu (U)-U), Inf) == 0);
836 %! assert (norm (vec (P'*L*U - single (Ac) - single (uc)* single (vc).'), Inf)
837 %! < norm (single (Ac))*1e1* eps ("single"));
838 */
839 
OCTAVE_END_NAMESPACE(octave)
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:414
@ Permuted_Lower
Definition: MatrixType.h:48
@ Permuted_Upper
Definition: MatrixType.h:47
Definition: dMatrix.h:42
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:158
static OCTAVE_API PermMatrix eye(octave_idx_type n)
Definition: PermMatrix.cc:205
OCTAVE_API PermMatrix transpose(void) const
Definition: PermMatrix.cc:101
Definition: lu.h:42
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
Definition: ovl.h:117
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:945
bool isreal(void) const
Definition: ov.h:783
ComplexMatrix complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:916
octave_idx_type rows(void) const
Definition: ov.h:590
bool isnumeric(void) const
Definition: ov.h:795
octave_idx_type columns(void) const
Definition: ov.h:592
int ndims(void) const
Definition: ov.h:596
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
bool is_undefined(void) const
Definition: ov.h:640
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
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
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
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1069
void error(const char *fmt,...)
Definition: error.cc:979
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:166
void scale(Matrix &m, double x, double y, double z)
Definition: graphics.cc:5851
static bool check_lu_dims(const octave_value &l, const octave_value &u, const octave_value &p)
Definition: lu.cc:563
static octave_value get_lu_u(const math::lu< MT > &fact)
Definition: lu.cc:55
static octave_value get_lu_l(const math::lu< MT > &fact)
Definition: lu.cc:44
F77_RET_T const F77_DBLE * x
T octave_idx_type m
Definition: mx-inlines.cc:773
octave_idx_type n
Definition: mx-inlines.cc:753
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
template class OCTAVE_API sparse_lu< SparseMatrix >
Definition: sparse-lu.cc:984
template class OCTAVE_API sparse_lu< SparseComplexMatrix >
Definition: sparse-lu.cc:986