GNU Octave  3.8.0
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
matrix_type.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2005-2013 David Bateman
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <algorithm>
28 
29 #include "ov.h"
30 #include "defun.h"
31 #include "error.h"
32 #include "ov-re-mat.h"
33 #include "ov-cx-mat.h"
34 #include "ov-re-sparse.h"
35 #include "ov-cx-sparse.h"
36 #include "MatrixType.h"
37 #include "oct-locbuf.h"
38 
39 DEFUN (matrix_type, args, ,
40  "-*- texinfo -*-\n\
41 @deftypefn {Built-in Function} {@var{type} =} matrix_type (@var{A})\n\
42 @deftypefnx {Built-in Function} {@var{type} =} matrix_type (@var{A}, \"nocompute\")\n\
43 @deftypefnx {Built-in Function} {@var{A} =} matrix_type (@var{A}, @var{type})\n\
44 @deftypefnx {Built-in Function} {@var{A} =} matrix_type (@var{A}, \"upper\", @var{perm})\n\
45 @deftypefnx {Built-in Function} {@var{A} =} matrix_type (@var{A}, \"lower\", @var{perm})\n\
46 @deftypefnx {Built-in Function} {@var{A} =} matrix_type (@var{A}, \"banded\", @var{nl}, @var{nu})\n\
47 Identify the matrix type or mark a matrix as a particular type. This allows\n\
48 more rapid solutions of linear equations involving @var{A} to be performed.\n\
49 Called with a single argument, @code{matrix_type} returns the type of the\n\
50 matrix and caches it for future use. Called with more than one argument,\n\
51 @code{matrix_type} allows the type of the matrix to be defined.\n\
52 \n\
53 If the option @qcode{\"nocompute\"} is given, the function will not attempt\n\
54 to guess the type if it is still unknown. This is useful for debugging\n\
55 purposes.\n\
56 \n\
57 The possible matrix types depend on whether the matrix is full or sparse, and\n\
58 can be one of the following\n\
59 \n\
60 @table @asis\n\
61 @item @qcode{\"unknown\"}\n\
62 Remove any previously cached matrix type, and mark type as unknown.\n\
63 \n\
64 @item @qcode{\"full\"}\n\
65 Mark the matrix as full.\n\
66 \n\
67 @item @qcode{\"positive definite\"}\n\
68 Probable full positive definite matrix.\n\
69 \n\
70 @item @qcode{\"diagonal\"}\n\
71 Diagonal matrix. (Sparse matrices only)\n\
72 \n\
73 @item @qcode{\"permuted diagonal\"}\n\
74 Permuted Diagonal matrix. The permutation does not need to be specifically\n\
75 indicated, as the structure of the matrix explicitly gives this. (Sparse\n\
76 matrices only)\n\
77 \n\
78 @item @qcode{\"upper\"}\n\
79 Upper triangular. If the optional third argument @var{perm} is given, the\n\
80 matrix is assumed to be a permuted upper triangular with the permutations\n\
81 defined by the vector @var{perm}.\n\
82 \n\
83 @item @qcode{\"lower\"}\n\
84 Lower triangular. If the optional third argument @var{perm} is given, the\n\
85 matrix is assumed to be a permuted lower triangular with the permutations\n\
86 defined by the vector @var{perm}.\n\
87 \n\
88 @item @qcode{\"banded\"}\n\
89 @itemx @qcode{\"banded positive definite\"}\n\
90 Banded matrix with the band size of @var{nl} below the diagonal and @var{nu}\n\
91 above it. If @var{nl} and @var{nu} are 1, then the matrix is tridiagonal and\n\
92 treated with specialized code. In addition the matrix can be marked as\n\
93 probably a positive definite. (Sparse matrices only)\n\
94 \n\
95 @item @qcode{\"singular\"}\n\
96 The matrix is assumed to be singular and will be treated with a minimum norm\n\
97 solution.\n\
98 \n\
99 @end table\n\
100 \n\
101 Note that the matrix type will be discovered automatically on the first\n\
102 attempt to solve a linear equation involving @var{A}. Therefore\n\
103 @code{matrix_type} is only useful to give Octave hints of the matrix type.\n\
104 Incorrectly defining the matrix type will result in incorrect results from\n\
105 solutions of linear equations; it is entirely @strong{the responsibility of\n\
106 the user} to correctly identify the matrix type.\n\
107 \n\
108 Also, the test for positive definiteness is a low-cost test for a Hermitian\n\
109 matrix with a real positive diagonal. This does not guarantee that the\n\
110 matrix is positive definite, but only that it is a probable candidate. When\n\
111 such a matrix is factorized, a Cholesky@tie{}factorization is first\n\
112 attempted, and if that fails the matrix is then treated with an\n\
113 LU@tie{}factorization. Once the matrix has been factorized,\n\
114 @code{matrix_type} will return the correct classification of the matrix.\n\
115 @end deftypefn")
116 {
117  int nargin = args.length ();
118  octave_value retval;
119 
120  if (nargin == 0)
121  print_usage ();
122  else if (nargin > 4)
123  error ("matrix_type: incorrect number of arguments");
124  else
125  {
126  bool autocomp = true;
127  if (nargin == 2 && args(1).is_string ()
128  && args(1).string_value () == "nocompute")
129  {
130  nargin = 1;
131  autocomp = false;
132  }
133 
134  if (args(0).is_scalar_type ())
135  {
136  if (nargin == 1)
137  retval = octave_value ("Diagonal");
138  else
139  retval = args(0);
140  }
141  else if (args(0).is_sparse_type ())
142  {
143  if (nargin == 1)
144  {
145  MatrixType mattyp;
146 
147  if (args(0).is_complex_type ())
148  {
149  mattyp = args(0).matrix_type ();
150 
151  if (mattyp.is_unknown () && autocomp )
152  {
154  args(0).sparse_complex_matrix_value ();
155  if (!error_state)
156  {
157  mattyp = MatrixType (m);
158  args(0).matrix_type (mattyp);
159  }
160  }
161  }
162  else
163  {
164  mattyp = args(0).matrix_type ();
165 
166  if (mattyp.is_unknown () && autocomp)
167  {
168  SparseMatrix m = args(0).sparse_matrix_value ();
169  if (!error_state)
170  {
171  mattyp = MatrixType (m);
172  args(0).matrix_type (mattyp);
173  }
174  }
175  }
176 
177  int typ = mattyp.type ();
178 
179  if (typ == MatrixType::Diagonal)
180  retval = octave_value ("Diagonal");
181  else if (typ == MatrixType::Permuted_Diagonal)
182  retval = octave_value ("Permuted Diagonal");
183  else if (typ == MatrixType::Upper)
184  retval = octave_value ("Upper");
185  else if (typ == MatrixType::Permuted_Upper)
186  retval = octave_value ("Permuted Upper");
187  else if (typ == MatrixType::Lower)
188  retval = octave_value ("Lower");
189  else if (typ == MatrixType::Permuted_Lower)
190  retval = octave_value ("Permuted Lower");
191  else if (typ == MatrixType::Banded)
192  retval = octave_value ("Banded");
193  else if (typ == MatrixType::Banded_Hermitian)
194  retval = octave_value ("Banded Positive Definite");
195  else if (typ == MatrixType::Tridiagonal)
196  retval = octave_value ("Tridiagonal");
197  else if (typ == MatrixType::Tridiagonal_Hermitian)
198  retval = octave_value ("Tridiagonal Positive Definite");
199  else if (typ == MatrixType::Hermitian)
200  retval = octave_value ("Positive Definite");
201  else if (typ == MatrixType::Rectangular)
202  {
203  if (args(0).rows () == args(0).columns ())
204  retval = octave_value ("Singular");
205  else
206  retval = octave_value ("Rectangular");
207  }
208  else if (typ == MatrixType::Full)
209  retval = octave_value ("Full");
210  else
211  retval = octave_value ("Unknown");
212  }
213  else
214  {
215  // Ok, we're changing the matrix type
216  std::string str_typ = args(1).string_value ();
217 
218  // FIXME: why do I have to explicitly call the constructor?
219  MatrixType mattyp = MatrixType ();
220 
221  octave_idx_type nl = 0;
222  octave_idx_type nu = 0;
223 
224  if (error_state)
225  error ("matrix_type: TYPE must be a string");
226  else
227  {
228  // Use STL function to convert to lower case
229  std::transform (str_typ.begin (), str_typ.end (),
230  str_typ.begin (), tolower);
231 
232  if (str_typ == "diagonal")
233  mattyp.mark_as_diagonal ();
234  if (str_typ == "permuted diagonal")
235  mattyp.mark_as_permuted_diagonal ();
236  else if (str_typ == "upper")
237  mattyp.mark_as_upper_triangular ();
238  else if (str_typ == "lower")
239  mattyp.mark_as_lower_triangular ();
240  else if (str_typ == "banded"
241  || str_typ == "banded positive definite")
242  {
243  if (nargin != 4)
244  error ("matrix_type: banded matrix type requires 4 arguments");
245  else
246  {
247  nl = args(2).nint_value ();
248  nu = args(3).nint_value ();
249 
250  if (error_state)
251  error ("matrix_type: band size NL, NU must be integers");
252  else
253  {
254  if (nl == 1 && nu == 1)
255  mattyp.mark_as_tridiagonal ();
256  else
257  mattyp.mark_as_banded (nu, nl);
258 
259  if (str_typ == "banded positive definite")
260  mattyp.mark_as_symmetric ();
261  }
262  }
263  }
264  else if (str_typ == "positive definite")
265  {
266  mattyp.mark_as_full ();
267  mattyp.mark_as_symmetric ();
268  }
269  else if (str_typ == "singular")
270  mattyp.mark_as_rectangular ();
271  else if (str_typ == "full")
272  mattyp.mark_as_full ();
273  else if (str_typ == "unknown")
274  mattyp.invalidate_type ();
275  else
276  error ("matrix_type: Unknown matrix type %s", str_typ.c_str ());
277 
278  if (! error_state)
279  {
280  if (nargin == 3
281  && (str_typ == "upper" || str_typ == "lower"))
282  {
283  const ColumnVector perm =
284  ColumnVector (args (2).vector_value ());
285 
286  if (error_state)
287  error ("matrix_type: Invalid permutation vector PERM");
288  else
289  {
290  octave_idx_type len = perm.length ();
291  dim_vector dv = args(0).dims ();
292 
293  if (len != dv(0))
294  error ("matrix_type: Invalid permutation vector PERM");
295  else
296  {
298 
299  for (octave_idx_type i = 0; i < len; i++)
300  p[i] = static_cast<octave_idx_type>
301  (perm (i))
302  - 1;
303 
304  if (str_typ == "upper")
305  mattyp.mark_as_permuted (len, p);
306  else
307  mattyp.mark_as_permuted (len, p);
308  }
309  }
310  }
311  else if (nargin != 2
312  && str_typ != "banded positive definite"
313  && str_typ != "banded")
314  error ("matrix_type: Invalid number of arguments");
315 
316  if (! error_state)
317  {
318  // Set the matrix type
319  if (args(0).is_complex_type ())
320  retval =
321  octave_value (args(0).sparse_complex_matrix_value (),
322  mattyp);
323  else
324  retval
325  = octave_value (args(0).sparse_matrix_value (),
326  mattyp);
327  }
328  }
329  }
330  }
331  }
332  else
333  {
334  if (nargin == 1)
335  {
336  MatrixType mattyp;
337 
338  if (args(0).is_complex_type ())
339  {
340  mattyp = args(0).matrix_type ();
341 
342  if (mattyp.is_unknown () && autocomp)
343  {
344  if (args(0).is_single_type ())
345  {
347  m = args(0).float_complex_matrix_value ();
348  if (!error_state)
349  {
350  mattyp = MatrixType (m);
351  args(0).matrix_type (mattyp);
352  }
353  }
354  else
355  {
356  ComplexMatrix m = args(0).complex_matrix_value ();
357  if (!error_state)
358  {
359  mattyp = MatrixType (m);
360  args(0).matrix_type (mattyp);
361  }
362  }
363  }
364  }
365  else
366  {
367  mattyp = args(0).matrix_type ();
368 
369  if (mattyp.is_unknown () && autocomp)
370  {
371  if (args(0).is_single_type ())
372  {
373  FloatMatrix m = args(0).float_matrix_value ();
374  if (!error_state)
375  {
376  mattyp = MatrixType (m);
377  args(0).matrix_type (mattyp);
378  }
379  }
380  else
381  {
382  Matrix m = args(0).matrix_value ();
383  if (!error_state)
384  {
385  mattyp = MatrixType (m);
386  args(0).matrix_type (mattyp);
387  }
388  }
389  }
390  }
391 
392  int typ = mattyp.type ();
393 
394  if (typ == MatrixType::Upper)
395  retval = octave_value ("Upper");
396  else if (typ == MatrixType::Permuted_Upper)
397  retval = octave_value ("Permuted Upper");
398  else if (typ == MatrixType::Lower)
399  retval = octave_value ("Lower");
400  else if (typ == MatrixType::Permuted_Lower)
401  retval = octave_value ("Permuted Lower");
402  else if (typ == MatrixType::Hermitian)
403  retval = octave_value ("Positive Definite");
404  else if (typ == MatrixType::Rectangular)
405  {
406  if (args(0).rows () == args(0).columns ())
407  retval = octave_value ("Singular");
408  else
409  retval = octave_value ("Rectangular");
410  }
411  else if (typ == MatrixType::Full)
412  retval = octave_value ("Full");
413  else
414  retval = octave_value ("Unknown");
415  }
416  else
417  {
418  // Ok, we're changing the matrix type
419  std::string str_typ = args(1).string_value ();
420 
421  // FIXME: why do I have to explicitly call the constructor?
422  MatrixType mattyp = MatrixType (MatrixType::Unknown, true);
423 
424  if (error_state)
425  error ("matrix_type: TYPE must be a string");
426  else
427  {
428  // Use STL function to convert to lower case
429  std::transform (str_typ.begin (), str_typ.end (),
430  str_typ.begin (), tolower);
431 
432  if (str_typ == "upper")
433  mattyp.mark_as_upper_triangular ();
434  else if (str_typ == "lower")
435  mattyp.mark_as_lower_triangular ();
436  else if (str_typ == "positive definite")
437  {
438  mattyp.mark_as_full ();
439  mattyp.mark_as_symmetric ();
440  }
441  else if (str_typ == "singular")
442  mattyp.mark_as_rectangular ();
443  else if (str_typ == "full")
444  mattyp.mark_as_full ();
445  else if (str_typ == "unknown")
446  mattyp.invalidate_type ();
447  else
448  error ("matrix_type: Unknown matrix type %s",
449  str_typ.c_str ());
450 
451  if (! error_state)
452  {
453  if (nargin == 3 && (str_typ == "upper"
454  || str_typ == "lower"))
455  {
456  const ColumnVector perm =
457  ColumnVector (args (2).vector_value ());
458 
459  if (error_state)
460  error ("matrix_type: Invalid permutation vector PERM");
461  else
462  {
463  octave_idx_type len = perm.length ();
464  dim_vector dv = args(0).dims ();
465 
466  if (len != dv(0))
467  error ("matrix_type: Invalid permutation vector PERM");
468  else
469  {
471 
472  for (octave_idx_type i = 0; i < len; i++)
473  p[i] = static_cast<octave_idx_type>
474  (perm (i))
475  - 1;
476 
477  if (str_typ == "upper")
478  mattyp.mark_as_permuted (len, p);
479  else
480  mattyp.mark_as_permuted (len, p);
481  }
482  }
483  }
484  else if (nargin != 2)
485  error ("matrix_type: Invalid number of arguments");
486 
487  if (! error_state)
488  {
489  // Set the matrix type
490  if (args(0).is_single_type ())
491  {
492  if (args(0).is_complex_type ())
493  retval = octave_value
494  (args(0).float_complex_matrix_value (),
495  mattyp);
496  else
497  retval = octave_value
498  (args(0).float_matrix_value (),
499  mattyp);
500  }
501  else
502  {
503  if (args(0).is_complex_type ())
504  retval = octave_value
505  (args(0).complex_matrix_value (),
506  mattyp);
507  else
508  retval = octave_value
509  (args(0).matrix_value (),
510  mattyp);
511  }
512  }
513  }
514  }
515  }
516  }
517  }
518 
519  return retval;
520 }
521 
522 /*
523 ## FIXME:
524 ## Disable tests for lower under-determined and upper over-determined
525 ## matrices as this detection is disabled in MatrixType due to issues
526 ## of non minimum norm solution being found.
527 
528 %!assert (matrix_type (speye (10,10)), "Diagonal")
529 %!assert (matrix_type (speye (10,10)([2:10,1],:)), "Permuted Diagonal")
530 %!assert (matrix_type ([[speye(10,10);sparse(1,10)],[1;sparse(9,1);1]]), "Upper")
531 %!assert (matrix_type ([[speye(10,10);sparse(1,10)],[1;sparse(9,1);1]](:,[2,1,3:11])), "Permuted Upper")
532 %!assert (matrix_type ([speye(10,10),sparse(10,1);1,sparse(1,9),1]), "Lower")
533 %!assert (matrix_type ([speye(10,10),sparse(10,1);1,sparse(1,9),1]([2,1,3:11],:)), "Permuted Lower")
534 
535 %!test
536 %! bnd = spparms ("bandden");
537 %! spparms ("bandden", 0.5);
538 %! a = spdiags (rand (10,3)-0.5,[-1,0,1],10,10);
539 %! assert (matrix_type (a), "Tridiagonal");
540 %! assert (matrix_type (a'+a+2*speye (10)), "Tridiagonal Positive Definite");
541 %! spparms ("bandden", bnd);
542 %!test
543 %! bnd=spparms ("bandden");
544 %! spparms ("bandden", 0.5);
545 %! a = spdiags (randn (10,4),[-2:1],10,10);
546 %! assert (matrix_type (a), "Banded");
547 %! assert (matrix_type (a'*a), "Banded Positive Definite");
548 %! spparms ("bandden", bnd);
549 %!test
550 %! a = [speye(10,10),[sparse(9,1);1];-1,sparse(1,9),1];
551 %! assert (matrix_type (a), "Full");
552 %! assert (matrix_type (a'*a), "Positive Definite");
553 
554 %!assert (matrix_type (speye (10,11)), "Diagonal")
555 %!assert (matrix_type (speye (10,11)([2:10,1],:)), "Permuted Diagonal")
556 %!assert (matrix_type (speye (11,10)), "Diagonal")
557 %!assert (matrix_type (speye (11,10)([2:11,1],:)), "Permuted Diagonal")
558 %#!assert (matrix_type ([[speye(10,10);sparse(1,10)],[[1,1];sparse(9,2);[1,1]]]), "Upper")
559 %#!assert (matrix_type ([[speye(10,10);sparse(1,10)],[[1,1];sparse(9,2);[1,1]]](:,[2,1,3:12])), "Permuted Upper")
560 %!assert (matrix_type ([speye(11,9),[1;sparse(8,1);1;0]]), "Upper")
561 %!assert (matrix_type ([speye(11,9),[1;sparse(8,1);1;0]](:,[2,1,3:10])), "Permuted Upper")
562 %#!assert (matrix_type ([speye(10,10),sparse(10,1);[1;1],sparse(2,9),[1;1]]), "Lower")
563 %#!assert (matrix_type ([speye(10,10),sparse(10,1);[1;1],sparse(2,9),[1;1]]([2,1,3:12],:)), "Permuted Lower")
564 %!assert (matrix_type ([speye(9,11);[1,sparse(1,8),1,0]]), "Lower")
565 %!assert (matrix_type ([speye(9,11);[1,sparse(1,8),1,0]]([2,1,3:10],:)), "Permuted Lower")
566 %!assert (matrix_type (spdiags (randn (10,4),[-2:1],10,9)), "Rectangular")
567 
568 %!assert (matrix_type (1i*speye (10,10)), "Diagonal")
569 %!assert (matrix_type (1i*speye (10,10)([2:10,1],:)), "Permuted Diagonal")
570 %!assert (matrix_type ([[speye(10,10);sparse(1,10)],[1i;sparse(9,1);1]]), "Upper")
571 %!assert (matrix_type ([[speye(10,10);sparse(1,10)],[1i;sparse(9,1);1]](:,[2,1,3:11])), "Permuted Upper")
572 %!assert (matrix_type ([speye(10,10),sparse(10,1);1i,sparse(1,9),1]), "Lower")
573 %!assert (matrix_type ([speye(10,10),sparse(10,1);1i,sparse(1,9),1]([2,1,3:11],:)), "Permuted Lower")
574 
575 %!test
576 %! bnd = spparms ("bandden");
577 %! spparms ("bandden", 0.5);
578 %! assert (matrix_type (spdiags (1i*randn (10,3),[-1,0,1],10,10)), "Tridiagonal");
579 %! a = 1i*(rand (9,1)-0.5);
580 %! a = [[a;0],ones(10,1),[0;-a]];
581 %! assert (matrix_type (spdiags (a,[-1,0,1],10,10)), "Tridiagonal Positive Definite");
582 %! spparms ("bandden", bnd);
583 %!test
584 %! bnd = spparms ("bandden");
585 %! spparms ("bandden", 0.5);
586 %! assert (matrix_type (spdiags (1i*randn (10,4),[-2:1],10,10)), "Banded");
587 %! a = 1i*(rand (9,2)-0.5);
588 %! a = [[a;[0,0]],ones(10,1),[[0;-a(:,2)],[0;0;-a(1:8,1)]]];
589 %! assert (matrix_type (spdiags (a,[-2:2],10,10)), "Banded Positive Definite");
590 %! spparms ("bandden", bnd);
591 %!test
592 %! a = [speye(10,10),[sparse(9,1);1i];-1,sparse(1,9),1];
593 %! assert (matrix_type (a), "Full");
594 %! assert (matrix_type (a'*a), "Positive Definite");
595 
596 %!assert (matrix_type (1i*speye (10,11)), "Diagonal")
597 %!assert (matrix_type (1i*speye (10,11)([2:10,1],:)), "Permuted Diagonal")
598 %!assert (matrix_type (1i*speye (11,10)), "Diagonal")
599 %!assert (matrix_type (1i*speye (11,10)([2:11,1],:)), "Permuted Diagonal")
600 %#!assert (matrix_type ([[speye(10,10);sparse(1,10)],[[1i,1i];sparse(9,2);[1i,1i]]]), "Upper")
601 %#!assert (matrix_type ([[speye(10,10);sparse(1,10)],[[1i,1i];sparse(9,2);[1i,1i]]](:,[2,1,3:12])), "Permuted Upper")
602 %!assert (matrix_type ([speye(11,9),[1i;sparse(8,1);1i;0]]), "Upper")
603 %!assert (matrix_type ([speye(11,9),[1i;sparse(8,1);1i;0]](:,[2,1,3:10])), "Permuted Upper")
604 %#!assert (matrix_type ([speye(10,10),sparse(10,1);[1i;1i],sparse(2,9),[1i;1i]]), "Lower")
605 %#!assert (matrix_type ([speye(10,10),sparse(10,1);[1i;1i],sparse(2,9),[1i;1i]]([2,1,3:12],:)), "Permuted Lower")
606 %!assert (matrix_type ([speye(9,11);[1i,sparse(1,8),1i,0]]), "Lower")
607 %!assert (matrix_type ([speye(9,11);[1i,sparse(1,8),1i,0]]([2,1,3:10],:)), "Permuted Lower")
608 %!assert (matrix_type (1i*spdiags(randn(10,4),[-2:1],10,9)), "Rectangular")
609 
610 %!test
611 %! a = matrix_type (spdiags (randn (10,3),[-1,0,1],10,10), "Singular");
612 %! assert (matrix_type (a), "Singular");
613 
614 %!assert (matrix_type (triu (ones(10,10))), "Upper")
615 %!assert (matrix_type (triu (ones(10,10),-1)), "Full")
616 %!assert (matrix_type (tril (ones(10,10))), "Lower")
617 %!assert (matrix_type (tril (ones(10,10),1)), "Full")
618 %!assert (matrix_type (10*eye (10,10) + ones (10,10)), "Positive Definite")
619 %!assert (matrix_type (ones (11,10)), "Rectangular")
620 %!test
621 %! a = matrix_type (ones (10,10), "Singular");
622 %! assert (matrix_type (a), "Singular");
623 
624 %!assert (matrix_type (triu (1i*ones (10,10))), "Upper")
625 %!assert (matrix_type (triu (1i*ones (10,10),-1)), "Full")
626 %!assert (matrix_type (tril (1i*ones (10,10))), "Lower")
627 %!assert (matrix_type (tril (1i*ones (10,10),1)), "Full")
628 %!assert (matrix_type (10*eye (10,10) + 1i*triu (ones (10,10),1) -1i*tril (ones (10,10),-1)), "Positive Definite")
629 %!assert (matrix_type (ones (11,10)), "Rectangular")
630 %!test
631 %! a = matrix_type (ones (10,10), "Singular");
632 %! assert (matrix_type (a), "Singular");
633 */