comparison src/corefcn/lu.cc @ 15039:e753177cde93

maint: Move non-dynamically linked functions from DLD-FUNCTIONS/ to corefcn/ directory * __contourc__.cc, __dispatch__.cc, __lin_interpn__.cc, __pchip_deriv__.cc, __qp__.cc, balance.cc, besselj.cc, betainc.cc, bsxfun.cc, cellfun.cc, colloc.cc, conv2.cc, daspk.cc, dasrt.cc, dassl.cc, det.cc, dlmread.cc, dot.cc, eig.cc, fft.cc, fft2.cc, fftn.cc, filter.cc, find.cc, gammainc.cc, gcd.cc, getgrent.cc, getpwent.cc, getrusage.cc, givens.cc, hess.cc, hex2num.cc, inv.cc, kron.cc, lookup.cc, lsode.cc, lu.cc, luinc.cc, matrix_type.cc, max.cc, md5sum.cc, mgorth.cc, nproc.cc, pinv.cc, quad.cc, quadcc.cc, qz.cc, rand.cc, rcond.cc, regexp.cc, schur.cc, spparms.cc, sqrtm.cc, str2double.cc, strfind.cc, sub2ind.cc, svd.cc, syl.cc, time.cc, tril.cc, typecast.cc: Move functions from DLD-FUNCTIONS/ to corefcn/ directory. Include "defun.h", not "defun-dld.h". Change docstring to refer to these as "Built-in Functions". * build-aux/mk-opts.pl: Generate options code with '#include "defun.h"'. Change option docstrings to refer to these as "Built-in Functions". * corefcn/module.mk: List of functions to build in corefcn/ dir. * DLD-FUNCTIONS/config-module.awk: Update to new build system. * DLD-FUNCTIONS/module-files: Remove functions which are now in corefcn/ directory. * src/Makefile.am: Update to build "convenience library" in corefcn/. Octave program now links against all other libraries + corefcn libary. * src/find-defun-files.sh: Strip $srcdir from filename. * src/link-deps.mk: Add REGEX and FFTW link dependencies for liboctinterp. * type.m, which.m: Change failing tests to use 'amd', still a dynamic function, rather than 'dot', which isn't.
author Rik <rik@octave.org>
date Fri, 27 Jul 2012 15:35:00 -0700
parents src/DLD-FUNCTIONS/lu.cc@5ae9f0f77635
children
comparison
equal deleted inserted replaced
15038:ab18578c2ade 15039:e753177cde93
1 /*
2
3 Copyright (C) 1996-2012 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 the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 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 <http://www.gnu.org/licenses/>.
20
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include "CmplxLU.h"
28 #include "dbleLU.h"
29 #include "fCmplxLU.h"
30 #include "floatLU.h"
31 #include "SparseCmplxLU.h"
32 #include "SparsedbleLU.h"
33
34 #include "defun.h"
35 #include "error.h"
36 #include "gripes.h"
37 #include "oct-obj.h"
38 #include "utils.h"
39 #include "ov-re-sparse.h"
40 #include "ov-cx-sparse.h"
41
42 template <class MT>
43 static octave_value
44 get_lu_l (const base_lu<MT>& fact)
45 {
46 MT L = fact.L ();
47 if (L.is_square ())
48 return octave_value (L, MatrixType (MatrixType::Lower));
49 else
50 return L;
51 }
52
53 template <class MT>
54 static octave_value
55 get_lu_u (const base_lu<MT>& fact)
56 {
57 MT U = fact.U ();
58 if (U.is_square () && fact.regular ())
59 return octave_value (U, MatrixType (MatrixType::Upper));
60 else
61 return U;
62 }
63
64 DEFUN (lu, args, nargout,
65 "-*- texinfo -*-\n\
66 @deftypefn {Built-in Function} {[@var{L}, @var{U}] =} lu (@var{A})\n\
67 @deftypefnx {Built-in Function} {[@var{L}, @var{U}, @var{P}] =} lu (@var{A})\n\
68 @deftypefnx {Built-in Function} {[@var{L}, @var{U}, @var{P}, @var{Q}] =} lu (@var{S})\n\
69 @deftypefnx {Built-in Function} {[@var{L}, @var{U}, @var{P}, @var{Q}, @var{R}] =} lu (@var{S})\n\
70 @deftypefnx {Built-in Function} {[@dots{}] =} lu (@var{S}, @var{thres})\n\
71 @deftypefnx {Built-in Function} {@var{y} =} lu (@dots{})\n\
72 @deftypefnx {Built-in Function} {[@dots{}] =} lu (@dots{}, \"vector\")\n\
73 @cindex LU decomposition\n\
74 Compute the LU@tie{}decomposition of @var{A}. If @var{A} is full\n\
75 subroutines from\n\
76 @sc{lapack} are used and if @var{A} is sparse then @sc{umfpack} is used. The\n\
77 result is returned in a permuted form, according to the optional return\n\
78 value @var{P}. For example, given the matrix @code{a = [1, 2; 3, 4]},\n\
79 \n\
80 @example\n\
81 [l, u, p] = lu (@var{a})\n\
82 @end example\n\
83 \n\
84 @noindent\n\
85 returns\n\
86 \n\
87 @example\n\
88 @group\n\
89 l =\n\
90 \n\
91 1.00000 0.00000\n\
92 0.33333 1.00000\n\
93 \n\
94 u =\n\
95 \n\
96 3.00000 4.00000\n\
97 0.00000 0.66667\n\
98 \n\
99 p =\n\
100 \n\
101 0 1\n\
102 1 0\n\
103 @end group\n\
104 @end example\n\
105 \n\
106 The matrix is not required to be square.\n\
107 \n\
108 When called with two or three output arguments and a spare input matrix,\n\
109 @code{lu} does not attempt to perform sparsity preserving column\n\
110 permutations. Called with a fourth output argument, the sparsity\n\
111 preserving column transformation @var{Q} is returned, such that\n\
112 @code{@var{P} * @var{A} * @var{Q} = @var{L} * @var{U}}.\n\
113 \n\
114 Called with a fifth output argument and a sparse input matrix,\n\
115 @code{lu} attempts to use a scaling factor @var{R} on the input matrix\n\
116 such that\n\
117 @code{@var{P} * (@var{R} \\ @var{A}) * @var{Q} = @var{L} * @var{U}}.\n\
118 This typically leads to a sparser and more stable factorization.\n\
119 \n\
120 An additional input argument @var{thres}, that defines the pivoting\n\
121 threshold can be given. @var{thres} can be a scalar, in which case\n\
122 it defines the @sc{umfpack} pivoting tolerance for both symmetric and\n\
123 unsymmetric cases. If @var{thres} is a 2-element vector, then the first\n\
124 element defines the pivoting tolerance for the unsymmetric @sc{umfpack}\n\
125 pivoting strategy and the second for the symmetric strategy. By default,\n\
126 the values defined by @code{spparms} are used ([0.1, 0.001]).\n\
127 \n\
128 Given the string argument \"vector\", @code{lu} returns the values of @var{P}\n\
129 and @var{Q} as vector values, such that for full matrix, @code{@var{A}\n\
130 (@var{P},:) = @var{L} * @var{U}}, and @code{@var{R}(@var{P},:) * @var{A}\n\
131 (:, @var{Q}) = @var{L} * @var{U}}.\n\
132 \n\
133 With two output arguments, returns the permuted forms of the upper and\n\
134 lower triangular matrices, such that @code{@var{A} = @var{L} * @var{U}}.\n\
135 With one output argument @var{y}, then the matrix returned by the @sc{lapack}\n\
136 routines is returned. If the input matrix is sparse then the matrix @var{L}\n\
137 is embedded into @var{U} to give a return value similar to the full case.\n\
138 For both full and sparse matrices, @code{lu} loses the permutation\n\
139 information.\n\
140 @end deftypefn")
141 {
142 octave_value_list retval;
143 int nargin = args.length ();
144 bool issparse = (nargin > 0 && args(0).is_sparse_type ());
145 bool scale = (nargout == 5);
146
147 if (nargin < 1 || (issparse && (nargin > 3 || nargout > 5))
148 || (!issparse && (nargin > 2 || nargout > 3)))
149 {
150 print_usage ();
151 return retval;
152 }
153
154 bool vecout = false;
155 Matrix thres;
156
157 int n = 1;
158 while (n < nargin && ! error_state)
159 {
160 if (args (n).is_string ())
161 {
162 std::string tmp = args(n++).string_value ();
163
164 if (! error_state )
165 {
166 if (tmp.compare ("vector") == 0)
167 vecout = true;
168 else
169 error ("lu: unrecognized string argument");
170 }
171 }
172 else
173 {
174 Matrix tmp = args(n++).matrix_value ();
175
176 if (! error_state )
177 {
178 if (!issparse)
179 error ("lu: can not define pivoting threshold THRES for full matrices");
180 else if (tmp.nelem () == 1)
181 {
182 thres.resize (1,2);
183 thres(0) = tmp(0);
184 thres(1) = tmp(0);
185 }
186 else if (tmp.nelem () == 2)
187 thres = tmp;
188 else
189 error ("lu: expecting 2-element vector for THRES");
190 }
191 }
192 }
193
194 octave_value arg = args(0);
195
196 octave_idx_type nr = arg.rows ();
197 octave_idx_type nc = arg.columns ();
198
199 int arg_is_empty = empty_arg ("lu", nr, nc);
200
201 if (issparse)
202 {
203 if (arg_is_empty < 0)
204 return retval;
205 else if (arg_is_empty > 0)
206 return octave_value_list (5, SparseMatrix ());
207
208 ColumnVector Qinit;
209 if (nargout < 4)
210 {
211 Qinit.resize (nc);
212 for (octave_idx_type i = 0; i < nc; i++)
213 Qinit (i) = i;
214 }
215
216 if (arg.is_real_type ())
217 {
218 SparseMatrix m = arg.sparse_matrix_value ();
219
220 switch (nargout)
221 {
222 case 0:
223 case 1:
224 case 2:
225 {
226 SparseLU fact (m, Qinit, thres, false, true);
227
228 if (nargout < 2)
229 retval(0) = fact.Y ();
230 else
231 {
232 PermMatrix P = fact.Pr_mat ();
233 SparseMatrix L = P.transpose () * fact.L ();
234 retval(1) = octave_value (fact.U (),
235 MatrixType (MatrixType::Upper));
236
237 retval(0) = octave_value (L,
238 MatrixType (MatrixType::Permuted_Lower,
239 nr, fact.row_perm ()));
240 }
241 }
242 break;
243
244 case 3:
245 {
246 SparseLU fact (m, Qinit, thres, false, true);
247
248 if (vecout)
249 retval(2) = fact.Pr_vec ();
250 else
251 retval(2) = fact.Pr_mat ();
252
253 retval(1) = octave_value (fact.U (),
254 MatrixType (MatrixType::Upper));
255 retval(0) = octave_value (fact.L (),
256 MatrixType (MatrixType::Lower));
257 }
258 break;
259
260 case 4:
261 default:
262 {
263 SparseLU fact (m, thres, scale);
264
265 if (scale)
266 retval(4) = fact.R ();
267
268 if (vecout)
269 {
270 retval(3) = fact.Pc_vec ();
271 retval(2) = fact.Pr_vec ();
272 }
273 else
274 {
275 retval(3) = fact.Pc_mat ();
276 retval(2) = fact.Pr_mat ();
277 }
278 retval(1) = octave_value (fact.U (),
279 MatrixType (MatrixType::Upper));
280 retval(0) = octave_value (fact.L (),
281 MatrixType (MatrixType::Lower));
282 }
283 break;
284 }
285 }
286 else if (arg.is_complex_type ())
287 {
288 SparseComplexMatrix m = arg.sparse_complex_matrix_value ();
289
290 switch (nargout)
291 {
292 case 0:
293 case 1:
294 case 2:
295 {
296 SparseComplexLU fact (m, Qinit, thres, false, true);
297
298 if (nargout < 2)
299 retval(0) = fact.Y ();
300 else
301 {
302 PermMatrix P = fact.Pr_mat ();
303 SparseComplexMatrix L = P.transpose () * fact.L ();
304 retval(1) = octave_value (fact.U (),
305 MatrixType (MatrixType::Upper));
306
307 retval(0) = octave_value (L,
308 MatrixType (MatrixType::Permuted_Lower,
309 nr, fact.row_perm ()));
310 }
311 }
312 break;
313
314 case 3:
315 {
316 SparseComplexLU fact (m, Qinit, thres, false, true);
317
318 if (vecout)
319 retval(2) = fact.Pr_vec ();
320 else
321 retval(2) = fact.Pr_mat ();
322
323 retval(1) = octave_value (fact.U (),
324 MatrixType (MatrixType::Upper));
325 retval(0) = octave_value (fact.L (),
326 MatrixType (MatrixType::Lower));
327 }
328 break;
329
330 case 4:
331 default:
332 {
333 SparseComplexLU fact (m, thres, scale);
334
335 if (scale)
336 retval(4) = fact.R ();
337
338 if (vecout)
339 {
340 retval(3) = fact.Pc_vec ();
341 retval(2) = fact.Pr_vec ();
342 }
343 else
344 {
345 retval(3) = fact.Pc_mat ();
346 retval(2) = fact.Pr_mat ();
347 }
348 retval(1) = octave_value (fact.U (),
349 MatrixType (MatrixType::Upper));
350 retval(0) = octave_value (fact.L (),
351 MatrixType (MatrixType::Lower));
352 }
353 break;
354 }
355 }
356 else
357 gripe_wrong_type_arg ("lu", arg);
358 }
359 else
360 {
361 if (arg_is_empty < 0)
362 return retval;
363 else if (arg_is_empty > 0)
364 return octave_value_list (3, Matrix ());
365
366 if (arg.is_real_type ())
367 {
368 if (arg.is_single_type ())
369 {
370 FloatMatrix m = arg.float_matrix_value ();
371
372 if (! error_state)
373 {
374 FloatLU fact (m);
375
376 switch (nargout)
377 {
378 case 0:
379 case 1:
380 retval(0) = fact.Y ();
381 break;
382
383 case 2:
384 {
385 PermMatrix P = fact.P ();
386 FloatMatrix L = P.transpose () * fact.L ();
387 retval(1) = get_lu_u (fact);
388 retval(0) = L;
389 }
390 break;
391
392 case 3:
393 default:
394 {
395 if (vecout)
396 retval(2) = fact.P_vec ();
397 else
398 retval(2) = fact.P ();
399 retval(1) = get_lu_u (fact);
400 retval(0) = get_lu_l (fact);
401 }
402 break;
403 }
404 }
405 }
406 else
407 {
408 Matrix m = arg.matrix_value ();
409
410 if (! error_state)
411 {
412 LU fact (m);
413
414 switch (nargout)
415 {
416 case 0:
417 case 1:
418 retval(0) = fact.Y ();
419 break;
420
421 case 2:
422 {
423 PermMatrix P = fact.P ();
424 Matrix L = P.transpose () * fact.L ();
425 retval(1) = get_lu_u (fact);
426 retval(0) = L;
427 }
428 break;
429
430 case 3:
431 default:
432 {
433 if (vecout)
434 retval(2) = fact.P_vec ();
435 else
436 retval(2) = fact.P ();
437 retval(1) = get_lu_u (fact);
438 retval(0) = get_lu_l (fact);
439 }
440 break;
441 }
442 }
443 }
444 }
445 else if (arg.is_complex_type ())
446 {
447 if (arg.is_single_type ())
448 {
449 FloatComplexMatrix m = arg.float_complex_matrix_value ();
450
451 if (! error_state)
452 {
453 FloatComplexLU fact (m);
454
455 switch (nargout)
456 {
457 case 0:
458 case 1:
459 retval(0) = fact.Y ();
460 break;
461
462 case 2:
463 {
464 PermMatrix P = fact.P ();
465 FloatComplexMatrix L = P.transpose () * fact.L ();
466 retval(1) = get_lu_u (fact);
467 retval(0) = L;
468 }
469 break;
470
471 case 3:
472 default:
473 {
474 if (vecout)
475 retval(2) = fact.P_vec ();
476 else
477 retval(2) = fact.P ();
478 retval(1) = get_lu_u (fact);
479 retval(0) = get_lu_l (fact);
480 }
481 break;
482 }
483 }
484 }
485 else
486 {
487 ComplexMatrix m = arg.complex_matrix_value ();
488
489 if (! error_state)
490 {
491 ComplexLU fact (m);
492
493 switch (nargout)
494 {
495 case 0:
496 case 1:
497 retval(0) = fact.Y ();
498 break;
499
500 case 2:
501 {
502 PermMatrix P = fact.P ();
503 ComplexMatrix L = P.transpose () * fact.L ();
504 retval(1) = get_lu_u (fact);
505 retval(0) = L;
506 }
507 break;
508
509 case 3:
510 default:
511 {
512 if (vecout)
513 retval(2) = fact.P_vec ();
514 else
515 retval(2) = fact.P ();
516 retval(1) = get_lu_u (fact);
517 retval(0) = get_lu_l (fact);
518 }
519 break;
520 }
521 }
522 }
523 }
524 else
525 gripe_wrong_type_arg ("lu", arg);
526 }
527
528 return retval;
529 }
530
531 /*
532 %!assert(lu ([1, 2; 3, 4]), [3, 4; 1/3, 2/3], eps);
533
534 %!test
535 %! [l, u] = lu ([1, 2; 3, 4]);
536 %! assert (l, [1/3, 1; 1, 0], sqrt (eps));
537 %! assert (u, [3, 4; 0, 2/3], sqrt (eps));
538
539 %!test
540 %! [l, u, p] = lu ([1, 2; 3, 4]);
541 %! assert (l, [1, 0; 1/3, 1], sqrt (eps));
542 %! assert (u, [3, 4; 0, 2/3], sqrt (eps));
543 %! assert (p(:,:), [0, 1; 1, 0], sqrt (eps));
544
545 %!test
546 %! [l, u, p] = lu ([1, 2; 3, 4], "vector");
547 %! assert (l, [1, 0; 1/3, 1], sqrt (eps));
548 %! assert (u, [3, 4; 0, 2/3], sqrt (eps));
549 %! assert (p, [2;1], sqrt (eps));
550
551 %!test
552 %! [l, u, p] = lu ([1, 2; 3, 4; 5, 6]);
553 %! assert (l, [1, 0; 1/5, 1; 3/5, 1/2], sqrt (eps));
554 %! assert (u, [5, 6; 0, 4/5], sqrt (eps));
555 %! assert (p(:,:), [0, 0, 1; 1, 0, 0; 0 1 0], sqrt (eps));
556
557 %!assert (lu (single ([1, 2; 3, 4])), single ([3, 4; 1/3, 2/3]), eps ("single"))
558
559 %!test
560 %! [l, u] = lu (single ([1, 2; 3, 4]));
561 %! assert (l, single ([1/3, 1; 1, 0]), sqrt (eps ("single")));
562 %! assert (u, single ([3, 4; 0, 2/3]), sqrt (eps ("single")));
563
564 %!test
565 %! [l, u, p] = lu (single ([1, 2; 3, 4]));
566 %! assert (l, single ([1, 0; 1/3, 1]), sqrt (eps ("single")));
567 %! assert (u, single ([3, 4; 0, 2/3]), sqrt (eps ("single")));
568 %! assert (p(:,:), single ([0, 1; 1, 0]), sqrt (eps ("single")));
569
570 %!test
571 %! [l, u, p] = lu (single ([1, 2; 3, 4]), "vector");
572 %! assert (l, single ([1, 0; 1/3, 1]), sqrt (eps ("single")));
573 %! assert (u, single ([3, 4; 0, 2/3]), sqrt (eps ("single")));
574 %! assert (p, single ([2;1]), sqrt (eps ("single")));
575
576 %!test
577 %! [l u p] = lu (single ([1, 2; 3, 4; 5, 6]));
578 %! assert (l, single ([1, 0; 1/5, 1; 3/5, 1/2]), sqrt (eps ("single")));
579 %! assert (u, single ([5, 6; 0, 4/5]), sqrt (eps ("single")));
580 %! assert (p(:,:), single ([0, 0, 1; 1, 0, 0; 0 1 0]), sqrt (eps ("single")));
581
582 %!error lu ()
583 %!error <can not define pivoting threshold> lu ([1, 2; 3, 4], 2)
584 */
585
586 static
587 bool check_lu_dims (const octave_value& l, const octave_value& u,
588 const octave_value& p)
589 {
590 octave_idx_type m = l.rows (), k = u.rows (), n = u.columns ();
591 return ((l.ndims () == 2 && u.ndims () == 2 && k == l.columns ())
592 && k == std::min (m, n) &&
593 (p.is_undefined () || p.rows () == m));
594 }
595
596 DEFUN (luupdate, args, ,
597 "-*- texinfo -*-\n\
598 @deftypefn {Built-in Function} {[@var{L}, @var{U}] =} luupdate (@var{L}, @var{U}, @var{x}, @var{y})\n\
599 @deftypefnx {Built-in Function} {[@var{L}, @var{U}, @var{P}] =} luupdate (@var{L}, @var{U}, @var{P}, @var{x}, @var{y})\n\
600 Given an LU@tie{}factorization of a real or complex matrix\n\
601 @w{@var{A} = @var{L}*@var{U}}, @var{L}@tie{}lower unit trapezoidal and\n\
602 @var{U}@tie{}upper trapezoidal, return the LU@tie{}factorization\n\
603 of @w{@var{A} + @var{x}*@var{y}.'}, where @var{x} and @var{y} are\n\
604 column vectors (rank-1 update) or matrices with equal number of columns\n\
605 (rank-k update).\n\
606 Optionally, row-pivoted updating can be used by supplying\n\
607 a row permutation (pivoting) matrix @var{P};\n\
608 in that case, an updated permutation matrix is returned.\n\
609 Note that if @var{L}, @var{U}, @var{P} is a pivoted LU@tie{}factorization\n\
610 as obtained by @code{lu}:\n\
611 \n\
612 @example\n\
613 [@var{L}, @var{U}, @var{P}] = lu (@var{A});\n\
614 @end example\n\
615 \n\
616 @noindent\n\
617 then a factorization of @xcode{@var{A}+@var{x}*@var{y}.'} can be obtained\n\
618 either as\n\
619 \n\
620 @example\n\
621 [@var{L1}, @var{U1}] = lu (@var{L}, @var{U}, @var{P}*@var{x}, @var{y})\n\
622 @end example\n\
623 \n\
624 @noindent\n\
625 or\n\
626 \n\
627 @example\n\
628 [@var{L1}, @var{U1}, @var{P1}] = lu (@var{L}, @var{U}, @var{P}, @var{x}, @var{y})\n\
629 @end example\n\
630 \n\
631 The first form uses the unpivoted algorithm, which is faster, but less\n\
632 stable. The second form uses a slower pivoted algorithm, which is more\n\
633 stable.\n\
634 \n\
635 The matrix case is done as a sequence of rank-1 updates;\n\
636 thus, for large enough k, it will be both faster and more accurate to\n\
637 recompute the factorization from scratch.\n\
638 @seealso{lu, qrupdate, cholupdate}\n\
639 @end deftypefn")
640 {
641 octave_idx_type nargin = args.length ();
642 octave_value_list retval;
643
644 bool pivoted = nargin == 5;
645
646 if (nargin != 4 && nargin != 5)
647 {
648 print_usage ();
649 return retval;
650 }
651
652 octave_value argl = args(0);
653 octave_value argu = args(1);
654 octave_value argp = pivoted ? args(2) : octave_value ();
655 octave_value argx = args(2 + pivoted);
656 octave_value argy = args(3 + pivoted);
657
658 if (argl.is_numeric_type () && argu.is_numeric_type ()
659 && argx.is_numeric_type () && argy.is_numeric_type ()
660 && (! pivoted || argp.is_perm_matrix ()))
661 {
662 if (check_lu_dims (argl, argu, argp))
663 {
664 PermMatrix P = (pivoted
665 ? argp.perm_matrix_value ()
666 : PermMatrix::eye (argl.rows ()));
667
668 if (argl.is_real_type ()
669 && argu.is_real_type ()
670 && argx.is_real_type ()
671 && argy.is_real_type ())
672 {
673 // all real case
674 if (argl.is_single_type ()
675 || argu.is_single_type ()
676 || argx.is_single_type ()
677 || argy.is_single_type ())
678 {
679 FloatMatrix L = argl.float_matrix_value ();
680 FloatMatrix U = argu.float_matrix_value ();
681 FloatMatrix x = argx.float_matrix_value ();
682 FloatMatrix y = argy.float_matrix_value ();
683
684 FloatLU fact (L, U, P);
685 if (pivoted)
686 fact.update_piv (x, y);
687 else
688 fact.update (x, y);
689
690 if (pivoted)
691 retval(2) = fact.P ();
692 retval(1) = get_lu_u (fact);
693 retval(0) = get_lu_l (fact);
694 }
695 else
696 {
697 Matrix L = argl.matrix_value ();
698 Matrix U = argu.matrix_value ();
699 Matrix x = argx.matrix_value ();
700 Matrix y = argy.matrix_value ();
701
702 LU fact (L, U, P);
703 if (pivoted)
704 fact.update_piv (x, y);
705 else
706 fact.update (x, y);
707
708 if (pivoted)
709 retval(2) = fact.P ();
710 retval(1) = get_lu_u (fact);
711 retval(0) = get_lu_l (fact);
712 }
713 }
714 else
715 {
716 // complex case
717 if (argl.is_single_type ()
718 || argu.is_single_type ()
719 || argx.is_single_type ()
720 || argy.is_single_type ())
721 {
722 FloatComplexMatrix L = argl.float_complex_matrix_value ();
723 FloatComplexMatrix U = argu.float_complex_matrix_value ();
724 FloatComplexMatrix x = argx.float_complex_matrix_value ();
725 FloatComplexMatrix y = argy.float_complex_matrix_value ();
726
727 FloatComplexLU fact (L, U, P);
728 if (pivoted)
729 fact.update_piv (x, y);
730 else
731 fact.update (x, y);
732
733 if (pivoted)
734 retval(2) = fact.P ();
735 retval(1) = get_lu_u (fact);
736 retval(0) = get_lu_l (fact);
737 }
738 else
739 {
740 ComplexMatrix L = argl.complex_matrix_value ();
741 ComplexMatrix U = argu.complex_matrix_value ();
742 ComplexMatrix x = argx.complex_matrix_value ();
743 ComplexMatrix y = argy.complex_matrix_value ();
744
745 ComplexLU fact (L, U, P);
746 if (pivoted)
747 fact.update_piv (x, y);
748 else
749 fact.update (x, y);
750
751 if (pivoted)
752 retval(2) = fact.P ();
753 retval(1) = get_lu_u (fact);
754 retval(0) = get_lu_l (fact);
755 }
756 }
757 }
758 else
759 error ("luupdate: dimension mismatch");
760 }
761 else
762 error ("luupdate: L, U, X, and Y must be numeric");
763
764 return retval;
765 }
766
767 /*
768 %!shared A, u, v, Ac, uc, vc
769 %! A = [0.091364 0.613038 0.999083;
770 %! 0.594638 0.425302 0.603537;
771 %! 0.383594 0.291238 0.085574;
772 %! 0.265712 0.268003 0.238409;
773 %! 0.669966 0.743851 0.445057 ];
774 %!
775 %! u = [0.85082;
776 %! 0.76426;
777 %! 0.42883;
778 %! 0.53010;
779 %! 0.80683 ];
780 %!
781 %! v = [0.98810;
782 %! 0.24295;
783 %! 0.43167 ];
784 %!
785 %! Ac = [0.620405 + 0.956953i 0.480013 + 0.048806i 0.402627 + 0.338171i;
786 %! 0.589077 + 0.658457i 0.013205 + 0.279323i 0.229284 + 0.721929i;
787 %! 0.092758 + 0.345687i 0.928679 + 0.241052i 0.764536 + 0.832406i;
788 %! 0.912098 + 0.721024i 0.049018 + 0.269452i 0.730029 + 0.796517i;
789 %! 0.112849 + 0.603871i 0.486352 + 0.142337i 0.355646 + 0.151496i ];
790 %!
791 %! uc = [0.20351 + 0.05401i;
792 %! 0.13141 + 0.43708i;
793 %! 0.29808 + 0.08789i;
794 %! 0.69821 + 0.38844i;
795 %! 0.74871 + 0.25821i ];
796 %!
797 %! vc = [0.85839 + 0.29468i;
798 %! 0.20820 + 0.93090i;
799 %! 0.86184 + 0.34689i ];
800 %!
801
802 %!testif HAVE_QRUPDATE_LUU
803 %! [L,U,P] = lu (A);
804 %! [L,U] = luupdate (L,U,P*u,v);
805 %! assert (norm (vec (tril (L)-L), Inf) == 0);
806 %! assert (norm (vec (triu (U)-U), Inf) == 0);
807 %! assert (norm (vec (P'*L*U - A - u*v.'), Inf) < norm (A)*1e1*eps);
808 %!
809 %!testif HAVE_QRUPDATE_LUU
810 %! [L,U,P] = lu (Ac);
811 %! [L,U] = luupdate (L,U,P*uc,vc);
812 %! assert (norm (vec (tril (L)-L), Inf) == 0);
813 %! assert (norm (vec (triu (U)-U), Inf) == 0);
814 %! assert (norm (vec (P'*L*U - Ac - uc*vc.'), Inf) < norm (Ac)*1e1*eps);
815
816 %!testif HAVE_QRUPDATE_LUU
817 %! [L,U,P] = lu (single (A));
818 %! [L,U] = luupdate (L,U,P*single (u), single (v));
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 - single (A) - single (u)*single (v).'), Inf) < norm (single (A))*1e1*eps ("single"));
822 %!
823 %!testif HAVE_QRUPDATE_LUU
824 %! [L,U,P] = lu (single (Ac));
825 %! [L,U] = luupdate (L,U,P*single (uc),single (vc));
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 (Ac) - single (uc)*single (vc).'), Inf) < norm (single (Ac))*1e1*eps ("single"));
829
830 %!testif HAVE_QRUPDATE_LUU
831 %! [L,U,P] = lu (A);
832 %! [L,U,P] = luupdate (L,U,P,u,v);
833 %! assert (norm (vec (tril (L)-L), Inf) == 0);
834 %! assert (norm (vec (triu (U)-U), Inf) == 0);
835 %! assert (norm (vec (P'*L*U - A - u*v.'), Inf) < norm (A)*1e1*eps);
836 %!
837 %!testif HAVE_QRUPDATE_LUU
838 %! [L,U,P] = lu (Ac);
839 %! [L,U,P] = luupdate (L,U,P,uc,vc);
840 %! assert (norm (vec (tril (L)-L), Inf) == 0);
841 %! assert (norm (vec (triu (U)-U), Inf) == 0);
842 %! assert (norm (vec (P'*L*U - Ac - uc*vc.'), Inf) < norm (Ac)*1e1*eps);
843
844 %!testif HAVE_QRUPDATE_LUU
845 %! [L,U,P] = lu (single (A));
846 %! [L,U,P] = luupdate (L,U,P,single (u),single (v));
847 %! assert (norm (vec (tril (L)-L), Inf) == 0);
848 %! assert (norm (vec (triu (U)-U), Inf) == 0);
849 %! assert (norm (vec (P'*L*U - single (A) - single (u)*single (v).'), Inf) < norm (single (A))*1e1*eps ("single"));
850 %!
851 %!testif HAVE_QRUPDATE_LUU
852 %! [L,U,P] = lu (single (Ac));
853 %! [L,U,P] = luupdate (L,U,P,single (uc),single (vc));
854 %! assert (norm (vec (tril (L)-L), Inf) == 0);
855 %! assert (norm (vec (triu (U)-U), Inf) == 0);
856 %! assert (norm (vec (P'*L*U - single (Ac) - single (uc)*single (vc).'), Inf) < norm (single (Ac))*1e1*eps ("single"));
857 */