GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
chol.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2017 John W. Eaton
4 Copyright (C) 2008-2009 Jaroslav Hajek
5 Copyright (C) 2008-2009 VZLU Prague
6 
7 This file is part of Octave.
8 
9 Octave is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13 
14 Octave is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Octave; see the file COPYING. If not, see
21 <http://www.gnu.org/licenses/>.
22 
23 */
24 
25 #if defined (HAVE_CONFIG_H)
26 # include "config.h"
27 #endif
28 
29 #include <string>
30 
31 #include "chol.h"
32 #include "sparse-chol.h"
33 #include "oct-spparms.h"
34 #include "sparse-util.h"
35 
36 #include "ov-re-sparse.h"
37 #include "ov-cx-sparse.h"
38 #include "defun-dld.h"
39 #include "error.h"
40 #include "errwarn.h"
41 #include "ovl.h"
42 
43 #include "oct-string.h"
44 
45 template <typename CHOLT>
46 static octave_value
47 get_chol (const CHOLT& fact)
48 {
49  return octave_value (fact.chol_matrix());
50 }
51 
52 template <typename CHOLT>
53 static octave_value
54 get_chol_r (const CHOLT& fact)
55 {
56  return octave_value (fact.chol_matrix (),
58 }
59 
60 template <typename CHOLT>
61 static octave_value
62 get_chol_l (const CHOLT& fact)
63 {
64  return octave_value (fact.chol_matrix ().transpose (),
66 }
67 
69  doc: /* -*- texinfo -*-
70 @deftypefn {} {@var{R} =} chol (@var{A})
71 @deftypefnx {} {[@var{R}, @var{p}] =} chol (@var{A})
72 @deftypefnx {} {[@var{R}, @var{p}, @var{Q}] =} chol (@var{A})
73 @deftypefnx {} {[@var{R}, @var{p}, @var{Q}] =} chol (@var{A}, "vector")
74 @deftypefnx {} {[@var{L}, @dots{}] =} chol (@dots{}, "lower")
75 @deftypefnx {} {[@var{R}, @dots{}] =} chol (@dots{}, "upper")
76 @cindex Cholesky factorization
77 Compute the upper Cholesky@tie{}factor, @var{R}, of the real symmetric
78 or complex Hermitian positive definite matrix @var{A}.
79 
80 The upper Cholesky@tie{}factor @var{R} is computed by using the upper
81 triangular part of matrix @var{A} and is defined by
82 @tex
83 $ R^T R = A $.
84 @end tex
85 @ifnottex
86 
87 @example
88 @var{R}' * @var{R} = @var{A}.
89 @end example
90 
91 @end ifnottex
92 
93 Calling @code{chol} using the optional @qcode{"upper"} flag has the
94 same behavior. In contrast, using the optional @qcode{"lower"} flag,
95 @code{chol} returns the lower triangular factorization, computed by using
96 the lower triangular part of matrix @var{A}, such that
97 @tex
98 $ L L^T = A $.
99 @end tex
100 @ifnottex
101 
102 @example
103 @var{L} * @var{L}' = @var{A}.
104 @end example
105 
106 @end ifnottex
107 
108 Called with one output argument @code{chol} fails if matrix @var{A} is
109 not positive definite. Note that if matrix @var{A} is not real symmetric
110 or complex Hermitian then the lower triangular part is considered to be
111 the (complex conjugate) transpose of the upper triangular part, or vice
112 versa, given the @qcode{"lower"} flag.
113 
114 Called with two or more output arguments @var{p} flags whether the matrix
115 @var{A} was positive definite and @code{chol} does not fail. A zero value
116 of @var{p} indicates that matrix @var{A} is positive definite and @var{R}
117 gives the factorization. Otherwise, @var{p} will have a positive value.
118 
119 If called with three output arguments matrix @var{A} must be sparse and
120 a sparsity preserving row/column permutation is applied to matrix @var{A}
121 prior to the factorization. That is @var{R} is the factorization of
122 @code{@var{A}(@var{Q},@var{Q})} such that
123 @tex
124 $ R^T R = Q^T A Q$.
125 @end tex
126 @ifnottex
127 
128 @example
129 @var{R}' * @var{R} = @var{Q}' * @var{A} * @var{Q}.
130 @end example
131 
132 @end ifnottex
133 
134 The sparsity preserving permutation is generally returned as a matrix.
135 However, given the optional flag @qcode{"vector"}, @var{Q} will be
136 returned as a vector such that
137 @tex
138 $ R^T R = A (Q, Q)$.
139 @end tex
140 @ifnottex
141 
142 @example
143 @var{R}' * @var{R} = @var{A}(@var{Q}, @var{Q}).
144 @end example
145 
146 @end ifnottex
147 
148 In general the lower triangular factorization is significantly faster for
149 sparse matrices.
150 @seealso{hess, lu, qr, qz, schur, svd, ichol, cholinv, chol2inv, cholupdate, cholinsert, choldelete, cholshift}
151 @end deftypefn */)
152 {
153  int nargin = args.length ();
154 
155  if (nargin < 1 || nargin > 3 || nargout > 3)
156  print_usage ();
157  if (nargout > 2 && ! args(0).is_sparse_type ())
158  error ("chol: using three output arguments, matrix A must be sparse");
159 
160  bool LLt = false;
161  bool vecout = false;
162 
163  int n = 1;
164  while (n < nargin)
165  {
166  std::string tmp = args(n++).xstring_value ("chol: optional arguments must be strings");
167 
168  if (octave::string::strcmpi (tmp, "vector"))
169  vecout = true;
170  else if (octave::string::strcmpi (tmp, "lower"))
171  LLt = true;
172  else if (octave::string::strcmpi (tmp, "upper"))
173  LLt = false;
174  else
175  error ("chol: optional argument must be one of \"vector\", \"lower\", or \"upper\"");
176  }
177 
179  octave_value arg = args(0);
180 
181  if (arg.is_empty ())
182  return ovl (Matrix ());
183 
184  if (arg.is_sparse_type ())
185  {
186  octave_idx_type info;
187  bool natural = (nargout != 3);
188  bool force = nargout > 1;
189 
190  if (arg.is_real_type ())
191  {
193 
194  octave::math::sparse_chol<SparseMatrix> fact (m, info, natural, force);
195 
196  if (nargout == 3)
197  {
198  if (vecout)
199  retval(2) = fact.perm ();
200  else
201  retval(2) = fact.Q ();
202  }
203 
204  if (nargout >= 2 || info == 0)
205  {
206  retval(1) = info;
207  if (LLt)
208  retval(0) = fact.L ();
209  else
210  retval(0) = fact.R ();
211  }
212  else
213  error ("chol: input matrix must be positive definite");
214  }
215  else if (arg.is_complex_type ())
216  {
218 
219  octave::math::sparse_chol<SparseComplexMatrix> fact (m, info, natural, force);
220 
221  if (nargout == 3)
222  {
223  if (vecout)
224  retval(2) = fact.perm ();
225  else
226  retval(2) = fact.Q ();
227  }
228 
229  if (nargout >= 2 || info == 0)
230  {
231  retval(1) = info;
232  if (LLt)
233  retval(0) = fact.L ();
234  else
235  retval(0) = fact.R ();
236  }
237  else
238  error ("chol: input matrix must be positive definite");
239  }
240  else
241  err_wrong_type_arg ("chol", arg);
242  }
243  else if (arg.is_single_type ())
244  {
245  if (vecout)
246  error ("chol: A must be sparse for the \"vector\" option");
247  if (arg.is_real_type ())
248  {
250 
251  octave_idx_type info;
252 
253  octave::math::chol<FloatMatrix> fact (m, info, LLt != true);
254 
255  if (nargout == 2 || info == 0)
256  retval = ovl (get_chol (fact), info);
257  else
258  error ("chol: input matrix must be positive definite");
259  }
260  else if (arg.is_complex_type ())
261  {
263 
264  octave_idx_type info;
265 
266  octave::math::chol<FloatComplexMatrix> fact (m, info, LLt != true);
267 
268  if (nargout == 2 || info == 0)
269  retval = ovl (get_chol (fact), info);
270  else
271  error ("chol: input matrix must be positive definite");
272  }
273  else
274  err_wrong_type_arg ("chol", arg);
275  }
276  else
277  {
278  if (vecout)
279  error ("chol: A must be sparse for the \"vector\" option");
280  if (arg.is_real_type ())
281  {
282  Matrix m = arg.matrix_value ();
283 
284  octave_idx_type info;
285 
286  octave::math::chol<Matrix> fact (m, info, LLt != true);
287 
288  if (nargout == 2 || info == 0)
289  retval = ovl (get_chol (fact), info);
290  else
291  error ("chol: input matrix must be positive definite");
292  }
293  else if (arg.is_complex_type ())
294  {
296 
297  octave_idx_type info;
298 
299  octave::math::chol<ComplexMatrix> fact (m, info, LLt != true);
300 
301  if (nargout == 2 || info == 0)
302  retval = ovl (get_chol (fact), info);
303  else
304  error ("chol: input matrix must be positive definite");
305  }
306  else
307  err_wrong_type_arg ("chol", arg);
308  }
309 
310  return retval;
311 }
312 
313 /*
314 %!assert (chol ([2, 1; 1, 1]), [sqrt(2), 1/sqrt(2); 0, 1/sqrt(2)], sqrt (eps))
315 %!assert (chol (single ([2, 1; 1, 1])), single ([sqrt(2), 1/sqrt(2); 0, 1/sqrt(2)]), sqrt (eps ("single")))
316 
317 %!assert (chol ([2, 1; 1, 1], "upper"), [sqrt(2), 1/sqrt(2); 0, 1/sqrt(2)],
318 %! sqrt (eps))
319 %!assert (chol ([2, 1; 1, 1], "lower"), [sqrt(2), 0; 1/sqrt(2), 1/sqrt(2)],
320 %! sqrt (eps))
321 
322 %!assert (chol ([2, 1; 1, 1], "lower"), chol ([2, 1; 1, 1], "LoweR"))
323 %!assert (chol ([2, 1; 1, 1], "upper"), chol ([2, 1; 1, 1], "Upper"))
324 
325 ## Check the "vector" option which only affects the 3rd argument and
326 ## is only valid for sparse input.
327 %!testif HAVE_CHOLMOD
328 %! a = sparse ([2 1; 1 1]);
329 %! r = sparse ([sqrt(2), 1/sqrt(2); 0, 1/sqrt(2)]);
330 %! [rd, pd, qd] = chol (a);
331 %! [rv, pv, qv] = chol (a, "vector");
332 %! assert (r, rd, eps)
333 %! assert (r, rv, eps)
334 %! assert (pd, 0)
335 %! assert (pd, pv)
336 %! assert (qd, sparse (eye (2)))
337 %! assert (qv, [1 2])
338 %!
339 %! [rv, pv, qv] = chol (a, "Vector"); # check case sensitivity
340 %! assert (r, rv, eps)
341 %! assert (pd, pv)
342 %! assert (qv, [1 2])
343 
344 %!testif HAVE_CHOLMOD <42587>
345 %! A = sparse ([1 0 8;0 1 8;8 8 1]);
346 %! [Q, p] = chol (A);
347 %! assert (p != 0);
348 
349 %!error chol ()
350 %!error <matrix must be positive definite> chol ([1, 2; 3, 4])
351 %!error <requires square matrix> chol ([1, 2; 3, 4; 5, 6])
352 %!error <optional arguments must be strings> chol (1, 2)
353 %!error <optional argument must be one of "vector", "lower"> chol (1, "foobar")
354 %!error <matrix A must be sparse> [L,p,Q] = chol ([1, 2; 3, 4])
355 %!error <A must be sparse> [L, p] = chol ([1, 2; 3, 4], "vector")
356 */
357 
358 DEFUN_DLD (cholinv, args, ,
359  doc: /* -*- texinfo -*-
360 @deftypefn {} {} cholinv (@var{A})
361 Compute the inverse of the symmetric positive definite matrix @var{A} using
362 the Cholesky@tie{}factorization.
363 @seealso{chol, chol2inv, inv}
364 @end deftypefn */)
365 {
366  if (args.length () != 1)
367  print_usage ();
368 
370  octave_value arg = args(0);
371 
372  octave_idx_type nr = arg.rows ();
373  octave_idx_type nc = arg.columns ();
374 
375  if (nr == 0 || nc == 0)
376  retval = Matrix ();
377  else
378  {
379  if (arg.is_sparse_type ())
380  {
381  octave_idx_type info;
382 
383  if (arg.is_real_type ())
384  {
386 
388 
389  if (info == 0)
390  retval = chol.inverse ();
391  else
392  error ("cholinv: A must be positive definite");
393  }
394  else if (arg.is_complex_type ())
395  {
397 
399 
400  if (info == 0)
401  retval = chol.inverse ();
402  else
403  error ("cholinv: A must be positive definite");
404  }
405  else
406  err_wrong_type_arg ("cholinv", arg);
407  }
408  else if (arg.is_single_type ())
409  {
410  if (arg.is_real_type ())
411  {
412  FloatMatrix m = arg.float_matrix_value ();
413 
414  octave_idx_type info;
416  if (info == 0)
417  retval = chol.inverse ();
418  else
419  error ("cholinv: A must be positive definite");
420  }
421  else if (arg.is_complex_type ())
422  {
424 
425  octave_idx_type info;
427  if (info == 0)
428  retval = chol.inverse ();
429  else
430  error ("cholinv: A must be positive definite");
431  }
432  else
433  err_wrong_type_arg ("chol", arg);
434  }
435  else
436  {
437  if (arg.is_real_type ())
438  {
439  Matrix m = arg.matrix_value ();
440 
441  octave_idx_type info;
443  if (info == 0)
444  retval = chol.inverse ();
445  else
446  error ("cholinv: A must be positive definite");
447  }
448  else if (arg.is_complex_type ())
449  {
451 
452  octave_idx_type info;
454  if (info == 0)
455  retval = chol.inverse ();
456  else
457  error ("cholinv: A must be positive definite");
458  }
459  else
460  err_wrong_type_arg ("chol", arg);
461  }
462  }
463 
464  return retval;
465 }
466 
467 /*
468 %!shared A, Ainv
469 %! A = [2,0.2;0.2,1];
470 %! Ainv = inv (A);
471 %!test
472 %! Ainv1 = cholinv (A);
473 %! assert (norm (Ainv-Ainv1), 0, 1e-10);
474 %!testif HAVE_CHOLMOD
475 %! Ainv2 = inv (sparse (A));
476 %! assert (norm (Ainv-Ainv2), 0, 1e-10);
477 %!testif HAVE_CHOLMOD
478 %! Ainv3 = cholinv (sparse (A));
479 %! assert (norm (Ainv-Ainv3), 0, 1e-10);
480 */
481 
483  doc: /* -*- texinfo -*-
484 @deftypefn {} {} chol2inv (@var{U})
485 Invert a symmetric, positive definite square matrix from its Cholesky
486 decomposition, @var{U}.
487 
488 Note that @var{U} should be an upper-triangular matrix with positive
489 diagonal elements. @code{chol2inv (@var{U})} provides
490 @code{inv (@var{U}'*@var{U})} but it is much faster than using @code{inv}.
491 @seealso{chol, cholinv, inv}
492 @end deftypefn */)
493 {
494  if (args.length () != 1)
495  print_usage ();
496 
498 
499  octave_value arg = args(0);
500 
501  octave_idx_type nr = arg.rows ();
502  octave_idx_type nc = arg.columns ();
503 
504  if (nr == 0 || nc == 0)
505  retval = Matrix ();
506  else
507  {
508  if (arg.is_sparse_type ())
509  {
510  if (arg.is_real_type ())
511  {
513 
514  retval = octave::math::chol2inv (r);
515  }
516  else if (arg.is_complex_type ())
517  {
519 
520  retval = octave::math::chol2inv (r);
521  }
522  else
523  err_wrong_type_arg ("chol2inv", arg);
524  }
525  else if (arg.is_single_type ())
526  {
527  if (arg.is_real_type ())
528  {
529  FloatMatrix r = arg.float_matrix_value ();
530 
531  retval = octave::math::chol2inv (r);
532  }
533  else if (arg.is_complex_type ())
534  {
536 
537  retval = octave::math::chol2inv (r);
538  }
539  else
540  err_wrong_type_arg ("chol2inv", arg);
541 
542  }
543  else
544  {
545  if (arg.is_real_type ())
546  {
547  Matrix r = arg.matrix_value ();
548 
549  retval = octave::math::chol2inv (r);
550  }
551  else if (arg.is_complex_type ())
552  {
554 
555  retval = octave::math::chol2inv (r);
556  }
557  else
558  err_wrong_type_arg ("chol2inv", arg);
559  }
560  }
561 
562  return retval;
563 }
564 
565 /*
566 
567 ## Test for bug #36437
568 %!function sparse_chol2inv (T, tol)
569 %! iT = inv (T);
570 %! ciT = chol2inv (chol (T));
571 %! assert (ciT, iT, tol);
572 %! assert (chol2inv (chol ( full (T))), ciT, tol*2);
573 %!endfunction
574 
575 %!testif HAVE_CHOLMOD
576 %! A = gallery ("poisson", 3);
577 %! sparse_chol2inv (A, eps);
578 
579 %!testif HAVE_CHOLMOD
580 %! n = 10;
581 %! B = spdiags (ones (n, 1) * [1 2 1], [-1 0 1], n, n);
582 %! sparse_chol2inv (B, eps*100);
583 
584 %!testif HAVE_CHOLMOD
585 %! C = gallery("tridiag", 5);
586 %! sparse_chol2inv (C, eps*10);
587 
588 %!testif HAVE_CHOLMOD
589 %! D = gallery("wathen", 1, 1);
590 %! sparse_chol2inv (D, eps*10^4);
591 
592 */
593 
594 DEFUN_DLD (cholupdate, args, nargout,
595  doc: /* -*- texinfo -*-
596 @deftypefn {} {[@var{R1}, @var{info}] =} cholupdate (@var{R}, @var{u}, @var{op})
597 Update or downdate a Cholesky@tie{}factorization.
598 
599 Given an upper triangular matrix @var{R} and a column vector @var{u},
600 attempt to determine another upper triangular matrix @var{R1} such that
601 
602 @itemize @bullet
603 @item
604 @var{R1}'*@var{R1} = @var{R}'*@var{R} + @var{u}*@var{u}'
605 if @var{op} is @qcode{"+"}
606 
607 @item
608 @var{R1}'*@var{R1} = @var{R}'*@var{R} - @var{u}*@var{u}'
609 if @var{op} is @qcode{"-"}
610 @end itemize
611 
612 If @var{op} is @qcode{"-"}, @var{info} is set to
613 
614 @itemize
615 @item 0 if the downdate was successful,
616 
617 @item 1 if @var{R}'*@var{R} - @var{u}*@var{u}' is not positive definite,
618 
619 @item 2 if @var{R} is singular.
620 @end itemize
621 
622 If @var{info} is not present, an error message is printed in cases 1 and 2.
623 @seealso{chol, cholinsert, choldelete, cholshift}
624 @end deftypefn */)
625 {
626  int nargin = args.length ();
627 
628  if (nargin < 2 || nargin > 3)
629  print_usage ();
630 
631  octave_value argr = args(0);
632  octave_value argu = args(1);
633 
634  if (! argr.is_numeric_type () || ! argu.is_numeric_type ()
635  || (nargin > 2 && ! args(2).is_string ()))
636  print_usage ();
637 
638  octave_value_list retval (nargout == 2 ? 2 : 1);
639 
640  octave_idx_type n = argr.rows ();
641 
642  std::string op = (nargin < 3) ? "+" : args(2).string_value ();
643 
644  bool down = (op == "-");
645 
646  if (! down && op != "+")
647  error ("cholupdate: OP must be \"+\" or \"-\"");
648 
649  if (argr.columns () != n || argu.rows () != n || argu.columns () != 1)
650  error ("cholupdate: dimension mismatch between R and U");
651 
652  int err = 0;
653  if (argr.is_single_type () || argu.is_single_type ())
654  {
655  if (argr.is_real_type () && argu.is_real_type ())
656  {
657  // real case
658  FloatMatrix R = argr.float_matrix_value ();
660 
662  fact.set (R);
663 
664  if (down)
665  err = fact.downdate (u);
666  else
667  fact.update (u);
668 
669  retval = ovl (get_chol_r (fact));
670  }
671  else
672  {
673  // complex case
677 
679  fact.set (R);
680 
681  if (down)
682  err = fact.downdate (u);
683  else
684  fact.update (u);
685 
686  retval = ovl (get_chol_r (fact));
687  }
688  }
689  else
690  {
691  if (argr.is_real_type () && argu.is_real_type ())
692  {
693  // real case
694  Matrix R = argr.matrix_value ();
695  ColumnVector u = argu.column_vector_value ();
696 
698  fact.set (R);
699 
700  if (down)
701  err = fact.downdate (u);
702  else
703  fact.update (u);
704 
705  retval = ovl (get_chol_r (fact));
706  }
707  else
708  {
709  // complex case
712 
714  fact.set (R);
715 
716  if (down)
717  err = fact.downdate (u);
718  else
719  fact.update (u);
720 
721  retval = ovl (get_chol_r (fact));
722  }
723  }
724 
725  if (nargout > 1)
726  retval(1) = err;
727  else if (err == 1)
728  error ("cholupdate: downdate violates positiveness");
729  else if (err == 2)
730  error ("cholupdate: singular matrix");
731 
732  return retval;
733 }
734 
735 /*
736 %!shared A, u, Ac, uc
737 %! A = [ 0.436997 -0.131721 0.124120 -0.061673 ;
738 %! -0.131721 0.738529 0.019851 -0.140295 ;
739 %! 0.124120 0.019851 0.354879 -0.059472 ;
740 %! -0.061673 -0.140295 -0.059472 0.600939 ];
741 %!
742 %! u = [ 0.98950 ;
743 %! 0.39844 ;
744 %! 0.63484 ;
745 %! 0.13351 ];
746 %! Ac = [ 0.5585528 + 0.0000000i -0.1662088 - 0.0315341i 0.0107873 + 0.0236411i -0.0276775 - 0.0186073i ;
747 %! -0.1662088 + 0.0315341i 0.6760061 + 0.0000000i 0.0011452 - 0.0475528i 0.0145967 + 0.0247641i ;
748 %! 0.0107873 - 0.0236411i 0.0011452 + 0.0475528i 0.6263149 - 0.0000000i -0.1585837 - 0.0719763i ;
749 %! -0.0276775 + 0.0186073i 0.0145967 - 0.0247641i -0.1585837 + 0.0719763i 0.6034234 - 0.0000000i ];
750 %!
751 %! uc = [ 0.54267 + 0.91519i ;
752 %! 0.99647 + 0.43141i ;
753 %! 0.83760 + 0.68977i ;
754 %! 0.39160 + 0.90378i ];
755 
756 %!test
757 %! R = chol (A);
758 %! R1 = cholupdate (R, u);
759 %! assert (norm (triu (R1)-R1, Inf), 0);
760 %! assert (norm (R1'*R1 - R'*R - u*u', Inf) < 1e1*eps);
761 %!
762 %! R1 = cholupdate (R1, u, "-");
763 %! assert (norm (triu (R1)-R1, Inf), 0);
764 %! assert (norm (R1 - R, Inf) < 1e1*eps);
765 
766 %!test
767 %! R = chol (Ac);
768 %! R1 = cholupdate (R, uc);
769 %! assert (norm (triu (R1)-R1, Inf), 0);
770 %! assert (norm (R1'*R1 - R'*R - uc*uc', Inf) < 1e1*eps);
771 %!
772 %! R1 = cholupdate (R1, uc, "-");
773 %! assert (norm (triu (R1)-R1, Inf), 0);
774 %! assert (norm (R1 - R, Inf) < 1e1*eps);
775 
776 %!test
777 %! R = chol (single (A));
778 %! R1 = cholupdate (R, single (u));
779 %! assert (norm (triu (R1)-R1, Inf), single (0));
780 %! assert (norm (R1'*R1 - R'*R - single (u*u'), Inf) < 1e1*eps ("single"));
781 %!
782 %! R1 = cholupdate (R1, single (u), "-");
783 %! assert (norm (triu (R1)-R1, Inf), single (0));
784 %! assert (norm (R1 - R, Inf) < 2e1*eps ("single"));
785 
786 %!test
787 %! R = chol (single (Ac));
788 %! R1 = cholupdate (R, single (uc));
789 %! assert (norm (triu (R1)-R1, Inf), single (0));
790 %! assert (norm (R1'*R1 - R'*R - single (uc*uc'), Inf) < 1e1*eps ("single"));
791 %!
792 %! R1 = cholupdate (R1, single (uc), "-");
793 %! assert (norm (triu (R1)-R1, Inf), single (0));
794 %! assert (norm (R1 - R, Inf) < 2e1*eps ("single"));
795 */
796 
797 DEFUN_DLD (cholinsert, args, nargout,
798  doc: /* -*- texinfo -*-
799 @deftypefn {} {@var{R1} =} cholinsert (@var{R}, @var{j}, @var{u})
800 @deftypefnx {} {[@var{R1}, @var{info}] =} cholinsert (@var{R}, @var{j}, @var{u})
801 Given a Cholesky@tie{}factorization of a real symmetric or complex Hermitian
802 positive definite matrix @w{@var{A} = @var{R}'*@var{R}}, @var{R}@tie{}upper
803 triangular, return the Cholesky@tie{}factorization of
804 @var{A1}, where @w{A1(p,p) = A}, @w{A1(:,j) = A1(j,:)' = u} and
805 @w{p = [1:j-1,j+1:n+1]}. @w{u(j)} should be positive.
806 
807 On return, @var{info} is set to
808 
809 @itemize
810 @item 0 if the insertion was successful,
811 
812 @item 1 if @var{A1} is not positive definite,
813 
814 @item 2 if @var{R} is singular.
815 @end itemize
816 
817 If @var{info} is not present, an error message is printed in cases 1 and 2.
818 @seealso{chol, cholupdate, choldelete, cholshift}
819 @end deftypefn */)
820 {
821  if (args.length () != 3)
822  print_usage ();
823 
824  octave_value argr = args(0);
825  octave_value argj = args(1);
826  octave_value argu = args(2);
827 
828  if (! argr.is_numeric_type () || ! argu.is_numeric_type ()
829  || ! argj.is_real_scalar ())
830  print_usage ();
831 
832  octave_idx_type n = argr.rows ();
833  octave_idx_type j = argj.scalar_value ();
834 
835  if (argr.columns () != n || argu.rows () != n+1 || argu.columns () != 1)
836  error ("cholinsert: dimension mismatch between R and U");
837 
838  if (j < 1 || j > n+1)
839  error ("cholinsert: index J out of range");
840 
841  octave_value_list retval (nargout == 2 ? 2 : 1);
842 
843  int err = 0;
844  if (argr.is_single_type () || argu.is_single_type ())
845  {
846  if (argr.is_real_type () && argu.is_real_type ())
847  {
848  // real case
849  FloatMatrix R = argr.float_matrix_value ();
851 
853  fact.set (R);
854  err = fact.insert_sym (u, j-1);
855 
856  retval = ovl (get_chol_r (fact));
857  }
858  else
859  {
860  // complex case
864 
866  fact.set (R);
867  err = fact.insert_sym (u, j-1);
868 
869  retval = ovl (get_chol_r (fact));
870  }
871  }
872  else
873  {
874  if (argr.is_real_type () && argu.is_real_type ())
875  {
876  // real case
877  Matrix R = argr.matrix_value ();
878  ColumnVector u = argu.column_vector_value ();
879 
881  fact.set (R);
882  err = fact.insert_sym (u, j-1);
883 
884  retval = ovl (get_chol_r (fact));
885  }
886  else
887  {
888  // complex case
892 
894  fact.set (R);
895  err = fact.insert_sym (u, j-1);
896 
897  retval = ovl (get_chol_r (fact));
898  }
899  }
900 
901  if (nargout > 1)
902  retval(1) = err;
903  else if (err == 1)
904  error ("cholinsert: insertion violates positiveness");
905  else if (err == 2)
906  error ("cholinsert: singular matrix");
907  else if (err == 3)
908  error ("cholinsert: diagonal element must be real");
909 
910  return retval;
911 }
912 
913 /*
914 %!test
915 %! u2 = [ 0.35080 ;
916 %! 0.63930 ;
917 %! 3.31057 ;
918 %! -0.13825 ;
919 %! 0.45266 ];
920 %!
921 %! R = chol (A);
922 %!
923 %! j = 3; p = [1:j-1, j+1:5];
924 %! R1 = cholinsert (R, j, u2);
925 %! A1 = R1'*R1;
926 %!
927 %! assert (norm (triu (R1)-R1, Inf), 0);
928 %! assert (norm (A1(p,p) - A, Inf) < 1e1*eps);
929 
930 %!test
931 %! u2 = [ 0.35080 + 0.04298i;
932 %! 0.63930 + 0.23778i;
933 %! 3.31057 + 0.00000i;
934 %! -0.13825 + 0.19879i;
935 %! 0.45266 + 0.50020i];
936 %!
937 %! R = chol (Ac);
938 %!
939 %! j = 3; p = [1:j-1, j+1:5];
940 %! R1 = cholinsert (R, j, u2);
941 %! A1 = R1'*R1;
942 %!
943 %! assert (norm (triu (R1)-R1, Inf), 0);
944 %! assert (norm (A1(p,p) - Ac, Inf) < 1e1*eps);
945 
946 %!test
947 %! u2 = single ([ 0.35080 ;
948 %! 0.63930 ;
949 %! 3.31057 ;
950 %! -0.13825 ;
951 %! 0.45266 ]);
952 %!
953 %! R = chol (single (A));
954 %!
955 %! j = 3; p = [1:j-1, j+1:5];
956 %! R1 = cholinsert (R, j, u2);
957 %! A1 = R1'*R1;
958 %!
959 %! assert (norm (triu (R1)-R1, Inf), single (0));
960 %! assert (norm (A1(p,p) - A, Inf) < 1e1*eps ("single"));
961 
962 %!test
963 %! u2 = single ([ 0.35080 + 0.04298i;
964 %! 0.63930 + 0.23778i;
965 %! 3.31057 + 0.00000i;
966 %! -0.13825 + 0.19879i;
967 %! 0.45266 + 0.50020i]);
968 %!
969 %! R = chol (single (Ac));
970 %!
971 %! j = 3; p = [1:j-1, j+1:5];
972 %! R1 = cholinsert (R, j, u2);
973 %! A1 = R1'*R1;
974 %!
975 %! assert (norm (triu (R1)-R1, Inf), single (0));
976 %! assert (norm (A1(p,p) - single (Ac), Inf) < 2e1*eps ("single"));
977 
978 %!test
979 %! cu = chol (triu (A), "upper");
980 %! cl = chol (tril (A), "lower");
981 %! assert (cu, cl', eps);
982 
983 %!test
984 %! cca = chol (Ac);
985 %!
986 %! ccal = chol (Ac, "lower");
987 %! ccal2 = chol (tril (Ac), "lower");
988 %!
989 %! ccau = chol (Ac, "upper");
990 %! ccau2 = chol (triu (Ac), "upper");
991 %!
992 %! assert (cca'*cca, Ac, eps);
993 %! assert (ccau'*ccau, Ac, eps);
994 %! assert (ccau2'*ccau2, Ac, eps);
995 %!
996 %! assert (cca, ccal', eps);
997 %! assert (cca, ccau, eps);
998 %! assert (cca, ccal2', eps);
999 %! assert (cca, ccau2, eps);
1000 
1001 %!test
1002 %! cca = chol (single (Ac));
1003 %!
1004 %! ccal = chol (single (Ac), "lower");
1005 %! ccal2 = chol (tril (single (Ac)), "lower");
1006 %!
1007 %! ccau = chol (single (Ac), "upper");
1008 %! ccau2 = chol (triu (single (Ac)), "upper");
1009 %!
1010 %! assert (cca'*cca, single (Ac), eps ("single"));
1011 %! assert (ccau'*ccau, single (Ac), eps ("single"));
1012 %! assert (ccau2'*ccau2, single (Ac), eps ("single"));
1013 %!
1014 %! assert (cca, ccal', eps ("single"));
1015 %! assert (cca, ccau, eps ("single"));
1016 %! assert (cca, ccal2', eps ("single"));
1017 %! assert (cca, ccau2, eps ("single"));
1018 
1019 %!test
1020 %! a = [12, 2, 3, 4;
1021 %! 2, 14, 5, 3;
1022 %! 3, 5, 16, 6;
1023 %! 4, 3, 6, 16];
1024 %!
1025 %! b = [0, 1, 2, 3;
1026 %! -1, 0, 1, 2;
1027 %! -2, -1, 0, 1;
1028 %! -3, -2, -1, 0];
1029 %!
1030 %! ca = a + i*b;
1031 %!
1032 %! cca = chol (ca);
1033 %!
1034 %! ccal = chol (ca, "lower");
1035 %! ccal2 = chol (tril (ca), "lower");
1036 %!
1037 %! ccau = chol (ca, "upper");
1038 %! ccau2 = chol (triu (ca), "upper");
1039 %!
1040 %! assert (cca'*cca, ca, 16*eps);
1041 %! assert (ccau'*ccau, ca, 16*eps);
1042 %! assert (ccau2'*ccau2, ca, 16*eps);
1043 %!
1044 %! assert (cca, ccal', 16*eps);
1045 %! assert (cca, ccau, 16*eps);
1046 %! assert (cca, ccal2', 16*eps);
1047 %! assert (cca, ccau2, 16*eps);
1048 */
1049 
1050 DEFUN_DLD (choldelete, args, ,
1051  doc: /* -*- texinfo -*-
1052 @deftypefn {} {@var{R1} =} choldelete (@var{R}, @var{j})
1053 Given a Cholesky@tie{}factorization of a real symmetric or complex Hermitian
1054 positive definite matrix @w{@var{A} = @var{R}'*@var{R}}, @var{R}@tie{}upper
1055 triangular, return the Cholesky@tie{}factorization of @w{A(p,p)}, where
1056 @w{p = [1:j-1,j+1:n+1]}.
1057 @seealso{chol, cholupdate, cholinsert, cholshift}
1058 @end deftypefn */)
1059 {
1060  if (args.length () != 2)
1061  print_usage ();
1062 
1063  octave_value argr = args(0);
1064  octave_value argj = args(1);
1065 
1066  if (! argr.is_numeric_type () || ! argj.is_real_scalar ())
1067  print_usage ();
1068 
1069  octave_idx_type n = argr.rows ();
1070  octave_idx_type j = argj.scalar_value ();
1071 
1072  if (argr.columns () != n)
1073  err_square_matrix_required ("choldelete", "R");
1074 
1075  if (j < 0 && j > n)
1076  error ("choldelete: index J out of range");
1077 
1079 
1080  if (argr.is_single_type ())
1081  {
1082  if (argr.is_real_type ())
1083  {
1084  // real case
1085  FloatMatrix R = argr.float_matrix_value ();
1086 
1088  fact.set (R);
1089  fact.delete_sym (j-1);
1090 
1091  retval = ovl (get_chol_r (fact));
1092  }
1093  else
1094  {
1095  // complex case
1097 
1099  fact.set (R);
1100  fact.delete_sym (j-1);
1101 
1102  retval = ovl (get_chol_r (fact));
1103  }
1104  }
1105  else
1106  {
1107  if (argr.is_real_type ())
1108  {
1109  // real case
1110  Matrix R = argr.matrix_value ();
1111 
1113  fact.set (R);
1114  fact.delete_sym (j-1);
1115 
1116  retval = ovl (get_chol_r (fact));
1117  }
1118  else
1119  {
1120  // complex case
1121  ComplexMatrix R = argr.complex_matrix_value ();
1122 
1124  fact.set (R);
1125  fact.delete_sym (j-1);
1126 
1127  retval = ovl (get_chol_r (fact));
1128  }
1129  }
1130 
1131  return retval;
1132 }
1133 
1134 /*
1135 %!test
1136 %! R = chol (A);
1137 %!
1138 %! j = 3; p = [1:j-1,j+1:4];
1139 %! R1 = choldelete (R, j);
1140 %!
1141 %! assert (norm (triu (R1)-R1, Inf), 0);
1142 %! assert (norm (R1'*R1 - A(p,p), Inf) < 1e1*eps);
1143 
1144 %!test
1145 %! R = chol (Ac);
1146 %!
1147 %! j = 3; p = [1:j-1,j+1:4];
1148 %! R1 = choldelete (R, j);
1149 %!
1150 %! assert (norm (triu (R1)-R1, Inf), 0);
1151 %! assert (norm (R1'*R1 - Ac(p,p), Inf) < 1e1*eps);
1152 
1153 %!test
1154 %! R = chol (single (A));
1155 %!
1156 %! j = 3; p = [1:j-1,j+1:4];
1157 %! R1 = choldelete (R, j);
1158 %!
1159 %! assert (norm (triu (R1)-R1, Inf), single (0));
1160 %! assert (norm (R1'*R1 - single (A(p,p)), Inf) < 1e1*eps ("single"));
1161 
1162 %!test
1163 %! R = chol (single (Ac));
1164 %!
1165 %! j = 3; p = [1:j-1,j+1:4];
1166 %! R1 = choldelete (R,j);
1167 %!
1168 %! assert (norm (triu (R1)-R1, Inf), single (0));
1169 %! assert (norm (R1'*R1 - single (Ac(p,p)), Inf) < 1e1*eps ("single"));
1170 */
1171 
1172 DEFUN_DLD (cholshift, args, ,
1173  doc: /* -*- texinfo -*-
1174 @deftypefn {} {@var{R1} =} cholshift (@var{R}, @var{i}, @var{j})
1175 Given a Cholesky@tie{}factorization of a real symmetric or complex Hermitian
1176 positive definite matrix @w{@var{A} = @var{R}'*@var{R}}, @var{R}@tie{}upper
1177 triangular, return the Cholesky@tie{}factorization of
1178 @w{@var{A}(p,p)}, where @w{p} is the permutation @*
1179 @code{p = [1:i-1, shift(i:j, 1), j+1:n]} if @w{@var{i} < @var{j}} @*
1180  or @*
1181 @code{p = [1:j-1, shift(j:i,-1), i+1:n]} if @w{@var{j} < @var{i}}. @*
1182 
1183 @seealso{chol, cholupdate, cholinsert, choldelete}
1184 @end deftypefn */)
1185 {
1186  if (args.length () != 3)
1187  print_usage ();
1188 
1189  octave_value argr = args(0);
1190  octave_value argi = args(1);
1191  octave_value argj = args(2);
1192 
1193  if (! argr.is_numeric_type () || ! argi.is_real_scalar ()
1194  || ! argj.is_real_scalar ())
1195  print_usage ();
1196 
1197  octave_idx_type n = argr.rows ();
1198  octave_idx_type i = argi.scalar_value ();
1199  octave_idx_type j = argj.scalar_value ();
1200 
1201  if (argr.columns () != n)
1202  err_square_matrix_required ("cholshift", "R");
1203 
1204  if (j < 0 || j > n+1 || i < 0 || i > n+1)
1205  error ("cholshift: index I or J is out of range");
1206 
1208 
1209  if (argr.is_single_type () && argi.is_single_type ()
1210  && argj.is_single_type ())
1211  {
1212  if (argr.is_real_type ())
1213  {
1214  // real case
1215  FloatMatrix R = argr.float_matrix_value ();
1216 
1218  fact.set (R);
1219  fact.shift_sym (i-1, j-1);
1220 
1221  retval = ovl (get_chol_r (fact));
1222  }
1223  else
1224  {
1225  // complex case
1227 
1229  fact.set (R);
1230  fact.shift_sym (i-1, j-1);
1231 
1232  retval = ovl (get_chol_r (fact));
1233  }
1234  }
1235  else
1236  {
1237  if (argr.is_real_type ())
1238  {
1239  // real case
1240  Matrix R = argr.matrix_value ();
1241 
1243  fact.set (R);
1244  fact.shift_sym (i-1, j-1);
1245 
1246  retval = ovl (get_chol_r (fact));
1247  }
1248  else
1249  {
1250  // complex case
1251  ComplexMatrix R = argr.complex_matrix_value ();
1252 
1254  fact.set (R);
1255  fact.shift_sym (i-1, j-1);
1256 
1257  retval = ovl (get_chol_r (fact));
1258  }
1259  }
1260 
1261  return retval;
1262 }
1263 
1264 /*
1265 %!test
1266 %! R = chol (A);
1267 %!
1268 %! i = 1; j = 3; p = [1:i-1, shift(i:j,-1), j+1:4];
1269 %! R1 = cholshift (R, i, j);
1270 %!
1271 %! assert (norm (triu (R1)-R1, Inf), 0);
1272 %! assert (norm (R1'*R1 - A(p,p), Inf) < 1e1*eps);
1273 %!
1274 %! j = 1; i = 3; p = [1:j-1, shift(j:i,+1), i+1:4];
1275 %! R1 = cholshift (R, i, j);
1276 %!
1277 %! assert (norm (triu (R1) - R1, Inf), 0);
1278 %! assert (norm (R1'*R1 - A(p,p), Inf) < 1e1*eps);
1279 
1280 %!test
1281 %! R = chol (Ac);
1282 %!
1283 %! i = 1; j = 3; p = [1:i-1, shift(i:j,-1), j+1:4];
1284 %! R1 = cholshift (R, i, j);
1285 %!
1286 %! assert (norm (triu (R1)-R1, Inf), 0);
1287 %! assert (norm (R1'*R1 - Ac(p,p), Inf) < 1e1*eps);
1288 %!
1289 %! j = 1; i = 3; p = [1:j-1, shift(j:i,+1), i+1:4];
1290 %! R1 = cholshift (R, i, j);
1291 %!
1292 %! assert (norm (triu (R1)-R1, Inf), 0);
1293 %! assert (norm (R1'*R1 - Ac(p,p), Inf) < 1e1*eps);
1294 
1295 %!test
1296 %! R = chol (single (A));
1297 %!
1298 %! i = 1; j = 3; p = [1:i-1, shift(i:j,-1), j+1:4];
1299 %! R1 = cholshift (R, i, j);
1300 %!
1301 %! assert (norm (triu (R1)-R1, Inf), 0);
1302 %! assert (norm (R1'*R1 - single (A(p,p)), Inf) < 1e1*eps ("single"));
1303 %!
1304 %! j = 1; i = 3; p = [1:j-1, shift(j:i,+1), i+1:4];
1305 %! R1 = cholshift (R, i, j);
1306 %!
1307 %! assert (norm (triu (R1)-R1, Inf), 0);
1308 %! assert (norm (R1'*R1 - single (A(p,p)), Inf) < 1e1*eps ("single"));
1309 
1310 %!test
1311 %! R = chol (single (Ac));
1312 %!
1313 %! i = 1; j = 3; p = [1:i-1, shift(i:j,-1), j+1:4];
1314 %! R1 = cholshift (R, i, j);
1315 %!
1316 %! assert (norm (triu (R1)-R1, Inf), 0);
1317 %! assert (norm (R1'*R1 - single (Ac(p,p)), Inf) < 1e1*eps ("single"));
1318 %!
1319 %! j = 1; i = 3; p = [1:j-1, shift(j:i,+1), i+1:4];
1320 %! R1 = cholshift (R, i, j);
1321 %!
1322 %! assert (norm (triu (R1)-R1, Inf), 0);
1323 %! assert (norm (R1'*R1 - single (Ac(p,p)), Inf) < 1e1*eps ("single"));
1324 */
ColumnVector column_vector_value(bool frc_str_conv=false, bool frc_vec_conv=false) const
Definition: ov.cc:1766
chol_type R(void) const
Definition: sparse-chol.h:68
bool is_real_type(void) const
Definition: ov.h:667
static octave_value get_chol_r(const CHOLT &fact)
Definition: chol.cc:54
SparseMatrix Q(void) const
Definition: sparse-chol.cc:489
octave_idx_type rows(void) const
Definition: ov.h:489
static octave_value get_chol(const CHOLT &fact)
Definition: chol.cc:47
FloatComplexMatrix float_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:809
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).is_integer_type())
FloatColumnVector float_column_vector_value(bool frc_str_conv=false, bool frc_vec_conv=false) const
Definition: ov.cc:1959
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
Definition: mx-defs.h:65
bool is_numeric_type(void) const
Definition: ov.h:679
chol_type L(void) const
Definition: sparse-chol.cc:444
RowVector perm(void) const
Definition: sparse-chol.cc:482
static octave_value get_chol_l(const CHOLT &fact)
Definition: chol.cc:62
void error(const char *fmt,...)
Definition: error.cc:570
octave_idx_type insert_sym(const VT &u, octave_idx_type j)
u
Definition: lu.cc:138
void err_square_matrix_required(const char *fcn, const char *name)
Definition: errwarn.cc:112
double scalar_value(bool frc_str_conv=false) const
Definition: ov.h:781
octave_value arg
Definition: pr-output.cc:3440
JNIEnv void * args
Definition: ov-java.cc:67
octave_idx_type columns(void) const
Definition: ov.h:491
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function xample nargout(@histc)
Definition: ov-usr-fcn.cc:935
bool is_sparse_type(void) const
Definition: ov.h:682
T chol2inv(const T &r)
Definition: chol.cc:247
bool is_real_scalar(void) const
Definition: ov.h:551
nd deftypefn *octave_map m
Definition: ov-struct.cc:2058
int nargin
Definition: graphics.cc:10115
octave_idx_type downdate(const VT &u)
bool is_complex_type(void) const
Definition: ov.h:670
double tmp
Definition: data.cc:6300
void delete_sym(octave_idx_type j)
octave_value retval
Definition: data.cc:6294
Definition: dMatrix.h:37
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:838
void set(const T &R)
Definition: chol.cc:262
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:787
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:156
void update(const VT &u)
bool is_empty(void) const
Definition: ov.h:542
bool strcmpi(const T &str_a, const T &str_b)
True if strings are the same, ignoring case.
Definition: oct-string.cc:129
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
ComplexMatrix complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:805
void shift_sym(octave_idx_type i, octave_idx_type j)
FloatComplexColumnVector float_complex_column_vector_value(bool frc_str_conv=false, bool frc_vec_conv=false) const
Definition: ov.cc:1967
FloatMatrix float_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:790
ComplexColumnVector complex_column_vector_value(bool frc_str_conv=false, bool frc_vec_conv=false) const
Definition: ov.cc:1774
#define DEFUN_DLD(name, args_name, nargout_name, doc)
Definition: defun-dld.h:45
OCTAVE_EXPORT octave_value_list error nd deftypefn *const octave_scalar_map err
Definition: error.cc:1036
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:834
bool is_single_type(void) const
Definition: ov.h:627
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
return octave_value(v1.char_array_value().concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string())? '\'': '"'))