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
ov-re-mat.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2013 John W. Eaton
4 Copyright (C) 2009-2010 VZLU Prague
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <iostream>
29 #include <limits>
30 #include <vector>
31 
32 #include "data-conv.h"
33 #include "lo-ieee.h"
34 #include "lo-utils.h"
35 #include "lo-specfun.h"
36 #include "lo-mappers.h"
37 #include "mach-info.h"
38 #include "mx-base.h"
39 #include "quit.h"
40 #include "oct-locbuf.h"
41 
42 #include "defun.h"
43 #include "gripes.h"
44 #include "mxarray.h"
45 #include "oct-obj.h"
46 #include "oct-lvalue.h"
47 #include "oct-stream.h"
48 #include "ops.h"
49 #include "ov-base.h"
50 #include "ov-base-mat.h"
51 #include "ov-base-mat.cc"
52 #include "ov-scalar.h"
53 #include "ov-re-mat.h"
54 #include "ov-flt-re-mat.h"
55 #include "ov-complex.h"
56 #include "ov-cx-mat.h"
57 #include "ov-re-sparse.h"
58 #include "ov-re-diag.h"
59 #include "ov-cx-diag.h"
60 #include "ov-lazy-idx.h"
61 #include "ov-perm.h"
62 #include "ov-type-conv.h"
63 #include "pr-output.h"
64 #include "variables.h"
65 
66 #include "byte-swap.h"
67 #include "ls-oct-ascii.h"
68 #include "ls-utils.h"
69 #include "ls-hdf5.h"
70 
71 template class octave_base_matrix<NDArray>;
72 
74 
76 
77 static octave_base_value *
79 {
81 
82  return new octave_float_matrix (v.float_array_value ());
83 }
84 
87 {
91 }
92 
95 {
96  octave_base_value *retval = 0;
97 
98  if (matrix.nelem () == 1)
99  retval = new octave_scalar (matrix (0));
100 
101  return retval;
102 }
103 
104 double
106 {
107  double retval = lo_ieee_nan_value ();
108 
109  if (numel () > 0)
110  {
111  gripe_implicit_conversion ("Octave:array-to-scalar",
112  "real matrix", "real scalar");
113 
114  retval = matrix (0, 0);
115  }
116  else
117  gripe_invalid_conversion ("real matrix", "real scalar");
118 
119  return retval;
120 }
121 
122 float
124 {
125  float retval = lo_ieee_float_nan_value ();
126 
127  if (numel () > 0)
128  {
129  gripe_implicit_conversion ("Octave:array-to-scalar",
130  "real matrix", "real scalar");
131 
132  retval = matrix (0, 0);
133  }
134  else
135  gripe_invalid_conversion ("real matrix", "real scalar");
136 
137  return retval;
138 }
139 
140 // FIXME
141 
142 Matrix
144 {
145  return matrix.matrix_value ();
146 }
147 
150 {
151  return FloatMatrix (matrix.matrix_value ());
152 }
153 
154 Complex
156 {
157  double tmp = lo_ieee_nan_value ();
158 
159  Complex retval (tmp, tmp);
160 
161  if (rows () > 0 && columns () > 0)
162  {
163  gripe_implicit_conversion ("Octave:array-to-scalar",
164  "real matrix", "complex scalar");
165 
166  retval = matrix (0, 0);
167  }
168  else
169  gripe_invalid_conversion ("real matrix", "complex scalar");
170 
171  return retval;
172 }
173 
176 {
177  float tmp = lo_ieee_float_nan_value ();
178 
179  FloatComplex retval (tmp, tmp);
180 
181  if (rows () > 0 && columns () > 0)
182  {
183  gripe_implicit_conversion ("Octave:array-to-scalar",
184  "real matrix", "complex scalar");
185 
186  retval = matrix (0, 0);
187  }
188  else
189  gripe_invalid_conversion ("real matrix", "complex scalar");
190 
191  return retval;
192 }
193 
194 // FIXME
195 
198 {
199  return ComplexMatrix (matrix.matrix_value ());
200 }
201 
204 {
206 }
207 
210 {
211  return ComplexNDArray (matrix);
212 }
213 
216 {
217  return FloatComplexNDArray (matrix);
218 }
219 
222 {
223  if (matrix.any_element_is_nan ())
225  else if (warn && matrix.any_element_not_one_or_zero ())
227 
228  return boolNDArray (matrix);
229 }
230 
233 {
234  charNDArray retval (dims ());
235 
236  octave_idx_type nel = numel ();
237 
238  for (octave_idx_type i = 0; i < nel; i++)
239  retval.elem (i) = static_cast<char>(matrix.elem (i));
240 
241  return retval;
242 }
243 
246 {
247  return SparseMatrix (matrix.matrix_value ());
248 }
249 
252 {
253  // FIXME: Need a SparseComplexMatrix (Matrix) constructor to make
254  // this function more efficient. Then this should become
255  // return SparseComplexMatrix (matrix.matrix_value ());
257 }
258 
261 {
262  octave_value retval;
263  if (k == 0 && matrix.ndims () == 2
264  && (matrix.rows () == 1 || matrix.columns () == 1))
265  retval = DiagMatrix (DiagArray2<double> (matrix));
266  else
268 
269  return retval;
270 }
271 
274 {
275  octave_value retval;
276 
277  if (matrix.ndims () == 2
278  && (matrix.rows () == 1 || matrix.columns () == 1))
279  {
280  Matrix mat = matrix.matrix_value ();
281 
282  retval = mat.diag (m, n);
283  }
284  else
285  error ("diag: expecting vector argument");
286 
287  return retval;
288 }
289 
290 // We override these two functions to allow reshaping both
291 // the matrix and the index cache.
293 octave_matrix::reshape (const dim_vector& new_dims) const
294 {
295  if (idx_cache)
296  {
297  return new octave_matrix (matrix.reshape (new_dims),
298  idx_vector (idx_cache->as_array ().reshape (new_dims),
299  idx_cache->extent (0)));
300  }
301  else
302  return octave_base_matrix<NDArray>::reshape (new_dims);
303 }
304 
307 {
308  if (idx_cache)
309  {
310  return new octave_matrix (matrix.squeeze (),
312  idx_cache->extent (0)));
313  }
314  else
316 }
317 
320 {
321  if (idx_cache)
322  {
323  // This is a valid index matrix, so sort via integers because it's
324  // generally more efficient.
325  return octave_lazy_index (*idx_cache).sort (dim, mode);
326  }
327  else
328  return octave_base_matrix<NDArray>::sort (dim, mode);
329 }
330 
333  sortmode mode) const
334 {
335  if (idx_cache)
336  {
337  // This is a valid index matrix, so sort via integers because it's
338  // generally more efficient.
339  return octave_lazy_index (*idx_cache).sort (sidx, dim, mode);
340  }
341  else
342  return octave_base_matrix<NDArray>::sort (sidx, dim, mode);
343 }
344 
345 sortmode
347 {
348  if (idx_cache)
349  {
350  // This is a valid index matrix, so check via integers because it's
351  // generally more efficient.
352  return idx_cache->as_array ().is_sorted (mode);
353  }
354  else
356 }
359 {
360  if (idx_cache)
361  {
362  // This is a valid index matrix, so sort via integers because it's
363  // generally more efficient.
364  return octave_lazy_index (*idx_cache).sort_rows_idx (mode);
365  }
366  else
368 }
369 
370 sortmode
372 {
373  if (idx_cache)
374  {
375  // This is a valid index matrix, so check via integers because it's
376  // generally more efficient.
377  return idx_cache->as_array ().is_sorted_rows (mode);
378  }
379  else
381 }
382 
385 {
386  octave_value retval;
387  dim_vector dv = dims ();
388  octave_idx_type nel = dv.numel ();
389 
390  charNDArray chm (dv);
391 
392  bool warned = false;
393 
394  for (octave_idx_type i = 0; i < nel; i++)
395  {
396  octave_quit ();
397 
398  double d = matrix (i);
399 
400  if (xisnan (d))
401  {
403  return retval;
404  }
405  else
406  {
407  int ival = NINT (d);
408 
409  if (ival < 0 || ival > std::numeric_limits<unsigned char>::max ())
410  {
411  // FIXME: is there something better we could do?
412 
413  ival = 0;
414 
415  if (! warned)
416  {
417  ::warning ("range error for conversion to character value");
418  warned = true;
419  }
420  }
421 
422  chm (i) = static_cast<char> (ival);
423  }
424  }
425 
426  retval = octave_value (chm, type);
427 
428  return retval;
429 }
430 
431 bool
432 octave_matrix::save_ascii (std::ostream& os)
433 {
434  dim_vector d = dims ();
435 
436  if (d.length () > 2)
437  {
438  NDArray tmp = array_value ();
439 
440  os << "# ndims: " << d.length () << "\n";
441 
442  for (int i=0; i < d.length (); i++)
443  os << " " << d (i);
444 
445  os << "\n" << tmp;
446  }
447  else
448  {
449  // Keep this case, rather than use generic code above for backward
450  // compatiability. Makes load_ascii much more complex!!
451  os << "# rows: " << rows () << "\n"
452  << "# columns: " << columns () << "\n";
453 
454  os << matrix_value ();
455  }
456 
457  return true;
458 }
459 
460 bool
461 octave_matrix::load_ascii (std::istream& is)
462 {
463  bool success = true;
464 
466 
467  keywords[0] = "ndims";
468  keywords[1] = "rows";
469 
470  std::string kw;
471  octave_idx_type val = 0;
472 
473  if (extract_keyword (is, keywords, kw, val, true))
474  {
475  if (kw == "ndims")
476  {
477  int mdims = static_cast<int> (val);
478 
479  if (mdims >= 0)
480  {
481  dim_vector dv;
482  dv.resize (mdims);
483 
484  for (int i = 0; i < mdims; i++)
485  is >> dv(i);
486 
487  if (is)
488  {
489  NDArray tmp(dv);
490 
491  is >> tmp;
492 
493  if (is)
494  matrix = tmp;
495  else
496  {
497  error ("load: failed to load matrix constant");
498  success = false;
499  }
500  }
501  else
502  {
503  error ("load: failed to read dimensions");
504  success = false;
505  }
506  }
507  else
508  {
509  error ("load: failed to extract number of dimensions");
510  success = false;
511  }
512  }
513  else if (kw == "rows")
514  {
515  octave_idx_type nr = val;
516  octave_idx_type nc = 0;
517 
518  if (nr >= 0 && extract_keyword (is, "columns", nc) && nc >= 0)
519  {
520  if (nr > 0 && nc > 0)
521  {
522  Matrix tmp (nr, nc);
523  is >> tmp;
524  if (is)
525  matrix = tmp;
526  else
527  {
528  error ("load: failed to load matrix constant");
529  success = false;
530  }
531  }
532  else if (nr == 0 || nc == 0)
533  matrix = Matrix (nr, nc);
534  else
535  panic_impossible ();
536  }
537  else
538  {
539  error ("load: failed to extract number of rows and columns");
540  success = false;
541  }
542  }
543  else
544  panic_impossible ();
545  }
546  else
547  {
548  error ("load: failed to extract number of rows and columns");
549  success = false;
550  }
551 
552  return success;
553 }
554 
555 bool
556 octave_matrix::save_binary (std::ostream& os, bool& save_as_floats)
557 {
558 
559  dim_vector d = dims ();
560  if (d.length () < 1)
561  return false;
562 
563  // Use negative value for ndims to differentiate with old format!!
564  int32_t tmp = - d.length ();
565  os.write (reinterpret_cast<char *> (&tmp), 4);
566  for (int i = 0; i < d.length (); i++)
567  {
568  tmp = d(i);
569  os.write (reinterpret_cast<char *> (&tmp), 4);
570  }
571 
572  NDArray m = array_value ();
573  save_type st = LS_DOUBLE;
574  if (save_as_floats)
575  {
576  if (m.too_large_for_float ())
577  {
578  warning ("save: some values too large to save as floats --");
579  warning ("save: saving as doubles instead");
580  }
581  else
582  st = LS_FLOAT;
583  }
584  else if (d.numel () > 8192) // FIXME: make this configurable.
585  {
586  double max_val, min_val;
587  if (m.all_integers (max_val, min_val))
588  st = get_save_type (max_val, min_val);
589  }
590 
591  const double *mtmp = m.data ();
592  write_doubles (os, mtmp, st, d.numel ());
593 
594  return true;
595 }
596 
597 bool
598 octave_matrix::load_binary (std::istream& is, bool swap,
600 {
601  char tmp;
602  int32_t mdims;
603  if (! is.read (reinterpret_cast<char *> (&mdims), 4))
604  return false;
605  if (swap)
606  swap_bytes<4> (&mdims);
607  if (mdims < 0)
608  {
609  mdims = - mdims;
610  int32_t di;
611  dim_vector dv;
612  dv.resize (mdims);
613 
614  for (int i = 0; i < mdims; i++)
615  {
616  if (! is.read (reinterpret_cast<char *> (&di), 4))
617  return false;
618  if (swap)
619  swap_bytes<4> (&di);
620  dv(i) = di;
621  }
622 
623  // Convert an array with a single dimension to be a row vector.
624  // Octave should never write files like this, other software
625  // might.
626 
627  if (mdims == 1)
628  {
629  mdims = 2;
630  dv.resize (mdims);
631  dv(1) = dv(0);
632  dv(0) = 1;
633  }
634 
635  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
636  return false;
637 
638  NDArray m(dv);
639  double *re = m.fortran_vec ();
640  read_doubles (is, re, static_cast<save_type> (tmp), dv.numel (),
641  swap, fmt);
642  if (error_state || ! is)
643  return false;
644  matrix = m;
645  }
646  else
647  {
648  int32_t nr, nc;
649  nr = mdims;
650  if (! is.read (reinterpret_cast<char *> (&nc), 4))
651  return false;
652  if (swap)
653  swap_bytes<4> (&nc);
654  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
655  return false;
656  Matrix m (nr, nc);
657  double *re = m.fortran_vec ();
658  octave_idx_type len = nr * nc;
659  read_doubles (is, re, static_cast<save_type> (tmp), len, swap, fmt);
660  if (error_state || ! is)
661  return false;
662  matrix = m;
663  }
664  return true;
665 }
666 
667 #if defined (HAVE_HDF5)
668 
669 bool
670 octave_matrix::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
671 {
672  dim_vector dv = dims ();
673  int empty = save_hdf5_empty (loc_id, name, dv);
674  if (empty)
675  return (empty > 0);
676 
677  int rank = dv.length ();
678  hid_t space_hid = -1, data_hid = -1;
679  bool retval = true;
680  NDArray m = array_value ();
681 
682  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
683 
684  // Octave uses column-major, while HDF5 uses row-major ordering
685  for (int i = 0; i < rank; i++)
686  hdims[i] = dv (rank-i-1);
687 
688  space_hid = H5Screate_simple (rank, hdims, 0);
689 
690  if (space_hid < 0) return false;
691 
692  hid_t save_type_hid = H5T_NATIVE_DOUBLE;
693 
694  if (save_as_floats)
695  {
696  if (m.too_large_for_float ())
697  {
698  warning ("save: some values too large to save as floats --");
699  warning ("save: saving as doubles instead");
700  }
701  else
702  save_type_hid = H5T_NATIVE_FLOAT;
703  }
704 #if HAVE_HDF5_INT2FLOAT_CONVERSIONS
705  // hdf5 currently doesn't support float/integer conversions
706  else
707  {
708  double max_val, min_val;
709 
710  if (m.all_integers (max_val, min_val))
711  save_type_hid
712  = save_type_to_hdf5 (get_save_type (max_val, min_val));
713  }
714 #endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */
715 
716 #if HAVE_HDF5_18
717  data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
718  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
719 #else
720  data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
721  H5P_DEFAULT);
722 #endif
723  if (data_hid < 0)
724  {
725  H5Sclose (space_hid);
726  return false;
727  }
728 
729  double *mtmp = m.fortran_vec ();
730  retval = H5Dwrite (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
731  H5P_DEFAULT, mtmp) >= 0;
732 
733  H5Dclose (data_hid);
734  H5Sclose (space_hid);
735 
736  return retval;
737 }
738 
739 bool
740 octave_matrix::load_hdf5 (hid_t loc_id, const char *name)
741 {
742  bool retval = false;
743 
744  dim_vector dv;
745  int empty = load_hdf5_empty (loc_id, name, dv);
746  if (empty > 0)
747  matrix.resize (dv);
748  if (empty)
749  return (empty > 0);
750 
751 #if HAVE_HDF5_18
752  hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
753 #else
754  hid_t data_hid = H5Dopen (loc_id, name);
755 #endif
756  hid_t space_id = H5Dget_space (data_hid);
757 
758  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
759 
760  if (rank < 1)
761  {
762  H5Sclose (space_id);
763  H5Dclose (data_hid);
764  return false;
765  }
766 
767  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
768  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
769 
770  H5Sget_simple_extent_dims (space_id, hdims, maxdims);
771 
772  // Octave uses column-major, while HDF5 uses row-major ordering
773  if (rank == 1)
774  {
775  dv.resize (2);
776  dv(0) = 1;
777  dv(1) = hdims[0];
778  }
779  else
780  {
781  dv.resize (rank);
782  for (hsize_t i = 0, j = rank - 1; i < rank; i++, j--)
783  dv(j) = hdims[i];
784  }
785 
786  NDArray m (dv);
787  double *re = m.fortran_vec ();
788  if (H5Dread (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
789  H5P_DEFAULT, re) >= 0)
790  {
791  retval = true;
792  matrix = m;
793  }
794 
795  H5Sclose (space_id);
796  H5Dclose (data_hid);
797 
798  return retval;
799 }
800 
801 #endif
802 
803 void
804 octave_matrix::print_raw (std::ostream& os,
805  bool pr_as_read_syntax) const
806 {
807  octave_print_internal (os, matrix, pr_as_read_syntax,
809 }
810 
811 mxArray *
813 {
814  mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxREAL);
815 
816  double *pr = static_cast<double *> (retval->get_data ());
817 
818  mwSize nel = numel ();
819 
820  const double *p = matrix.data ();
821 
822  for (mwIndex i = 0; i < nel; i++)
823  pr[i] = p[i];
824 
825  return retval;
826 }
827 
828 // This uses a smarter strategy for doing the complex->real mappers. We
829 // allocate an array for a real result and keep filling it until a complex
830 // result is produced.
831 static octave_value
832 do_rc_map (const NDArray& a, Complex (&fcn) (double))
833 {
834  octave_idx_type n = a.numel ();
835  NoAlias<NDArray> rr (a.dims ());
836 
837  for (octave_idx_type i = 0; i < n; i++)
838  {
839  octave_quit ();
840 
841  Complex tmp = fcn (a(i));
842  if (tmp.imag () == 0.0)
843  rr(i) = tmp.real ();
844  else
845  {
846  NoAlias<ComplexNDArray> rc (a.dims ());
847 
848  for (octave_idx_type j = 0; j < i; j++)
849  rc(j) = rr(j);
850 
851  rc(i) = tmp;
852 
853  for (octave_idx_type j = i+1; j < n; j++)
854  {
855  octave_quit ();
856 
857  rc(j) = fcn (a(j));
858  }
859 
860  return new octave_complex_matrix (rc);
861  }
862  }
863 
864  return rr;
865 }
866 
869 {
870  switch (umap)
871  {
872  case umap_imag:
873  return NDArray (matrix.dims (), 0.0);
874 
875  case umap_real:
876  case umap_conj:
877  return matrix;
878 
879  // Mappers handled specially.
880 #define ARRAY_METHOD_MAPPER(UMAP, FCN) \
881  case umap_ ## UMAP: \
882  return octave_value (matrix.FCN ())
883 
885  ARRAY_METHOD_MAPPER (isnan, isnan);
886  ARRAY_METHOD_MAPPER (isinf, isinf);
887  ARRAY_METHOD_MAPPER (finite, isfinite);
888 
889 #define ARRAY_MAPPER(UMAP, TYPE, FCN) \
890  case umap_ ## UMAP: \
891  return octave_value (matrix.map<TYPE> (FCN))
892 
893 #define RC_ARRAY_MAPPER(UMAP, TYPE, FCN) \
894  case umap_ ## UMAP: \
895  return do_rc_map (matrix, FCN)
896 
899  ARRAY_MAPPER (angle, double, ::arg);
900  ARRAY_MAPPER (arg, double, ::arg);
902  ARRAY_MAPPER (asinh, double, ::asinh);
903  ARRAY_MAPPER (atan, double, ::atan);
905  ARRAY_MAPPER (erf, double, ::erf);
906  ARRAY_MAPPER (erfinv, double, ::erfinv);
907  ARRAY_MAPPER (erfcinv, double, ::erfcinv);
908  ARRAY_MAPPER (erfc, double, ::erfc);
909  ARRAY_MAPPER (erfcx, double, ::erfcx);
910  ARRAY_MAPPER (erfi, double, ::erfi);
911  ARRAY_MAPPER (dawson, double, ::dawson);
912  ARRAY_MAPPER (gamma, double, xgamma);
913  RC_ARRAY_MAPPER (lgamma, Complex, rc_lgamma);
914  ARRAY_MAPPER (cbrt, double, ::cbrt);
915  ARRAY_MAPPER (ceil, double, ::ceil);
916  ARRAY_MAPPER (cos, double, ::cos);
917  ARRAY_MAPPER (cosh, double, ::cosh);
918  ARRAY_MAPPER (exp, double, ::exp);
919  ARRAY_MAPPER (expm1, double, ::expm1);
920  ARRAY_MAPPER (fix, double, ::fix);
921  ARRAY_MAPPER (floor, double, ::floor);
924  RC_ARRAY_MAPPER (log10, Complex, rc_log10);
926  ARRAY_MAPPER (round, double, xround);
927  ARRAY_MAPPER (roundb, double, xroundb);
928  ARRAY_MAPPER (signum, double, ::signum);
929  ARRAY_MAPPER (sin, double, ::sin);
930  ARRAY_MAPPER (sinh, double, ::sinh);
932  ARRAY_MAPPER (tan, double, ::tan);
933  ARRAY_MAPPER (tanh, double, ::tanh);
934  ARRAY_MAPPER (isna, bool, octave_is_NA);
935  ARRAY_MAPPER (xsignbit, double, xsignbit);
936 
937  default:
938  if (umap >= umap_xisalnum && umap <= umap_xtoupper)
939  {
940  octave_value str_conv = convert_to_str (true, true);
941  return error_state ? octave_value () : str_conv.map (umap);
942  }
943  else
944  return octave_base_value::map (umap);
945  }
946 }
947 
948 DEFUN (double, args, ,
949  "-*- texinfo -*-\n\
950 @deftypefn {Built-in Function} {} double (@var{x})\n\
951 Convert @var{x} to double precision type.\n\
952 @seealso{single}\n\
953 @end deftypefn")
954 {
955  // The OCTAVE_TYPE_CONV_BODY3 macro declares retval, so they go
956  // inside their own scopes, and we don't declare retval here to
957  // avoid a shadowed declaration warning.
958 
959  if (args.length () == 1)
960  {
961  if (args(0).is_perm_matrix ())
962  {
964  }
965  else if (args(0).is_diag_matrix ())
966  {
967  if (args(0).is_complex_type ())
968  {
971  }
972  else
973  {
975  octave_scalar);
976  }
977  }
978  else if (args(0).is_sparse_type ())
979  {
980  if (args(0).is_complex_type ())
981  {
984  }
985  else
986  {
988  octave_scalar);
989  }
990  }
991  else if (args(0).is_complex_type ())
992  {
995  }
996  else
997  {
999  }
1000  }
1001  else
1002  print_usage ();
1003 
1004  return octave_value ();
1005 }
1006 
1007 /*
1008 %!assert (class (double (single (1))), "double")
1009 %!assert (class (double (single (1 + i))), "double")
1010 %!assert (class (double (int8 (1))), "double")
1011 %!assert (class (double (uint8 (1))), "double")
1012 %!assert (class (double (int16 (1))), "double")
1013 %!assert (class (double (uint16 (1))), "double")
1014 %!assert (class (double (int32 (1))), "double")
1015 %!assert (class (double (uint32 (1))), "double")
1016 %!assert (class (double (int64 (1))), "double")
1017 %!assert (class (double (uint64 (1))), "double")
1018 %!assert (class (double (true)), "double")
1019 %!assert (class (double ("A")), "double")
1020 %!test
1021 %! x = sparse (logical ([1 0; 0 1]));
1022 %! y = double (x);
1023 %! assert (class (x), "logical");
1024 %! assert (class (y), "double");
1025 %! assert (issparse (y));
1026 %!test
1027 %! x = diag (single ([1 3 2]));
1028 %! y = double (x);
1029 %! assert (class (x), "single");
1030 %! assert (class (y), "double");
1031 %!test
1032 %! x = diag (single ([i 3 2]));
1033 %! y = double (x);
1034 %! assert (class (x), "single");
1035 %! assert (class (y), "double");
1036 */