GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
qr.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 <string>
31
32#include "MArray.h"
33#include "Matrix.h"
34#include "qr.h"
35#include "qrp.h"
36#include "sparse-qr.h"
37
38#include "defun.h"
39#include "error.h"
40#include "errwarn.h"
41#include "ov.h"
42#include "ovl.h"
43
44OCTAVE_NAMESPACE_BEGIN
45
46/*
47## Restore all rand* "state" values
48%!function restore_rand_states (state)
49%! rand ("state", state.rand);
50%! randn ("state", state.randn);
51%!endfunction
52
53%!shared old_state, restore_state
54%! ## Save and restore the states of both random number generators that are
55%! ## tested by the unit tests in this file.
56%! old_state.rand = rand ("state");
57%! old_state.randn = randn ("state");
58%! restore_state = onCleanup (@() restore_rand_states (old_state));
59*/
60
61template <typename MT>
62static octave_value
63get_qr_r (const math::qr<MT>& fact)
64{
65 MT R = fact.R ();
66 if (R.issquare () && fact.regular ())
68 else
69 return R;
70}
71
72template <typename T>
73static typename math::qr<T>::type
74qr_type (int nargout, bool economy)
75{
76 if (nargout == 0 || nargout == 1)
77 return math::qr<T>::raw;
78 else if (economy)
79 return math::qr<T>::economy;
80 else
81 return math::qr<T>::std;
82}
83
84// dense X
85//
86// [Q, R] = qr (X): form Q unitary and R upper triangular such
87// that Q * R = X
88//
89// [Q, R] = qr (X, 0): form the economy decomposition such that if X is
90// m by n then only the first n columns of Q are
91// computed.
92//
93// [Q, R, P] = qr (X): form QRP factorization of X where
94// P is a permutation matrix such that
95// A * P = Q * R
96//
97// [Q, R, P] = qr (X, 0): form the economy decomposition with
98// permutation vector P such that Q * R = X(:, P)
99//
100// qr (X) alone returns the output of the LAPACK routine dgeqrf, such
101// that R = triu (qr (X))
102//
103// sparse X
104//
105// X = qr (A, B): if M < N, X is the minimum 2-norm solution of
106// A\B. If M >= N, X is the least squares
107// approximation of A\B. X is calculated by
108// SPQR-function SuiteSparseQR_min2norm.
109//
110DEFUN (qr, args, nargout,
111 doc: /* -*- texinfo -*-
112@deftypefn {} {[@var{Q}, @var{R}] =} qr (@var{A})
113@deftypefnx {} {[@var{Q}, @var{R}, @var{P}] =} qr (@var{A})
114@deftypefnx {} {@var{X} =} qr (@var{A}) # non-sparse A
115@deftypefnx {} {@var{R} =} qr (@var{A}) # sparse A
116@deftypefnx {} {@var{X} =} qr (@var{A}, @var{B}) # sparse A
117@deftypefnx {} {[@var{C}, @var{R}] =} qr (@var{A}, @var{B})
118@deftypefnx {} {[@dots{}] =} qr (@dots{}, 0)
119@deftypefnx {} {[@dots{}] =} qr (@dots{}, "vector")
120@deftypefnx {} {[@dots{}] =} qr (@dots{}, "matrix")
121@cindex QR factorization
122Compute the QR@tie{}factorization of @var{A}, using standard @sc{lapack}
123subroutines.
124
125The QR@tie{}factorization is
126@tex
127$QR = A$ where $Q$ is an orthogonal matrix and $R$ is upper triangular.
128@end tex
129@ifnottex
130
131@example
132@var{Q} * @var{R} = @var{A}
133@end example
134
135@noindent
136where @var{Q} is an orthogonal matrix and @var{R} is upper triangular.
137@end ifnottex
138
139For example, given the matrix @code{@var{A} = [1, 2; 3, 4]},
140
141@example
142[@var{Q}, @var{R}] = qr (@var{A})
143@end example
144
145@noindent
146returns
147
148@example
149@group
150@var{Q} =
151
152 -0.31623 -0.94868
153 -0.94868 0.31623
154
155@var{R} =
156
157 -3.16228 -4.42719
158 0.00000 -0.63246
159@end group
160@end example
161
162@noindent
163which multiplied together return the original matrix
164
165@example
166@group
167@var{Q} * @var{R}
168 @result{}
169 1.0000 2.0000
170 3.0000 4.0000
171@end group
172@end example
173
174If just a single return value is requested then it is either @var{R}, if
175@var{A} is sparse, or @var{X}, such that @code{@var{R} = triu (@var{X})} if
176@var{A} is full. (Note: unlike most commands, the single return value is not
177the first return value when multiple values are requested.)
178
179If a third output @var{P} is requested, then @code{qr} calculates the permuted
180QR@tie{}factorization
181@tex
182$QR = AP$ where $Q$ is an orthogonal matrix, $R$ is upper triangular, and $P$
183is a permutation matrix.
184@end tex
185@ifnottex
186
187@example
188@var{Q} * @var{R} = @var{A} * @var{P}
189@end example
190
191@noindent
192where @var{Q} is an orthogonal matrix, @var{R} is upper triangular, and
193@var{P} is a permutation matrix.
194@end ifnottex
195
196If @var{A} is dense, the permuted QR@tie{}factorization has the additional
197property that the diagonal entries of @var{R} are ordered by decreasing
198magnitude. In other words, @code{abs (diag (@var{R}))} will be ordered
199from largest to smallest.
200
201If @var{A} is sparse, @var{P} is a fill-reducing ordering of the columns
202of @var{A}. In that case, the diagonal entries of @var{R} are not ordered by
203decreasing magnitude.
204
205For example, given the matrix @code{@var{A} = [1, 2; 3, 4]},
206
207@example
208[@var{Q}, @var{R}, @var{P}] = qr (@var{A})
209@end example
210
211@noindent
212returns
213
214@example
215@group
216@var{Q} =
217
218 -0.44721 -0.89443
219 -0.89443 0.44721
220
221@var{R} =
222
223 -4.47214 -3.13050
224 0.00000 0.44721
225
226@var{P} =
227
228 0 1
229 1 0
230@end group
231@end example
232
233If the input matrix @var{A} is sparse, the sparse QR@tie{}factorization
234is computed by using @sc{SPQR} or @sc{cxsparse} (e.g., if @sc{SPQR} is not
235available). Because the matrix @var{Q} is, in general, a full matrix, it is
236recommended to request only one return value @var{R}. In that case, the
237computation avoids the construction of @var{Q} and returns a sparse @var{R}
238such that @code{@var{R} = chol (@var{A}' * @var{A})}.
239
240If @var{A} is dense, an additional matrix @var{B} is supplied and two
241return values are requested, then @code{qr} returns @var{C}, where
242@code{@var{C} = @var{Q}' * @var{B}}. This allows the least squares
243approximation of @code{@var{A} \ @var{B}} to be calculated as
244
245@example
246@group
247[@var{C}, @var{R}] = qr (@var{A}, @var{B})
248@var{X} = @var{R} \ @var{C}
249@end group
250@end example
251
252If @var{A} is a sparse MxN matrix and an additional matrix @var{B} is
253supplied, one or two return values are possible. If one return value @var{X}
254is requested and M < N, then @var{X} is the minimum 2-norm solution of
255@w{@code{@var{A} \ @var{B}}}. If M >= N, @var{X} is the least squares
256approximation @w{of @code{@var{A} \ @var{B}}}. If two return values are
257requested, @var{C} and @var{R} have the same meaning as in the dense case
258(@var{C} is dense and @var{R} is sparse).
259The version with one return parameter should be preferred because
260it uses less memory and can handle rank-deficient matrices better.
261
262If the final argument is the string @qcode{"vector"} then @var{P} is a
263permutation vector (of the columns of @var{A}) instead of a permutation
264matrix. In this case, the defining relationship is:
265
266@example
267@var{Q} * @var{R} = @var{A}(:, @var{P})
268@end example
269
270The default, however, is to return a permutation matrix and this may be
271explicitly specified by using a final argument of @qcode{"matrix"}.
272
273If the final argument is the scalar 0 an @qcode{"economy"} factorization is
274returned. If the original matrix @var{A} has size MxN and M > N, then the
275@qcode{"economy"} factorization will calculate just N rows in @var{R} and N
276columns in @var{Q} and omit the zeros in @var{R}. If M @leq{} N, there is no
277difference between the economy and standard factorizations. When calculating
278an @qcode{"economy"} factorization and @var{A} is dense, the output @var{P} is
279always a vector rather than a matrix. If @var{A} is sparse, output
280@var{P} is a sparse permutation matrix.
281
282Background: The QR factorization has applications in the solution of least
283squares problems
284@tex
285$$
286\min_x \left\Vert A x - b \right\Vert_2
287$$
288@end tex
289@ifnottex
290
291@example
292min norm (A*x - b)
293@end example
294
295@end ifnottex
296for overdetermined systems of equations (i.e.,
297@tex
298$A$
299@end tex
300@ifnottex
301@var{A}
302@end ifnottex
303is a tall, thin matrix).
304
305The permuted QR@tie{}factorization
306@code{[@var{Q}, @var{R}, @var{P}] = qr (@var{A})} allows the construction of an
307orthogonal basis of @code{span (A)}.
308
309@seealso{chol, hess, lu, qz, schur, svd, qrupdate, qrinsert, qrdelete, qrshift}
310@end deftypefn */)
311{
312 int nargin = args.length ();
313
314 if (nargin < 1 || nargin > 3)
315 print_usage ();
316
317 octave_value_list retval;
318
319 octave_value arg = args(0);
320
321 bool economy = false;
322 bool is_cmplx = false;
323 bool have_b = 0;
324 bool vector_p = 0;
325
326 if (arg.iscomplex ())
327 is_cmplx = true;
328 if (nargin > 1)
329 {
330 have_b = true;
331 if (args(nargin-1).is_scalar_type ())
332 {
333 int val = args(nargin-1).int_value ();
334 if (val == 0)
335 {
336 economy = true;
337 have_b = (nargin > 2);
338 }
339 else if (nargin == 3) // argument 3 should be 0 or a string
340 print_usage ();
341 }
342 else if (args(nargin-1).is_string ())
343 {
344 std::string str = args(nargin-1).string_value ();
345 if (str == "vector")
346 vector_p = true;
347 else if (str != "matrix")
348 error ("qr: type for P must be 'matrix' or 'vector', not %s",
349 str.c_str ());
350 have_b = (nargin > 2);
351 }
352 else if (! args(nargin-1).is_matrix_type ())
353 err_wrong_type_arg ("qr", args(nargin-1));
354 else if (nargin == 3) // should be caught by is_scalar_type or is_string
355 print_usage ();
356
357 if (have_b && args(1).iscomplex ())
358 is_cmplx = true;
359 }
360
361 if (arg.issparse ())
362 {
363 if (nargout > 3)
364 error ("qr: too many output arguments");
365
366 if (is_cmplx)
367 {
368 if (have_b && nargout == 1)
369 {
370 octave_idx_type info;
371
372 if (! args(1).issparse () && args(1).iscomplex ())
373 retval = ovl
374 (math::sparse_qr<SparseComplexMatrix>::solve
377 args(1).complex_matrix_value (), info));
378 else if (args(1).issparse () && args(1).iscomplex ())
379 retval = ovl
380 (math::sparse_qr<SparseComplexMatrix>::solve
383 args(1).sparse_complex_matrix_value (), info));
384 else if (! args(1).issparse () && ! args(1).iscomplex ())
385 retval = ovl
386 (math::sparse_qr<SparseComplexMatrix>::solve
389 args(1).matrix_value (), info));
390 else if (args(1).issparse () && ! args(1).iscomplex ())
391 retval = ovl
392 (math::sparse_qr<SparseComplexMatrix>::solve
395 args(1).sparse_matrix_value (), info));
396 else
397 error ("qr: b is not valid");
398 }
399 else if (have_b && nargout == 2)
400 {
401 math::sparse_qr<SparseComplexMatrix>
402 q (arg.sparse_complex_matrix_value (), 0);
403 retval = ovl (q.C (args(1).complex_matrix_value (), economy),
404 q.R (economy));
405 }
406 else if (have_b && nargout == 3)
407 {
408 math::sparse_qr<SparseComplexMatrix>
410 if (vector_p)
411 retval = ovl (q.C (args(1).complex_matrix_value (), economy),
412 q.R (economy), q.E ());
413 else
414 retval = ovl (q.C (args(1).complex_matrix_value (), economy),
415 q.R (economy), q.E_MAT ());
416 }
417 else
418 {
419 if (nargout > 2)
420 {
421 math::sparse_qr<SparseComplexMatrix>
423 if (vector_p)
424 retval = ovl (q.Q (economy), q.R (economy), q.E ());
425 else
426 retval = ovl (q.Q (economy), q.R (economy),
427 q.E_MAT ());
428 }
429 else if (nargout > 1)
430 {
431 math::sparse_qr<SparseComplexMatrix>
432 q (arg.sparse_complex_matrix_value (), 0);
433 retval = ovl (q.Q (economy), q.R (economy));
434 }
435 else
436 {
437 math::sparse_qr<SparseComplexMatrix>
438 q (arg.sparse_complex_matrix_value (), 0);
439 retval = ovl (q.R (economy));
440 }
441 }
442 }
443 else
444 {
445 if (have_b && nargout == 1)
446 {
447 octave_idx_type info;
448 if (args(1).issparse () && ! args(1).iscomplex ())
449 retval = ovl (math::sparse_qr<SparseMatrix>::solve
451 (arg.sparse_matrix_value (),
452 args (1).sparse_matrix_value (), info));
453 else if (! args(1).issparse () && args(1).iscomplex ())
454 retval = ovl (math::sparse_qr<SparseMatrix>::solve
456 (arg.sparse_matrix_value (),
457 args (1).complex_matrix_value (), info));
458 else if (! args(1).issparse () && ! args(1).iscomplex ())
459 retval = ovl (math::sparse_qr<SparseMatrix>::solve
461 (arg.sparse_matrix_value (),
462 args (1).matrix_value (), info));
463 else if (args(1).issparse () && args(1).iscomplex ())
464 retval = ovl (math::sparse_qr<SparseMatrix>::solve
466 (arg.sparse_matrix_value (),
467 args(1).sparse_complex_matrix_value (),
468 info));
469 else
470 error ("qr: b is not valid");
471 }
472 else if (have_b && nargout == 2)
473 {
474 math::sparse_qr<SparseMatrix>
475 q (arg.sparse_matrix_value (), 0);
476 retval = ovl (q.C (args(1).matrix_value (), economy),
477 q.R (economy));
478 }
479 else if (have_b && nargout == 3)
480 {
481 math::sparse_qr<SparseMatrix>
482 q (arg.sparse_matrix_value ());
483 if (vector_p)
484 retval = ovl (q.C (args(1).matrix_value (), economy),
485 q.R (economy), q.E ());
486 else
487 retval = ovl (q.C (args(1).matrix_value (), economy),
488 q.R (economy), q.E_MAT ());
489 }
490
491 else
492 {
493 if (nargout > 2)
494 {
495 math::sparse_qr<SparseMatrix>
496 q (arg.sparse_matrix_value ());
497 if (vector_p)
498 retval = ovl (q.Q (economy), q.R (economy), q.E ());
499 else
500 retval = ovl (q.Q (economy), q.R (economy),
501 q.E_MAT ());
502 }
503 else if (nargout > 1)
504 {
505 math::sparse_qr<SparseMatrix>
506 q (arg.sparse_matrix_value (), 0);
507 retval = ovl (q.Q (economy), q.R (economy));
508 }
509 else
510 {
511 math::sparse_qr<SparseMatrix>
512 q (arg.sparse_matrix_value (), 0);
513 retval = ovl (q.R (economy));
514 }
515 }
516 }
517 }
518 else
519 {
520 if (have_b && nargout > 2)
521 error ("qr: too many output arguments for dense A with B");
522
523 if (arg.is_single_type ())
524 {
525 if (arg.isreal ())
526 {
527 math::qr<FloatMatrix>::type type
528 = qr_type<FloatMatrix> (nargout, economy);
529
531
532 switch (nargout)
533 {
534 case 0:
535 case 1:
536 {
537 math::qr<FloatMatrix> fact (m, type);
538 retval = ovl (fact.R ());
539 }
540 break;
541
542 case 2:
543 {
544 math::qr<FloatMatrix> fact (m, type);
545 retval = ovl (fact.Q (), get_qr_r (fact));
546 if (have_b)
547 {
548 if (is_cmplx)
549 retval(0) = fact.Q ().transpose ()
550 * args(1).float_complex_matrix_value ();
551 else
552 retval(0) = fact.Q ().transpose ()
553 * args(1).float_matrix_value ();
554 }
555 }
556 break;
557
558 default:
559 {
560 math::qrp<FloatMatrix> fact (m, type);
561
562 if (economy || vector_p)
563 retval = ovl (fact.Q (), get_qr_r (fact), fact.Pvec ());
564 else
565 retval = ovl (fact.Q (), get_qr_r (fact), fact.P ());
566 }
567 break;
568 }
569 }
570 else if (arg.iscomplex ())
571 {
572 math::qr<FloatComplexMatrix>::type type
573 = qr_type<FloatComplexMatrix> (nargout, economy);
574
576
577 switch (nargout)
578 {
579 case 0:
580 case 1:
581 {
582 math::qr<FloatComplexMatrix> fact (m, type);
583 retval = ovl (fact.R ());
584 }
585 break;
586
587 case 2:
588 {
589 math::qr<FloatComplexMatrix> fact (m, type);
590 retval = ovl (fact.Q (), get_qr_r (fact));
591 if (have_b)
592 retval(0) = conj (fact.Q ().transpose ())
593 * args(1).float_complex_matrix_value ();
594 }
595 break;
596
597 default:
598 {
599 math::qrp<FloatComplexMatrix> fact (m, type);
600 if (economy || vector_p)
601 retval = ovl (fact.Q (), get_qr_r (fact), fact.Pvec ());
602 else
603 retval = ovl (fact.Q (), get_qr_r (fact), fact.P ());
604 }
605 break;
606 }
607 }
608 }
609 else
610 {
611 if (arg.isreal ())
612 {
613 math::qr<Matrix>::type type
614 = qr_type<Matrix> (nargout, economy);
615
616 Matrix m = arg.matrix_value ();
617
618 switch (nargout)
619 {
620 case 0:
621 case 1:
622 {
623 math::qr<Matrix> fact (m, type);
624 retval = ovl (fact.R ());
625 }
626 break;
627
628 case 2:
629 {
630 math::qr<Matrix> fact (m, type);
631 retval = ovl (fact.Q (), get_qr_r (fact));
632 if (have_b)
633 {
634 if (is_cmplx)
635 retval(0) = fact.Q ().transpose ()
636 * args(1).complex_matrix_value ();
637 else
638 retval(0) = fact.Q ().transpose ()
639 * args(1).matrix_value ();
640 }
641 }
642 break;
643
644 default:
645 {
646 math::qrp<Matrix> fact (m, type);
647 if (economy || vector_p)
648 retval = ovl (fact.Q (), get_qr_r (fact), fact.Pvec ());
649 else
650 retval = ovl (fact.Q (), get_qr_r (fact), fact.P ());
651 }
652 break;
653 }
654 }
655 else if (arg.iscomplex ())
656 {
657 math::qr<ComplexMatrix>::type type
658 = qr_type<ComplexMatrix> (nargout, economy);
659
661
662 switch (nargout)
663 {
664 case 0:
665 case 1:
666 {
667 math::qr<ComplexMatrix> fact (m, type);
668 retval = ovl (fact.R ());
669 }
670 break;
671
672 case 2:
673 {
674 math::qr<ComplexMatrix> fact (m, type);
675 retval = ovl (fact.Q (), get_qr_r (fact));
676 if (have_b)
677 retval(0) = conj (fact.Q ().transpose ())
678 * args(1).complex_matrix_value ();
679 }
680 break;
681
682 default:
683 {
684 math::qrp<ComplexMatrix> fact (m, type);
685 if (economy || vector_p)
686 retval = ovl (fact.Q (), get_qr_r (fact), fact.Pvec ());
687 else
688 retval = ovl (fact.Q (), get_qr_r (fact), fact.P ());
689 }
690 break;
691 }
692 }
693 else
694 err_wrong_type_arg ("qr", arg);
695 }
696 }
697
698 return retval;
699}
700
701/*
702%!test
703%! a = [0, 2, 1; 2, 1, 2];
704%!
705%! [q, r] = qr (a);
706%! [qe, re] = qr (a, 0);
707%!
708%! assert (q * r, a, sqrt (eps));
709%! assert (qe * re, a, sqrt (eps));
710
711%!test
712%! a = [0, 2, 1; 2, 1, 2];
713%!
714%! [q, r] = qr (a);
715%! [qe, re] = qr (a, 0);
716%!
717%! assert (q * r, a, sqrt (eps));
718%! assert (qe * re, a, sqrt (eps));
719
720%!test
721%! a = [0, 2, 1; 2, 1, 2];
722%!
723%! [q, r, p] = qr (a); # FIXME: not giving right dimensions.
724%! [qe, re, pe] = qr (a, 0);
725%!
726%! assert (q * r, a * p, sqrt (eps));
727%! assert (qe * re, a(:, pe), sqrt (eps));
728
729%!test
730%! a = [0, 2; 2, 1; 1, 2];
731%!
732%! [q, r] = qr (a);
733%! [qe, re] = qr (a, 0);
734%!
735%! assert (q * r, a, sqrt (eps));
736%! assert (qe * re, a, sqrt (eps));
737
738%!test
739%! a = [0, 2; 2, 1; 1, 2];
740%!
741%! [q, r, p] = qr (a);
742%! [qe, re, pe] = qr (a, 0);
743%!
744%! assert (q * r, a * p, sqrt (eps));
745%! assert (qe * re, a(:, pe), sqrt (eps));
746
747%!test
748%! a = [0, 2, 1; 2, 1, 2; 3, 1, 2];
749%! b = [1, 3, 2; 1, 1, 0; 3, 0, 2];
750%!
751%! [q, r] = qr (a);
752%! [c, re] = qr (a, b);
753%!
754%! assert (r, re, sqrt (eps));
755%! assert (q'*b, c, sqrt (eps));
756
757%!test
758%! a = [0, 2, i; 2, 1, 2; 3, 1, 2];
759%! b = [1, 3, 2; 1, i, 0; 3, 0, 2];
760%!
761%! [q, r] = qr (a);
762%! [c, re] = qr (a, b);
763%!
764%! assert (r, re, sqrt (eps));
765%! assert (q'*b, c, sqrt (eps));
766
767%!test
768%! a = [0, 2, i; 2, 1, 2; 3, 1, 2];
769%! b = [1, 3, 2; 1, 1, 0; 3, 0, 2];
770%!
771%! [q, r] = qr (a);
772%! [c, re] = qr (a, b);
773%!
774%! assert (r, re, sqrt (eps));
775%! assert (q'*b, c, sqrt (eps));
776
777%!test
778%! a = [0, 2, 1; 2, 1, 2; 3, 1, 2];
779%! b = [1, 3, 2; 1, i, 0; 3, 0, 2];
780%!
781%! [q, r] = qr (a);
782%! [c, re] = qr (a, b);
783%!
784%! assert (r, re, sqrt (eps));
785%! assert (q'*b, c, sqrt (eps));
786
787%!test
788%! assert (qr (zeros (0, 0)), zeros (0, 0))
789%! assert (qr (zeros (1, 0)), zeros (1, 0))
790%! assert (qr (zeros (0, 1)), zeros (0, 1))
791
792%!error qr ()
793%!error qr ([1, 2; 3, 4], 0, 2)
794%!error <too many output arguments for dense A with B>
795%! [q, r, p] = qr (rand (3, 2), rand (3, 1));
796%!error <too many output arguments for dense A with B>
797%! [q, r, p] = qr (rand (3, 2), rand (3, 1), 0);
798
799%!function retval = __testqr (q, r, a, p)
800%! tol = 100*eps (class (q));
801%! retval = 0;
802%! if (nargin == 3)
803%! n1 = norm (q*r - a);
804%! n2 = norm (q'*q - eye (columns (q)));
805%! retval = (n1 < tol && n2 < tol);
806%! else
807%! n1 = norm (q'*q - eye (columns (q)));
808%! retval = (n1 < tol);
809%! if (isvector (p))
810%! n2 = norm (q*r - a(:,p));
811%! retval = (retval && n2 < tol);
812%! else
813%! n2 = norm (q*r - a*p);
814%! retval = (retval && n2 < tol);
815%! endif
816%! endif
817%!endfunction
818
819%!test
820%! t = ones (24, 1);
821%! j = 1;
822%!
823%! if (false) # eliminate big matrix tests
824%! a = rand (5000, 20);
825%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a);
826%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a');
827%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p);
828%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p);
829%!
830%! a = a+1i*eps;
831%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a);
832%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a');
833%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p);
834%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p);
835%! endif
836%!
837%! a = [ ones(1,15); sqrt(eps)*eye(15) ];
838%! [q,r] = qr (a); t(j++) = __testqr (q, r, a);
839%! [q,r] = qr (a'); t(j++) = __testqr (q, r, a');
840%! [q,r,p] = qr (a); t(j++) = __testqr (q, r, a, p);
841%! [q,r,p] = qr (a'); t(j++) = __testqr (q, r, a', p);
842%!
843%! a = a+1i*eps;
844%! [q,r] = qr (a); t(j++) = __testqr (q, r, a);
845%! [q,r] = qr (a'); t(j++) = __testqr (q, r, a');
846%! [q,r,p] = qr (a); t(j++) = __testqr (q, r, a, p);
847%! [q,r,p] = qr (a'); t(j++) = __testqr (q, r, a', p);
848%!
849%! a = [ ones(1,15); sqrt(eps)*eye(15) ];
850%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a);
851%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a');
852%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p);
853%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p);
854%!
855%! a = a+1i*eps;
856%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a);
857%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a');
858%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p);
859%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p);
860%!
861%! a = [ 611 196 -192 407 -8 -52 -49 29
862%! 196 899 113 -192 -71 -43 -8 -44
863%! -192 113 899 196 61 49 8 52
864%! 407 -192 196 611 8 44 59 -23
865%! -8 -71 61 8 411 -599 208 208
866%! -52 -43 49 44 -599 411 208 208
867%! -49 -8 8 59 208 208 99 -911
868%! 29 -44 52 -23 208 208 -911 99 ];
869%! [q,r] = qr (a);
870%!
871%! assert (all (t) && norm (q*r - a) < 5000*eps);
872
873%!test
874%! a = single ([0, 2, 1; 2, 1, 2]);
875%!
876%! [q, r] = qr (a);
877%! [qe, re] = qr (a, 0);
878%!
879%! assert (q * r, a, sqrt (eps ("single")));
880%! assert (qe * re, a, sqrt (eps ("single")));
881
882%!test
883%! a = single ([0, 2, 1; 2, 1, 2]);
884%!
885%! [q, r, p] = qr (a); # FIXME: not giving right dimensions.
886%! [qe, re, pe] = qr (a, 0);
887%!
888%! assert (q * r, a * p, sqrt (eps ("single")));
889%! assert (qe * re, a(:, pe), sqrt (eps ("single")));
890
891%!test
892%! a = single ([0, 2; 2, 1; 1, 2]);
893%!
894%! [q, r] = qr (a);
895%! [qe, re] = qr (a, 0);
896%!
897%! assert (q * r, a, sqrt (eps ("single")));
898%! assert (qe * re, a, sqrt (eps ("single")));
899
900%!test
901%! a = single ([0, 2; 2, 1; 1, 2]);
902%!
903%! [q, r, p] = qr (a);
904%! [qe, re, pe] = qr (a, 0);
905%!
906%! assert (q * r, a * p, sqrt (eps ("single")));
907%! assert (qe * re, a(:, pe), sqrt (eps ("single")));
908
909%!test
910%! a = single ([0, 2, 1; 2, 1, 2; 3, 1, 2]);
911%! b = single ([1, 3, 2; 1, 1, 0; 3, 0, 2]);
912%!
913%! [q, r] = qr (a);
914%! [c, re] = qr (a, b);
915%!
916%! assert (r, re, sqrt (eps ("single")));
917%! assert (q'*b, c, sqrt (eps ("single")));
918
919%!test
920%! a = single ([0, 2, i; 2, 1, 2; 3, 1, 2]);
921%! b = single ([1, 3, 2; 1, i, 0; 3, 0, 2]);
922%!
923%! [q, r] = qr (a);
924%! [c, re] = qr (a, b);
925%!
926%! assert (r, re, sqrt (eps ("single")));
927%! assert (q'*b, c, sqrt (eps ("single")));
928
929%!test
930%! a = single ([0, 2, i; 2, 1, 2; 3, 1, 2]);
931%! b = single ([1, 3, 2; 1, 1, 0; 3, 0, 2]);
932%!
933%! [q, r] = qr (a);
934%! [c, re] = qr (a, b);
935%!
936%! assert (r, re, sqrt (eps));
937%! assert (q'*b, c, sqrt (eps));
938
939%!test
940%! a = single ([0, 2, 1; 2, 1, 2; 3, 1, 2]);
941%! b = single ([1, 3, 2; 1, i, 0; 3, 0, 2]);
942%!
943%! [q, r] = qr (a);
944%! [c, re] = qr (a, b);
945%!
946%! assert (r, re, sqrt (eps ("single")));
947%! assert (q'*b, c, sqrt (eps ("single")));
948
949%!test
950%! t = ones (24, 1);
951%! j = 1;
952%!
953%! if (false) # eliminate big matrix tests
954%! a = rand (5000,20);
955%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a);
956%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a');
957%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p);
958%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p);
959%!
960%! a = a+1i*eps ("single");
961%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a);
962%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a');
963%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p);
964%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p);
965%! endif
966%!
967%! a = [ ones(1,15); sqrt(eps("single"))*eye(15) ];
968%! [q,r] = qr (a); t(j++) = __testqr (q, r, a);
969%! [q,r] = qr (a'); t(j++) = __testqr (q, r, a');
970%! [q,r,p] = qr (a); t(j++) = __testqr (q, r, a, p);
971%! [q,r,p] = qr (a'); t(j++) = __testqr (q, r, a', p);
972%!
973%! a = a+1i*eps ("single");
974%! [q,r] = qr (a); t(j++) = __testqr (q, r, a);
975%! [q,r] = qr (a'); t(j++) = __testqr (q, r, a');
976%! [q,r,p] = qr (a); t(j++) = __testqr (q, r, a, p);
977%! [q,r,p] = qr (a'); t(j++) = __testqr (q, r, a', p);
978%!
979%! a = [ ones(1,15); sqrt(eps("single"))*eye(15) ];
980%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a);
981%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a');
982%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p);
983%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p);
984%!
985%! a = a+1i*eps ("single");
986%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a);
987%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a');
988%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p);
989%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a',p);
990%!
991%! a = [ 611 196 -192 407 -8 -52 -49 29
992%! 196 899 113 -192 -71 -43 -8 -44
993%! -192 113 899 196 61 49 8 52
994%! 407 -192 196 611 8 44 59 -23
995%! -8 -71 61 8 411 -599 208 208
996%! -52 -43 49 44 -599 411 208 208
997%! -49 -8 8 59 208 208 99 -911
998%! 29 -44 52 -23 208 208 -911 99 ];
999%! [q,r] = qr (a);
1000%!
1001%! assert (all (t) && norm (q*r-a) < 5000*eps ("single"));
1002
1003## The deactivated tests below can't be tested till rectangular back-subs is
1004## implemented for sparse matrices.
1005
1006%!testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
1007%! n = 20; d = 0.2;
1008%! ## initialize generators to make behavior reproducible
1009%! rand ("state", 42);
1010%! randn ("state", 42);
1011%! a = sprandn (n,n,d) + speye (n,n);
1012%! r = qr (a);
1013%! assert (r'*r, a'*a, 1e-10);
1014
1015%!testif HAVE_COLAMD; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
1016%! n = 20; d = 0.2;
1017%! ## initialize generators to make behavior reproducible
1018%! rand ("state", 42);
1019%! randn ("state", 42);
1020%! a = sprandn (n,n,d) + speye (n,n);
1021%! q = symamd (a);
1022%! a = a(q,q);
1023%! r = qr (a);
1024%! assert (r'*r, a'*a, 1e-10);
1025
1026%!testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
1027%! n = 20; d = 0.2;
1028%! ## initialize generators to make behavior reproducible
1029%! rand ("state", 42);
1030%! randn ("state", 42);
1031%! a = sprandn (n,n,d) + speye (n,n);
1032%! [c,r] = qr (a, ones (n,1));
1033%! assert (r\c, full (a)\ones (n,1), 10e-10);
1034
1035%!testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
1036%! n = 20; d = 0.2;
1037%! ## initialize generators to make behavior reproducible
1038%! rand ("state", 42);
1039%! randn ("state", 42);
1040%! a = sprandn (n,n,d) + speye (n,n);
1041%! b = randn (n,2);
1042%! [c,r] = qr (a, b);
1043%! assert (r\c, full (a)\b, 10e-10);
1044
1045## Test under-determined systems!!
1046%!#testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
1047%! n = 20; d = 0.2;
1048%! ## initialize generators to make behavior reproducible
1049%! rand ("state", 42);
1050%! randn ("state", 42);
1051%! a = sprandn (n,n+1,d) + speye (n,n+1);
1052%! b = randn (n,2);
1053%! [c,r] = qr (a, b);
1054%! assert (r\c, full (a)\b, 10e-10);
1055
1056%!testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
1057%! n = 20; d = 0.2;
1058%! ## initialize generators to make behavior reproducible
1059%! rand ("state", 42);
1060%! randn ("state", 42);
1061%! a = 1i*sprandn (n,n,d) + speye (n,n);
1062%! r = qr (a);
1063%! assert (r'*r,a'*a,1e-10);
1064
1065%!testif HAVE_COLAMD; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
1066%! n = 20; d = 0.2;
1067%! ## initialize generators to make behavior reproducible
1068%! rand ("state", 42);
1069%! randn ("state", 42);
1070%! a = 1i*sprandn (n,n,d) + speye (n,n);
1071%! q = symamd (a);
1072%! a = a(q,q);
1073%! r = qr (a);
1074%! assert (r'*r, a'*a, 1e-10);
1075
1076%!testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
1077%! n = 20; d = 0.2;
1078%! ## initialize generators to make behavior reproducible
1079%! rand ("state", 42);
1080%! randn ("state", 42);
1081%! a = 1i*sprandn (n,n,d) + speye (n,n);
1082%! [c,r] = qr (a, ones (n,1));
1083%! assert (r\c, full (a)\ones (n,1), 10e-10);
1084
1085%!testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
1086%! n = 20; d = 0.2;
1087%! ## initialize generators to make behavior reproducible
1088%! rand ("state", 42);
1089%! randn ("state", 42);
1090%! a = 1i*sprandn (n,n,d) + speye (n,n);
1091%! b = randn (n,2);
1092%! [c,r] = qr (a, b);
1093%! assert (r\c, full (a)\b, 10e-10);
1094
1095## Test under-determined systems!!
1096%!#testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
1097%! n = 20; d = 0.2;
1098%! ## initialize generators to make behavior reproducible
1099%! rand ("state", 42);
1100%! randn ("state", 42);
1101%! a = 1i*sprandn (n,n+1,d) + speye (n,n+1);
1102%! b = randn (n, 2);
1103%! [c, r] = qr (a, b);
1104%! assert (r\c, full (a)\b, 10e-10);
1105
1106%!testif HAVE_SPQR, HAVE_CHOLMOD
1107%! n = 12; m = 20; d = 0.2;
1108%! ## initialize generators to make behavior reproducible
1109%! rand ("state", 42);
1110%! randn ("state", 42);
1111%! a = sprandn (m, n, d);
1112%! b = randn (m, 2);
1113%! [c, r] = qr (a, b);
1114%! assert (r\c, full (a)\b, 10e-10);
1115
1116%!testif HAVE_SPQR, HAVE_CHOLMOD
1117%! n = 12; m = 20; d = 0.2;
1118%! ## initialize generators to make behavior reproducible
1119%! rand ("state", 42);
1120%! randn ("state", 42);
1121%! a = sprandn (m, n, d);
1122%! b = sprandn (m, 2, d);
1123%! [c, r] = qr (a, b, 0);
1124%! [c2, r2] = qr (full (a), full (b), 0);
1125%! assert (r\c, r2\c2, 10e-10);
1126
1127%!testif HAVE_SPQR, HAVE_CHOLMOD
1128%! n = 12; m = 20; d = 0.2;
1129%! ## initialize generators to make behavior reproducible
1130%! rand ("state", 42);
1131%! randn ("state", 42);
1132%! a = sprandn (m, n, d);
1133%! b = randn (m, 2);
1134%! [c, r, p] = qr (a, b, "matrix");
1135%! x = p * (r\c);
1136%! [c2, r2] = qr (full (a), b);
1137%! x2 = r2 \ c2;
1138%! assert (x, x2, 10e-10);
1139
1140%!testif HAVE_SPQR, HAVE_CHOLMOD
1141%! n = 12; m = 20; d = 0.2;
1142%! ## initialize generators to make behavior reproducible
1143%! rand ("state", 42);
1144%! randn ("state", 42);
1145%! a = sprandn (m, n, d);
1146%! [q, r, p] = qr (a, "matrix");
1147%! assert (q * r, a * p, 10e-10);
1148
1149%!testif HAVE_SPQR, HAVE_CHOLMOD
1150%! n = 12; m = 20; d = 0.2;
1151%! ## initialize generators to make behavior reproducible
1152%! rand ("state", 42);
1153%! randn ("state", 42);
1154%! a = sprandn (m, n, d);
1155%! b = randn (m, 2);
1156%! x = qr (a, b);
1157%! [c2, r2] = qr (full (a), b);
1158%! assert (x, r2\c2, 10e-10);
1159
1160%!testif HAVE_SPQR, HAVE_CHOLMOD
1161%! n = 12; m = 20; d = 0.2;
1162%! ## initialize generators to make behavior reproducible
1163%! rand ("state", 42);
1164%! randn ("state", 42);
1165%! a = sprandn (m, n, d);
1166%! b = i * randn (m, 2);
1167%! x = qr (a, b);
1168%! [c2, r2] = qr (full (a), b);
1169%! assert (x, r2\c2, 10e-10);
1170
1171%!#testif HAVE_SPQR, HAVE_CHOLMOD
1172%! n = 12; m = 20; d = 0.2;
1173%! ## initialize generators to make behavior reproducible
1174%! rand ("state", 42);
1175%! randn ("state", 42);
1176%! a = sprandn (m, n, d);
1177%! b = i * randn (m, 2);
1178%! [c, r] = qr (a, b);
1179%! [c2, r2] = qr (full (a), b);
1180%! assert (r\c, r2\c2, 10e-10);
1181
1182%!testif HAVE_SPQR, HAVE_CHOLMOD
1183%! n = 12; m = 20; d = 0.2;
1184%! ## initialize generators to make behavior reproducible
1185%! rand ("state", 42);
1186%! randn ("state", 42);
1187%! a = sprandn (m, n, d);
1188%! b = i * randn (m, 2);
1189%! [c, r, p] = qr (a, b, "matrix");
1190%! x = p * (r\c);
1191%! [c2, r2] = qr (full (a), b);
1192%! x2 = r2 \ c2;
1193%! assert (x, x2, 10e-10);
1194
1195%!testif HAVE_SPQR, HAVE_CHOLMOD
1196%! n = 12; m = 20; d = 0.2;
1197%! ## initialize generators to make behavior reproducible
1198%! rand ("state", 42);
1199%! randn ("state", 42);
1200%! a = i * sprandn (m, n, d);
1201%! b = sprandn (m, 2, d);
1202%! [c, r] = qr (a, b, 0);
1203%! [c2, r2] = qr (full (a), full (b), 0);
1204%! assert (r\c, r2\c2, 10e-10);
1205
1206%!testif HAVE_SPQR, HAVE_CHOLMOD
1207%! n = 12; m = 20; d = 0.2;
1208%! ## initialize generators to make behavior reproducible
1209%! rand ("state", 42);
1210%! randn ("state", 42);
1211%! a = i * sprandn (m, n, d);
1212%! b = randn (m, 2);
1213%! [c, r, p] = qr (a, b, "matrix");
1214%! x = p * (r\c);
1215%! [c2, r2] = qr (full (a), b);
1216%! x2 = r2 \ c2;
1217%! assert(x, x2, 10e-10);
1218
1219%!testif HAVE_SPQR, HAVE_CHOLMOD
1220%! n = 12; m = 20; d = 0.2;
1221%! ## initialize generators to make behavior reproducible
1222%! rand ("state", 42);
1223%! randn ("state", 42);
1224%! a = i * sprandn (m, n, d);
1225%! [q, r, p] = qr (a, "matrix");
1226%! assert(q * r, a * p, 10e-10);
1227
1228%!testif HAVE_SPQR, HAVE_CHOLMOD
1229%! n = 12; m = 20; d = 0.2;
1230%! ## initialize generators to make behavior reproducible
1231%! rand ("state", 42);
1232%! randn ("state", 42);
1233%! a = i * sprandn (m, n, d);
1234%! b = randn (m, 2);
1235%! x = qr (a, b);
1236%! [c2, r2] = qr (full (a), b);
1237%! assert (x, r2\c2, 10e-10);
1238
1239%!testif HAVE_SPQR, HAVE_CHOLMOD
1240%! a = sparse (5, 6);
1241%! a(3,1) = 0.8;
1242%! a(2,2) = 1.4;
1243%! a(1,6) = -0.5;
1244%! r = qr (a);
1245%! assert (r'*r, a'*a, 10e-10);
1246*/
1247
1248static
1249bool check_qr_dims (const octave_value& q, const octave_value& r,
1250 bool allow_ecf = false)
1251{
1252 octave_idx_type m = q.rows ();
1253 octave_idx_type k = r.rows ();
1254 octave_idx_type n = r.columns ();
1255 return ((q.ndims () == 2 && r.ndims () == 2 && k == q.columns ())
1256 && (m == k || (allow_ecf && k == n && k < m)));
1257}
1258
1259static
1260bool check_index (const octave_value& i, bool vector_allowed = false)
1261{
1262 return ((i.isreal () || i.isinteger ())
1263 && (i.is_scalar_type () || vector_allowed));
1264}
1265
1266DEFUN (qrupdate, args, ,
1267 doc: /* -*- texinfo -*-
1268@deftypefn {} {[@var{Q1}, @var{R1}] =} qrupdate (@var{Q}, @var{R}, @var{u}, @var{v})
1269Update a QR factorization given update vectors or matrices.
1270
1271Given a QR@tie{}factorization of a real or complex matrix
1272@w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and
1273@var{R}@tie{}upper trapezoidal, return the QR@tie{}factorization of
1274@w{@var{A} + @var{u}*@var{v}'}, where @var{u} and @var{v} are column vectors
1275(rank-1 update) or matrices with equal number of columns
1276(rank-k update). Notice that the latter case is done as a sequence of
1277rank-1 updates; thus, for k large enough, it will be both faster and more
1278accurate to recompute the factorization from scratch.
1279
1280The QR@tie{}factorization supplied may be either full (Q is square) or
1281economized (R is square).
1282
1283@seealso{qr, qrinsert, qrdelete, qrshift}
1284@end deftypefn */)
1285{
1286 octave_value_list retval;
1287
1288 if (args.length () != 4)
1289 print_usage ();
1290
1291 octave_value argq = args(0);
1292 octave_value argr = args(1);
1293 octave_value argu = args(2);
1294 octave_value argv = args(3);
1295
1296 if (! argq.isnumeric () || ! argr.isnumeric ()
1297 || ! argu.isnumeric () || ! argv.isnumeric ())
1298 print_usage ();
1299
1300 if (! check_qr_dims (argq, argr, true))
1301 error ("qrupdate: Q and R dimensions don't match");
1302
1303 if (argq.isreal () && argr.isreal () && argu.isreal ()
1304 && argv.isreal ())
1305 {
1306 // all real case
1307 if (argq.is_single_type () || argr.is_single_type ()
1308 || argu.is_single_type () || argv.is_single_type ())
1309 {
1311 FloatMatrix R = argr.float_matrix_value ();
1312 FloatMatrix u = argu.float_matrix_value ();
1313 FloatMatrix v = argv.float_matrix_value ();
1314
1315 math::qr<FloatMatrix> fact (Q, R);
1316 fact.update (u, v);
1317
1318 retval = ovl (fact.Q (), get_qr_r (fact));
1319 }
1320 else
1321 {
1322 Matrix Q = argq.matrix_value ();
1323 Matrix R = argr.matrix_value ();
1324 Matrix u = argu.matrix_value ();
1325 Matrix v = argv.matrix_value ();
1326
1327 math::qr<Matrix> fact (Q, R);
1328 fact.update (u, v);
1329
1330 retval = ovl (fact.Q (), get_qr_r (fact));
1331 }
1332 }
1333 else
1334 {
1335 // complex case
1336 if (argq.is_single_type () || argr.is_single_type ()
1337 || argu.is_single_type () || argv.is_single_type ())
1338 {
1343
1344 math::qr<FloatComplexMatrix> fact (Q, R);
1345 fact.update (u, v);
1346
1347 retval = ovl (fact.Q (), get_qr_r (fact));
1348 }
1349 else
1350 {
1355
1356 math::qr<ComplexMatrix> fact (Q, R);
1357 fact.update (u, v);
1358
1359 retval = ovl (fact.Q (), get_qr_r (fact));
1360 }
1361 }
1362
1363 return retval;
1364}
1365
1366/*
1367%!shared A, u, v, Ac, uc, vc
1368%! A = [0.091364 0.613038 0.999083;
1369%! 0.594638 0.425302 0.603537;
1370%! 0.383594 0.291238 0.085574;
1371%! 0.265712 0.268003 0.238409;
1372%! 0.669966 0.743851 0.445057 ];
1373%!
1374%! u = [0.85082;
1375%! 0.76426;
1376%! 0.42883;
1377%! 0.53010;
1378%! 0.80683 ];
1379%!
1380%! v = [0.98810;
1381%! 0.24295;
1382%! 0.43167 ];
1383%!
1384%! Ac = [0.620405 + 0.956953i 0.480013 + 0.048806i 0.402627 + 0.338171i;
1385%! 0.589077 + 0.658457i 0.013205 + 0.279323i 0.229284 + 0.721929i;
1386%! 0.092758 + 0.345687i 0.928679 + 0.241052i 0.764536 + 0.832406i;
1387%! 0.912098 + 0.721024i 0.049018 + 0.269452i 0.730029 + 0.796517i;
1388%! 0.112849 + 0.603871i 0.486352 + 0.142337i 0.355646 + 0.151496i ];
1389%!
1390%! uc = [0.20351 + 0.05401i;
1391%! 0.13141 + 0.43708i;
1392%! 0.29808 + 0.08789i;
1393%! 0.69821 + 0.38844i;
1394%! 0.74871 + 0.25821i ];
1395%!
1396%! vc = [0.85839 + 0.29468i;
1397%! 0.20820 + 0.93090i;
1398%! 0.86184 + 0.34689i ];
1399%!
1400
1401%!test
1402%! [Q,R] = qr (A);
1403%! [Q,R] = qrupdate (Q, R, u, v);
1404%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 1e1*eps);
1405%! assert (norm (vec (triu (R)-R), Inf) == 0);
1406%! assert (norm (vec (Q*R - A - u*v'), Inf) < norm (A)*1e1*eps);
1407%!
1408%!test
1409%! [Q,R] = qr (Ac);
1410%! [Q,R] = qrupdate (Q, R, uc, vc);
1411%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 1e1*eps);
1412%! assert (norm (vec (triu (R)-R), Inf) == 0);
1413%! assert (norm (vec (Q*R - Ac - uc*vc'), Inf) < norm (Ac)*1e1*eps);
1414
1415%!test
1416%! [Q,R] = qr (single (A));
1417%! [Q,R] = qrupdate (Q, R, single (u), single (v));
1418%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single"));
1419%! assert (norm (vec (triu (R)-R), Inf) == 0);
1420%! assert (norm (vec (Q*R - single (A) - single (u)*single (v)'), Inf) < norm (single (A))*1e1*eps ("single"));
1421%!
1422%!test
1423%! [Q,R] = qr (single (Ac));
1424%! [Q,R] = qrupdate (Q, R, single (uc), single (vc));
1425%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single"));
1426%! assert (norm (vec (triu (R)-R), Inf) == 0);
1427%! assert (norm (vec (Q*R - single (Ac) - single (uc)*single (vc)'), Inf) < norm (single (Ac))*1e1*eps ("single"));
1428*/
1429
1430DEFUN (qrinsert, args, ,
1431 doc: /* -*- texinfo -*-
1432@deftypefn {} {[@var{Q1}, @var{R1}] =} qrinsert (@var{Q}, @var{R}, @var{j}, @var{x}, @var{orient})
1433Update a QR factorization given a row or column to insert in the original
1434factored matrix.
1435
1436
1437Given a QR@tie{}factorization of a real or complex matrix
1438@w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and
1439@var{R}@tie{}upper trapezoidal, return the QR@tie{}factorization of
1440@w{[A(:,1:j-1) x A(:,j:n)]}, where @var{u} is a column vector to be inserted
1441into @var{A} (if @var{orient} is @qcode{"col"}), or the
1442QR@tie{}factorization of @w{[A(1:j-1,:);x;A(:,j:n)]}, where @var{x} is a row
1443vector to be inserted into @var{A} (if @var{orient} is @qcode{"row"}).
1444
1445The default value of @var{orient} is @qcode{"col"}. If @var{orient} is
1446@qcode{"col"}, @var{u} may be a matrix and @var{j} an index vector
1447resulting in the QR@tie{}factorization of a matrix @var{B} such that
1448@w{B(:,@var{j})} gives @var{u} and @w{B(:,@var{j}) = []} gives @var{A}.
1449Notice that the latter case is done as a sequence of k insertions;
1450thus, for k large enough, it will be both faster and more accurate to
1451recompute the factorization from scratch.
1452
1453If @var{orient} is @qcode{"col"}, the QR@tie{}factorization supplied may
1454be either full (Q is square) or economized (R is square).
1455
1456If @var{orient} is @qcode{"row"}, full factorization is needed.
1457@seealso{qr, qrupdate, qrdelete, qrshift}
1458@end deftypefn */)
1459{
1460 int nargin = args.length ();
1461
1462 if (nargin < 4 || nargin > 5)
1463 print_usage ();
1464
1465 octave_value argq = args(0);
1466 octave_value argr = args(1);
1467 octave_value argj = args(2);
1468 octave_value argx = args(3);
1469
1470 if (! argq.isnumeric () || ! argr.isnumeric ()
1471 || ! argx.isnumeric ()
1472 || (nargin > 4 && ! args(4).is_string ()))
1473 print_usage ();
1474
1475 std::string orient = (nargin < 5) ? "col" : args(4).string_value ();
1476 bool col = (orient == "col");
1477
1478 if (! col && orient != "row")
1479 error (R"(qrinsert: ORIENT must be "col" or "row")");
1480
1481 if (! check_qr_dims (argq, argr, col) || (! col && argx.rows () != 1))
1482 error ("qrinsert: dimension mismatch");
1483
1484 if (! check_index (argj, col))
1485 error ("qrinsert: invalid index J");
1486
1487 octave_value_list retval;
1488
1490
1491 octave_idx_type one = 1;
1492
1493 if (argq.isreal () && argr.isreal () && argx.isreal ())
1494 {
1495 // real case
1496 if (argq.is_single_type () || argr.is_single_type ()
1497 || argx.is_single_type ())
1498 {
1500 FloatMatrix R = argr.float_matrix_value ();
1502
1503 math::qr<FloatMatrix> fact (Q, R);
1504
1505 if (col)
1506 fact.insert_col (x, j-one);
1507 else
1508 fact.insert_row (x.row (0), j(0)-one);
1509
1510 retval = ovl (fact.Q (), get_qr_r (fact));
1511 }
1512 else
1513 {
1514 Matrix Q = argq.matrix_value ();
1515 Matrix R = argr.matrix_value ();
1516 Matrix x = argx.matrix_value ();
1517
1518 math::qr<Matrix> fact (Q, R);
1519
1520 if (col)
1521 fact.insert_col (x, j-one);
1522 else
1523 fact.insert_row (x.row (0), j(0)-one);
1524
1525 retval = ovl (fact.Q (), get_qr_r (fact));
1526 }
1527 }
1528 else
1529 {
1530 // complex case
1531 if (argq.is_single_type () || argr.is_single_type ()
1532 || argx.is_single_type ())
1533 {
1537
1538 math::qr<FloatComplexMatrix> fact (Q, R);
1539
1540 if (col)
1541 fact.insert_col (x, j-one);
1542 else
1543 fact.insert_row (x.row (0), j(0)-one);
1544
1545 retval = ovl (fact.Q (), get_qr_r (fact));
1546 }
1547 else
1548 {
1552
1553 math::qr<ComplexMatrix> fact (Q, R);
1554
1555 if (col)
1556 fact.insert_col (x, j-one);
1557 else
1558 fact.insert_row (x.row (0), j(0)-one);
1559
1560 retval = ovl (fact.Q (), get_qr_r (fact));
1561 }
1562 }
1563
1564 return retval;
1565}
1566
1567/*
1568%!test
1569%! [Q,R] = qr (A);
1570%! [Q,R] = qrinsert (Q, R, 3, u);
1571%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 1e1*eps);
1572%! assert (norm (vec (triu (R) - R), Inf) == 0);
1573%! assert (norm (vec (Q*R - [A(:,1:2) u A(:,3)]), Inf) < norm (A)*1e1*eps);
1574%!test
1575%! [Q,R] = qr (Ac);
1576%! [Q,R] = qrinsert (Q, R, 3, uc);
1577%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 1e1*eps);
1578%! assert (norm (vec (triu (R) - R), Inf) == 0);
1579%! assert (norm (vec (Q*R - [Ac(:,1:2) uc Ac(:,3)]), Inf) < norm (Ac)*1e1*eps);
1580%!test
1581%! x = [0.85082 0.76426 0.42883 ];
1582%!
1583%! [Q,R] = qr (A);
1584%! [Q,R] = qrinsert (Q, R, 3, x, "row");
1585%! assert (norm (vec (Q'*Q - eye (6)), Inf) < 1e1*eps);
1586%! assert (norm (vec (triu (R) - R), Inf) == 0);
1587%! assert (norm (vec (Q*R - [A(1:2,:);x;A(3:5,:)]), Inf) < norm (A)*1e1*eps);
1588%!test
1589%! x = [0.20351 + 0.05401i 0.13141 + 0.43708i 0.29808 + 0.08789i ];
1590%!
1591%! [Q,R] = qr (Ac);
1592%! [Q,R] = qrinsert (Q, R, 3, x, "row");
1593%! assert (norm (vec (Q'*Q - eye (6)), Inf) < 1e1*eps);
1594%! assert (norm (vec (triu (R) - R), Inf) == 0);
1595%! assert (norm (vec (Q*R - [Ac(1:2,:);x;Ac(3:5,:)]), Inf) < norm (Ac)*1e1*eps);
1596
1597%!test
1598%! [Q,R] = qr (single (A));
1599%! [Q,R] = qrinsert (Q, R, 3, single (u));
1600%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single"));
1601%! assert (norm (vec (triu (R) - R), Inf) == 0);
1602%! assert (norm (vec (Q*R - single ([A(:,1:2) u A(:,3)])), Inf) < norm (single (A))*1e1*eps ("single"));
1603%!test
1604%! [Q,R] = qr (single (Ac));
1605%! [Q,R] = qrinsert (Q, R, 3, single (uc));
1606%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single"));
1607%! assert (norm (vec (triu (R) - R), Inf) == 0);
1608%! assert (norm (vec (Q*R - single ([Ac(:,1:2) uc Ac(:,3)])), Inf) < norm (single (Ac))*1e1*eps ("single"));
1609%!test
1610%! x = single ([0.85082 0.76426 0.42883 ]);
1611%!
1612%! [Q,R] = qr (single (A));
1613%! [Q,R] = qrinsert (Q, R, 3, x, "row");
1614%! assert (norm (vec (Q'*Q - eye (6,"single")), Inf) < 1e1*eps ("single"));
1615%! assert (norm (vec (triu (R) - R), Inf) == 0);
1616%! assert (norm (vec (Q*R - single ([A(1:2,:);x;A(3:5,:)])), Inf) < norm (single (A))*1e1*eps ("single"));
1617%!test
1618%! x = single ([0.20351 + 0.05401i 0.13141 + 0.43708i 0.29808 + 0.08789i ]);
1619%!
1620%! [Q,R] = qr (single (Ac));
1621%! [Q,R] = qrinsert (Q, R, 3, x, "row");
1622%! assert (norm (vec (Q'*Q - eye (6,"single")), Inf) < 1e1*eps ("single"));
1623%! assert (norm (vec (triu (R) - R), Inf) == 0);
1624%! assert (norm (vec (Q*R - single ([Ac(1:2,:);x;Ac(3:5,:)])), Inf) < norm (single (Ac))*1e1*eps ("single"));
1625*/
1626
1627DEFUN (qrdelete, args, ,
1628 doc: /* -*- texinfo -*-
1629@deftypefn {} {[@var{Q1}, @var{R1}] =} qrdelete (@var{Q}, @var{R}, @var{j}, @var{orient})
1630Update a QR factorization given a row or column to delete from the original
1631factored matrix.
1632
1633Given a QR@tie{}factorization of a real or complex matrix
1634@w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and
1635@var{R}@tie{}upper trapezoidal, return the QR@tie{}factorization of
1636@w{[A(:,1:j-1), U, A(:,j:n)]},
1637where @var{u} is a column vector to be inserted into @var{A}
1638(if @var{orient} is @qcode{"col"}),
1639or the QR@tie{}factorization of @w{[A(1:j-1,:);X;A(:,j:n)]},
1640where @var{x} is a row @var{orient} is @qcode{"row"}).
1641The default value of @var{orient} is @qcode{"col"}.
1642
1643If @var{orient} is @qcode{"col"}, @var{j} may be an index vector
1644resulting in the QR@tie{}factorization of a matrix @var{B} such that
1645@w{A(:,@var{j}) = []} gives @var{B}. Notice that the latter case is done as
1646a sequence of k deletions; thus, for k large enough, it will be both faster
1647and more accurate to recompute the factorization from scratch.
1648
1649If @var{orient} is @qcode{"col"}, the QR@tie{}factorization supplied may
1650be either full (Q is square) or economized (R is square).
1651
1652If @var{orient} is @qcode{"row"}, full factorization is needed.
1653@seealso{qr, qrupdate, qrinsert, qrshift}
1654@end deftypefn */)
1655{
1656 int nargin = args.length ();
1657
1658 if (nargin < 3 || nargin > 4)
1659 print_usage ();
1660
1661 octave_value argq = args(0);
1662 octave_value argr = args(1);
1663 octave_value argj = args(2);
1664
1665 if (! argq.isnumeric () || ! argr.isnumeric ()
1666 || (nargin > 3 && ! args(3).is_string ()))
1667 print_usage ();
1668
1669 std::string orient = (nargin < 4) ? "col" : args(3).string_value ();
1670 bool col = orient == "col";
1671
1672 if (! col && orient != "row")
1673 error (R"(qrdelete: ORIENT must be "col" or "row")");
1674
1675 if (! check_qr_dims (argq, argr, col))
1676 error ("qrdelete: dimension mismatch");
1677
1679 if (! check_index (argj, col))
1680 error ("qrdelete: invalid index J");
1681
1682 octave_value_list retval;
1683
1684 octave_idx_type one = 1;
1685
1686 if (argq.isreal () && argr.isreal ())
1687 {
1688 // real case
1689 if (argq.is_single_type () || argr.is_single_type ())
1690 {
1692 FloatMatrix R = argr.float_matrix_value ();
1693
1694 math::qr<FloatMatrix> fact (Q, R);
1695
1696 if (col)
1697 fact.delete_col (j-one);
1698 else
1699 fact.delete_row (j(0)-one);
1700
1701 retval = ovl (fact.Q (), get_qr_r (fact));
1702 }
1703 else
1704 {
1705 Matrix Q = argq.matrix_value ();
1706 Matrix R = argr.matrix_value ();
1707
1708 math::qr<Matrix> fact (Q, R);
1709
1710 if (col)
1711 fact.delete_col (j-one);
1712 else
1713 fact.delete_row (j(0)-one);
1714
1715 retval = ovl (fact.Q (), get_qr_r (fact));
1716 }
1717 }
1718 else
1719 {
1720 // complex case
1721 if (argq.is_single_type () || argr.is_single_type ())
1722 {
1725
1726 math::qr<FloatComplexMatrix> fact (Q, R);
1727
1728 if (col)
1729 fact.delete_col (j-one);
1730 else
1731 fact.delete_row (j(0)-one);
1732
1733 retval = ovl (fact.Q (), get_qr_r (fact));
1734 }
1735 else
1736 {
1739
1740 math::qr<ComplexMatrix> fact (Q, R);
1741
1742 if (col)
1743 fact.delete_col (j-one);
1744 else
1745 fact.delete_row (j(0)-one);
1746
1747 retval = ovl (fact.Q (), get_qr_r (fact));
1748 }
1749 }
1750
1751 return retval;
1752}
1753
1754/*
1755%!test
1756%! AA = [0.091364 0.613038 0.027504 0.999083;
1757%! 0.594638 0.425302 0.562834 0.603537;
1758%! 0.383594 0.291238 0.742073 0.085574;
1759%! 0.265712 0.268003 0.783553 0.238409;
1760%! 0.669966 0.743851 0.457255 0.445057 ];
1761%!
1762%! [Q,R] = qr (AA);
1763%! [Q,R] = qrdelete (Q, R, 3);
1764%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 16*eps);
1765%! assert (norm (vec (triu (R) - R), Inf) == 0);
1766%! assert (norm (vec (Q*R - [AA(:,1:2) AA(:,4)]), Inf) < norm (AA)*1e1*eps);
1767%!
1768%!test
1769%! AA = [0.364554 + 0.993117i 0.669818 + 0.510234i 0.426568 + 0.041337i 0.847051 + 0.233291i;
1770%! 0.049600 + 0.242783i 0.448946 + 0.484022i 0.141155 + 0.074420i 0.446746 + 0.392706i;
1771%! 0.581922 + 0.657416i 0.581460 + 0.030016i 0.219909 + 0.447288i 0.201144 + 0.069132i;
1772%! 0.694986 + 0.000571i 0.682327 + 0.841712i 0.807537 + 0.166086i 0.192767 + 0.358098i;
1773%! 0.945002 + 0.066788i 0.350492 + 0.642638i 0.579629 + 0.048102i 0.600170 + 0.636938i ] * I;
1774%!
1775%! [Q,R] = qr (AA);
1776%! [Q,R] = qrdelete (Q, R, 3);
1777%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 16*eps);
1778%! assert (norm (vec (triu (R) - R), Inf) == 0);
1779%! assert (norm (vec (Q*R - [AA(:,1:2) AA(:,4)]), Inf) < norm (AA)*1e1*eps);
1780%!
1781%!test
1782%! AA = [0.091364 0.613038 0.027504 0.999083;
1783%! 0.594638 0.425302 0.562834 0.603537;
1784%! 0.383594 0.291238 0.742073 0.085574;
1785%! 0.265712 0.268003 0.783553 0.238409;
1786%! 0.669966 0.743851 0.457255 0.445057 ];
1787%!
1788%! [Q,R] = qr (AA);
1789%! [Q,R] = qrdelete (Q, R, 3, "row");
1790%! assert (norm (vec (Q'*Q - eye (4)), Inf) < 1e1*eps);
1791%! assert (norm (vec (triu (R) - R), Inf) == 0);
1792%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps);
1793%!
1794%!test
1795%! AA = [0.364554 + 0.993117i 0.669818 + 0.510234i 0.426568 + 0.041337i 0.847051 + 0.233291i;
1796%! 0.049600 + 0.242783i 0.448946 + 0.484022i 0.141155 + 0.074420i 0.446746 + 0.392706i;
1797%! 0.581922 + 0.657416i 0.581460 + 0.030016i 0.219909 + 0.447288i 0.201144 + 0.069132i;
1798%! 0.694986 + 0.000571i 0.682327 + 0.841712i 0.807537 + 0.166086i 0.192767 + 0.358098i;
1799%! 0.945002 + 0.066788i 0.350492 + 0.642638i 0.579629 + 0.048102i 0.600170 + 0.636938i ] * I;
1800%!
1801%! [Q,R] = qr (AA);
1802%! [Q,R] = qrdelete (Q, R, 3, "row");
1803%! assert (norm (vec (Q'*Q - eye (4)), Inf) < 1e1*eps);
1804%! assert (norm (vec (triu (R) - R), Inf) == 0);
1805%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps);
1806
1807%!test
1808%! AA = single ([0.091364 0.613038 0.027504 0.999083;
1809%! 0.594638 0.425302 0.562834 0.603537;
1810%! 0.383594 0.291238 0.742073 0.085574;
1811%! 0.265712 0.268003 0.783553 0.238409;
1812%! 0.669966 0.743851 0.457255 0.445057 ]);
1813%!
1814%! [Q,R] = qr (AA);
1815%! [Q,R] = qrdelete (Q, R, 3);
1816%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single"));
1817%! assert (norm (vec (triu (R) - R), Inf) == 0);
1818%! assert (norm (vec (Q*R - [AA(:,1:2) AA(:,4)]), Inf) < norm (AA)*1e1*eps ("single"));
1819%!
1820%!test
1821%! AA = single ([0.364554 + 0.993117i 0.669818 + 0.510234i 0.426568 + 0.041337i 0.847051 + 0.233291i;
1822%! 0.049600 + 0.242783i 0.448946 + 0.484022i 0.141155 + 0.074420i 0.446746 + 0.392706i;
1823%! 0.581922 + 0.657416i 0.581460 + 0.030016i 0.219909 + 0.447288i 0.201144 + 0.069132i;
1824%! 0.694986 + 0.000571i 0.682327 + 0.841712i 0.807537 + 0.166086i 0.192767 + 0.358098i;
1825%! 0.945002 + 0.066788i 0.350492 + 0.642638i 0.579629 + 0.048102i 0.600170 + 0.636938i ]) * I;
1826%!
1827%! [Q,R] = qr (AA);
1828%! [Q,R] = qrdelete (Q, R, 3);
1829%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single"));
1830%! assert (norm (vec (triu (R) - R), Inf) == 0);
1831%! assert (norm (vec (Q*R - [AA(:,1:2) AA(:,4)]), Inf) < norm (AA)*1e1*eps ("single"));
1832%!
1833%!test
1834%! AA = single ([0.091364 0.613038 0.027504 0.999083;
1835%! 0.594638 0.425302 0.562834 0.603537;
1836%! 0.383594 0.291238 0.742073 0.085574;
1837%! 0.265712 0.268003 0.783553 0.238409;
1838%! 0.669966 0.743851 0.457255 0.445057 ]);
1839%!
1840%! [Q,R] = qr (AA);
1841%! [Q,R] = qrdelete (Q, R, 3, "row");
1842%! assert (norm (vec (Q'*Q - eye (4,"single")), Inf) < 1.5e1*eps ("single"));
1843%! assert (norm (vec (triu (R) - R), Inf) == 0);
1844%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps ("single"));
1845%!testif HAVE_QRUPDATE
1846%! ## Same test as above but with more precicision
1847%! AA = single ([0.091364 0.613038 0.027504 0.999083;
1848%! 0.594638 0.425302 0.562834 0.603537;
1849%! 0.383594 0.291238 0.742073 0.085574;
1850%! 0.265712 0.268003 0.783553 0.238409;
1851%! 0.669966 0.743851 0.457255 0.445057 ]);
1852%!
1853%! [Q,R] = qr (AA);
1854%! [Q,R] = qrdelete (Q, R, 3, "row");
1855%! assert (norm (vec (Q'*Q - eye (4,"single")), Inf) < 1e1*eps ("single"));
1856%! assert (norm (vec (triu (R) - R), Inf) == 0);
1857%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps ("single"));
1858%!
1859%!test
1860%! AA = single ([0.364554 + 0.993117i 0.669818 + 0.510234i 0.426568 + 0.041337i 0.847051 + 0.233291i;
1861%! 0.049600 + 0.242783i 0.448946 + 0.484022i 0.141155 + 0.074420i 0.446746 + 0.392706i;
1862%! 0.581922 + 0.657416i 0.581460 + 0.030016i 0.219909 + 0.447288i 0.201144 + 0.069132i;
1863%! 0.694986 + 0.000571i 0.682327 + 0.841712i 0.807537 + 0.166086i 0.192767 + 0.358098i;
1864%! 0.945002 + 0.066788i 0.350492 + 0.642638i 0.579629 + 0.048102i 0.600170 + 0.636938i ]) * I;
1865%!
1866%! [Q,R] = qr (AA);
1867%! [Q,R] = qrdelete (Q, R, 3, "row");
1868%! assert (norm (vec (Q'*Q - eye (4,"single")), Inf) < 1e1*eps ("single"));
1869%! assert (norm (vec (triu (R) - R), Inf) == 0);
1870%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps ("single"));
1871*/
1872
1873DEFUN (qrshift, args, ,
1874 doc: /* -*- texinfo -*-
1875@deftypefn {} {[@var{Q1}, @var{R1}] =} qrshift (@var{Q}, @var{R}, @var{i}, @var{j})
1876Update a QR factorization given a range of columns to shift in the original
1877factored matrix.
1878
1879Given a QR@tie{}factorization of a real or complex matrix
1880@w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and
1881@var{R}@tie{}upper trapezoidal, return the QR@tie{}factorization
1882of @w{@var{A}(:,p)}, where @w{p} is the permutation @*
1883@code{p = [1:i-1, shift(i:j, 1), j+1:n]} if @w{@var{i} < @var{j}} @*
1884 or @*
1885@code{p = [1:j-1, shift(j:i,-1), i+1:n]} if @w{@var{j} < @var{i}}. @*
1886
1887@seealso{qr, qrupdate, qrinsert, qrdelete}
1888@end deftypefn */)
1889{
1890 if (args.length () != 4)
1891 print_usage ();
1892
1893 octave_value argq = args(0);
1894 octave_value argr = args(1);
1895 octave_value argi = args(2);
1896 octave_value argj = args(3);
1897
1898 if (! argq.isnumeric () || ! argr.isnumeric ())
1899 print_usage ();
1900
1901 if (! check_qr_dims (argq, argr, true))
1902 error ("qrshift: dimensions mismatch");
1903
1904 octave_idx_type i = argi.idx_type_value ();
1905 octave_idx_type j = argj.idx_type_value ();
1906
1907 if (! check_index (argi) || ! check_index (argj))
1908 error ("qrshift: invalid index I or J");
1909
1910 octave_value_list retval;
1911
1912 if (argq.isreal () && argr.isreal ())
1913 {
1914 // all real case
1915 if (argq.is_single_type ()
1916 && argr.is_single_type ())
1917 {
1919 FloatMatrix R = argr.float_matrix_value ();
1920
1921 math::qr<FloatMatrix> fact (Q, R);
1922 fact.shift_cols (i-1, j-1);
1923
1924 retval = ovl (fact.Q (), get_qr_r (fact));
1925 }
1926 else
1927 {
1928 Matrix Q = argq.matrix_value ();
1929 Matrix R = argr.matrix_value ();
1930
1931 math::qr<Matrix> fact (Q, R);
1932 fact.shift_cols (i-1, j-1);
1933
1934 retval = ovl (fact.Q (), get_qr_r (fact));
1935 }
1936 }
1937 else
1938 {
1939 // complex case
1940 if (argq.is_single_type ()
1941 && argr.is_single_type ())
1942 {
1945
1946 math::qr<FloatComplexMatrix> fact (Q, R);
1947 fact.shift_cols (i-1, j-1);
1948
1949 retval = ovl (fact.Q (), get_qr_r (fact));
1950 }
1951 else
1952 {
1955
1956 math::qr<ComplexMatrix> fact (Q, R);
1957 fact.shift_cols (i-1, j-1);
1958
1959 retval = ovl (fact.Q (), get_qr_r (fact));
1960 }
1961 }
1962
1963 return retval;
1964}
1965
1966/*
1967%!test
1968%! AA = A.';
1969%! i = 2; j = 4; p = [1:i-1, shift(i:j,-1), j+1:5];
1970%!
1971%! [Q,R] = qr (AA);
1972%! [Q,R] = qrshift (Q, R, i, j);
1973%! assert (norm (vec (Q'*Q - eye (3)), Inf) < 1e1*eps);
1974%! assert (norm (vec (triu (R) - R), Inf) == 0);
1975%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps);
1976%!
1977%! j = 2; i = 4; p = [1:j-1, shift(j:i,+1), i+1:5];
1978%!
1979%! [Q,R] = qr (AA);
1980%! [Q,R] = qrshift (Q, R, i, j);
1981%! assert (norm (vec (Q'*Q - eye (3)), Inf) < 1e1*eps);
1982%! assert (norm (vec (triu (R) - R), Inf) == 0);
1983%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps);
1984%!
1985%!test
1986%! AA = Ac.';
1987%! i = 2; j = 4; p = [1:i-1, shift(i:j,-1), j+1:5];
1988%!
1989%! [Q,R] = qr (AA);
1990%! [Q,R] = qrshift (Q, R, i, j);
1991%! assert (norm (vec (Q'*Q - eye (3)), Inf) < 1e1*eps);
1992%! assert (norm (vec (triu (R) - R), Inf) == 0);
1993%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps);
1994%!
1995%! j = 2; i = 4; p = [1:j-1, shift(j:i,+1), i+1:5];
1996%!
1997%! [Q,R] = qr (AA);
1998%! [Q,R] = qrshift (Q, R, i, j);
1999%! assert (norm (vec (Q'*Q - eye (3)), Inf) < 1e1*eps);
2000%! assert (norm (vec (triu (R) - R), Inf) == 0);
2001%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps);
2002
2003%!test
2004%! AA = single (A).';
2005%! i = 2; j = 4; p = [1:i-1, shift(i:j,-1), j+1:5];
2006%!
2007%! [Q,R] = qr (AA);
2008%! [Q,R] = qrshift (Q, R, i, j);
2009%! assert (norm (vec (Q'*Q - eye (3,"single")), Inf) < 1e1*eps ("single"));
2010%! assert (norm (vec (triu (R) - R), Inf) == 0);
2011%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps ("single"));
2012%!
2013%! j = 2; i = 4; p = [1:j-1, shift(j:i,+1), i+1:5];
2014%!
2015%! [Q,R] = qr (AA);
2016%! [Q,R] = qrshift (Q, R, i, j);
2017%! assert (norm (vec (Q'*Q - eye (3,"single")), Inf) < 1e1*eps ("single"));
2018%! assert (norm (vec (triu (R) - R), Inf) == 0);
2019%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps ("single"));
2020%!
2021%!test
2022%! AA = single (Ac).';
2023%! i = 2; j = 4; p = [1:i-1, shift(i:j,-1), j+1:5];
2024%!
2025%! [Q,R] = qr (AA);
2026%! [Q,R] = qrshift (Q, R, i, j);
2027%! assert (norm (vec (Q'*Q - eye (3,"single")), Inf) < 1e1*eps ("single"));
2028%! assert (norm (vec (triu (R) - R), Inf) == 0);
2029%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps ("single"));
2030%!
2031%! j = 2; i = 4; p = [1:j-1, shift(j:i,+1), i+1:5];
2032%!
2033%! [Q,R] = qr (AA);
2034%! [Q,R] = qrshift (Q, R, i, j);
2035%! assert (norm (vec (Q'*Q - eye (3,"single")), Inf) < 1e1*eps ("single"));
2036%! assert (norm (vec (triu (R) - R), Inf) == 0);
2037%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps ("single"));
2038*/
2039
2040OCTAVE_NAMESPACE_END
ComplexColumnVector conj(const ComplexColumnVector &a)
Definition: CColVector.cc:217
Definition: dMatrix.h:42
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
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 idx_type_value(bool req_int=false, bool frc_str_conv=false) const
bool is_scalar_type(void) const
Definition: ov.h:789
bool isinteger(void) const
Definition: ov.h:775
octave_idx_type columns(void) const
Definition: ov.h:592
int ndims(void) const
Definition: ov.h:596
OCTINTERP_API Array< octave_idx_type > octave_idx_type_vector_value(bool req_int=false, bool frc_str_conv=false, bool frc_vec_conv=false) const
FloatMatrix float_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:901
bool is_single_type(void) const
Definition: ov.h:743
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:898
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
Definition: mx-defs.h:53
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 error(const char *fmt,...)
Definition: error.cc:980
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:166
static OCTAVE_NAMESPACE_BEGIN octave_value get_qr_r(const math::qr< MT > &fact)
Definition: qr.cc:63
static bool check_index(const octave_value &i, bool vector_allowed=false)
Definition: qr.cc:1260
static bool check_qr_dims(const octave_value &q, const octave_value &r, bool allow_ecf=false)
Definition: qr.cc:1249
static math::qr< T >::type qr_type(int nargout, bool economy)
Definition: qr.cc:74
F77_RET_T const F77_INT const F77_INT const F77_INT F77_DBLE const F77_INT F77_DBLE const F77_INT F77_DBLE * Q
F77_RET_T const F77_DBLE * x
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