ov-re-mat.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 Copyright (C) 2009-2010 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include <climits>
00029 
00030 #include <iostream>
00031 #include <vector>
00032 
00033 #include "data-conv.h"
00034 #include "lo-ieee.h"
00035 #include "lo-utils.h"
00036 #include "lo-specfun.h"
00037 #include "lo-mappers.h"
00038 #include "mach-info.h"
00039 #include "mx-base.h"
00040 #include "quit.h"
00041 #include "oct-locbuf.h"
00042 
00043 #include "defun.h"
00044 #include "gripes.h"
00045 #include "oct-obj.h"
00046 #include "oct-lvalue.h"
00047 #include "oct-stream.h"
00048 #include "ops.h"
00049 #include "ov-base.h"
00050 #include "ov-base-mat.h"
00051 #include "ov-base-mat.cc"
00052 #include "ov-scalar.h"
00053 #include "ov-re-mat.h"
00054 #include "ov-flt-re-mat.h"
00055 #include "ov-complex.h"
00056 #include "ov-cx-mat.h"
00057 #include "ov-re-sparse.h"
00058 #include "ov-re-diag.h"
00059 #include "ov-cx-diag.h"
00060 #include "ov-lazy-idx.h"
00061 #include "ov-perm.h"
00062 #include "ov-type-conv.h"
00063 #include "pr-output.h"
00064 #include "variables.h"
00065 
00066 #include "byte-swap.h"
00067 #include "ls-oct-ascii.h"
00068 #include "ls-utils.h"
00069 #include "ls-hdf5.h"
00070 
00071 #if ! defined (UCHAR_MAX)
00072 #define UCHAR_MAX 255
00073 #endif
00074 
00075 template class octave_base_matrix<NDArray>;
00076 
00077 DEFINE_OCTAVE_ALLOCATOR (octave_matrix);
00078 
00079 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_matrix, "matrix", "double");
00080 
00081 static octave_base_value *
00082 default_numeric_demotion_function (const octave_base_value& a)
00083 {
00084   CAST_CONV_ARG (const octave_matrix&);
00085 
00086   return new octave_float_matrix (v.float_array_value ());
00087 }
00088 
00089 octave_base_value::type_conv_info
00090 octave_matrix::numeric_demotion_function (void) const
00091 {
00092   return octave_base_value::type_conv_info(default_numeric_demotion_function,
00093                                            octave_float_matrix::static_type_id ());
00094 }
00095 
00096 octave_base_value *
00097 octave_matrix::try_narrowing_conversion (void)
00098 {
00099   octave_base_value *retval = 0;
00100 
00101   if (matrix.nelem () == 1)
00102     retval = new octave_scalar (matrix (0));
00103 
00104   return retval;
00105 }
00106 
00107 double
00108 octave_matrix::double_value (bool) const
00109 {
00110   double retval = lo_ieee_nan_value ();
00111 
00112   if (numel () > 0)
00113     {
00114       gripe_implicit_conversion ("Octave:array-as-scalar",
00115                                  "real matrix", "real scalar");
00116 
00117       retval = matrix (0, 0);
00118     }
00119   else
00120     gripe_invalid_conversion ("real matrix", "real scalar");
00121 
00122   return retval;
00123 }
00124 
00125 float
00126 octave_matrix::float_value (bool) const
00127 {
00128   float retval = lo_ieee_float_nan_value ();
00129 
00130   if (numel () > 0)
00131     {
00132       gripe_implicit_conversion ("Octave:array-as-scalar",
00133                                  "real matrix", "real scalar");
00134 
00135       retval = matrix (0, 0);
00136     }
00137   else
00138     gripe_invalid_conversion ("real matrix", "real scalar");
00139 
00140   return retval;
00141 }
00142 
00143 // FIXME
00144 
00145 Matrix
00146 octave_matrix::matrix_value (bool) const
00147 {
00148   return matrix.matrix_value ();
00149 }
00150 
00151 FloatMatrix
00152 octave_matrix::float_matrix_value (bool) const
00153 {
00154   return FloatMatrix (matrix.matrix_value ());
00155 }
00156 
00157 Complex
00158 octave_matrix::complex_value (bool) const
00159 {
00160   double tmp = lo_ieee_nan_value ();
00161 
00162   Complex retval (tmp, tmp);
00163 
00164   if (rows () > 0 && columns () > 0)
00165     {
00166       gripe_implicit_conversion ("Octave:array-as-scalar",
00167                                  "real matrix", "complex scalar");
00168 
00169       retval = matrix (0, 0);
00170     }
00171   else
00172     gripe_invalid_conversion ("real matrix", "complex scalar");
00173 
00174   return retval;
00175 }
00176 
00177 FloatComplex
00178 octave_matrix::float_complex_value (bool) const
00179 {
00180   float tmp = lo_ieee_float_nan_value ();
00181 
00182   FloatComplex retval (tmp, tmp);
00183 
00184   if (rows () > 0 && columns () > 0)
00185     {
00186       gripe_implicit_conversion ("Octave:array-as-scalar",
00187                                  "real matrix", "complex scalar");
00188 
00189       retval = matrix (0, 0);
00190     }
00191   else
00192     gripe_invalid_conversion ("real matrix", "complex scalar");
00193 
00194   return retval;
00195 }
00196 
00197 // FIXME
00198 
00199 ComplexMatrix
00200 octave_matrix::complex_matrix_value (bool) const
00201 {
00202   return ComplexMatrix (matrix.matrix_value ());
00203 }
00204 
00205 FloatComplexMatrix
00206 octave_matrix::float_complex_matrix_value (bool) const
00207 {
00208   return FloatComplexMatrix (matrix.matrix_value ());
00209 }
00210 
00211 ComplexNDArray
00212 octave_matrix::complex_array_value (bool) const
00213 {
00214   return ComplexNDArray (matrix);
00215 }
00216 
00217 FloatComplexNDArray
00218 octave_matrix::float_complex_array_value (bool) const
00219 {
00220   return FloatComplexNDArray (matrix);
00221 }
00222 
00223 boolNDArray
00224 octave_matrix::bool_array_value (bool warn) const
00225 {
00226   if (matrix.any_element_is_nan ())
00227     gripe_nan_to_logical_conversion ();
00228   else if (warn && matrix.any_element_not_one_or_zero ())
00229     gripe_logical_conversion ();
00230 
00231   return boolNDArray (matrix);
00232 }
00233 
00234 charNDArray
00235 octave_matrix::char_array_value (bool) const
00236 {
00237   charNDArray retval (dims ());
00238 
00239   octave_idx_type nel = numel ();
00240 
00241   for (octave_idx_type i = 0; i < nel; i++)
00242     retval.elem (i) = static_cast<char>(matrix.elem (i));
00243 
00244   return retval;
00245 }
00246 
00247 SparseMatrix
00248 octave_matrix::sparse_matrix_value (bool) const
00249 {
00250   return SparseMatrix (matrix.matrix_value ());
00251 }
00252 
00253 SparseComplexMatrix
00254 octave_matrix::sparse_complex_matrix_value (bool) const
00255 {
00256   // FIXME Need a SparseComplexMatrix (Matrix) constructor to make
00257   // this function more efficient. Then this should become
00258   // return SparseComplexMatrix (matrix.matrix_value ());
00259   return SparseComplexMatrix (sparse_matrix_value ());
00260 }
00261 
00262 octave_value
00263 octave_matrix::diag (octave_idx_type k) const
00264 {
00265   octave_value retval;
00266   if (k == 0 && matrix.ndims () == 2
00267       && (matrix.rows () == 1 || matrix.columns () == 1))
00268     retval = DiagMatrix (DiagArray2<double> (matrix));
00269   else
00270     retval = octave_base_matrix<NDArray>::diag (k);
00271 
00272   return retval;
00273 }
00274 
00275 // We override these two functions to allow reshaping both
00276 // the matrix and the index cache.
00277 octave_value
00278 octave_matrix::reshape (const dim_vector& new_dims) const
00279 {
00280   if (idx_cache)
00281     {
00282       return new octave_matrix (matrix.reshape (new_dims),
00283                                 idx_vector (idx_cache->as_array ().reshape (new_dims),
00284                                             idx_cache->extent (0)));
00285     }
00286   else
00287     return octave_base_matrix<NDArray>::reshape (new_dims);
00288 }
00289 
00290 octave_value
00291 octave_matrix::squeeze (void) const
00292 {
00293   if (idx_cache)
00294     {
00295       return new octave_matrix (matrix.squeeze (),
00296                                 idx_vector (idx_cache->as_array ().squeeze (),
00297                                             idx_cache->extent (0)));
00298     }
00299   else
00300     return octave_base_matrix<NDArray>::squeeze ();
00301 }
00302 
00303 octave_value
00304 octave_matrix::sort (octave_idx_type dim, sortmode mode) const
00305 {
00306   if (idx_cache)
00307     {
00308       // This is a valid index matrix, so sort via integers because it's
00309       // generally more efficient.
00310       return octave_lazy_index (*idx_cache).sort (dim, mode);
00311     }
00312   else
00313     return octave_base_matrix<NDArray>::sort (dim, mode);
00314 }
00315 
00316 octave_value
00317 octave_matrix::sort (Array<octave_idx_type> &sidx, octave_idx_type dim,
00318                      sortmode mode) const
00319 {
00320   if (idx_cache)
00321     {
00322       // This is a valid index matrix, so sort via integers because it's
00323       // generally more efficient.
00324       return octave_lazy_index (*idx_cache).sort (sidx, dim, mode);
00325     }
00326   else
00327     return octave_base_matrix<NDArray>::sort (sidx, dim, mode);
00328 }
00329 
00330 sortmode
00331 octave_matrix::is_sorted (sortmode mode) const
00332 {
00333   if (idx_cache)
00334     {
00335       // This is a valid index matrix, so check via integers because it's
00336       // generally more efficient.
00337       return idx_cache->as_array ().is_sorted (mode);
00338     }
00339   else
00340     return octave_base_matrix<NDArray>::is_sorted (mode);
00341 }
00342 Array<octave_idx_type>
00343 octave_matrix::sort_rows_idx (sortmode mode) const
00344 {
00345   if (idx_cache)
00346     {
00347       // This is a valid index matrix, so sort via integers because it's
00348       // generally more efficient.
00349       return octave_lazy_index (*idx_cache).sort_rows_idx (mode);
00350     }
00351   else
00352     return octave_base_matrix<NDArray>::sort_rows_idx (mode);
00353 }
00354 
00355 sortmode
00356 octave_matrix::is_sorted_rows (sortmode mode) const
00357 {
00358   if (idx_cache)
00359     {
00360       // This is a valid index matrix, so check via integers because it's
00361       // generally more efficient.
00362       return idx_cache->as_array ().is_sorted_rows (mode);
00363     }
00364   else
00365     return octave_base_matrix<NDArray>::is_sorted_rows (mode);
00366 }
00367 
00368 octave_value
00369 octave_matrix::convert_to_str_internal (bool, bool, char type) const
00370 {
00371   octave_value retval;
00372   dim_vector dv = dims ();
00373   octave_idx_type nel = dv.numel ();
00374 
00375   charNDArray chm (dv);
00376 
00377   bool warned = false;
00378 
00379   for (octave_idx_type i = 0; i < nel; i++)
00380     {
00381       octave_quit ();
00382 
00383       double d = matrix (i);
00384 
00385       if (xisnan (d))
00386         {
00387           gripe_nan_to_character_conversion ();
00388           return retval;
00389         }
00390       else
00391         {
00392           int ival = NINT (d);
00393 
00394           if (ival < 0 || ival > UCHAR_MAX)
00395             {
00396               // FIXME -- is there something
00397               // better we could do?
00398 
00399               ival = 0;
00400 
00401               if (! warned)
00402                 {
00403                   ::warning ("range error for conversion to character value");
00404                   warned = true;
00405                 }
00406             }
00407 
00408           chm (i) = static_cast<char> (ival);
00409         }
00410     }
00411 
00412   retval = octave_value (chm, type);
00413 
00414   return retval;
00415 }
00416 
00417 bool
00418 octave_matrix::save_ascii (std::ostream& os)
00419 {
00420   dim_vector d = dims ();
00421 
00422   if (d.length () > 2)
00423     {
00424       NDArray tmp = array_value ();
00425 
00426       os << "# ndims: " << d.length () << "\n";
00427 
00428       for (int i=0; i < d.length (); i++)
00429         os << " " << d (i);
00430 
00431       os << "\n" << tmp;
00432     }
00433   else
00434     {
00435       // Keep this case, rather than use generic code above for backward
00436       // compatiability. Makes load_ascii much more complex!!
00437       os << "# rows: " << rows () << "\n"
00438          << "# columns: " << columns () << "\n";
00439 
00440       os << matrix_value ();
00441     }
00442 
00443   return true;
00444 }
00445 
00446 bool
00447 octave_matrix::load_ascii (std::istream& is)
00448 {
00449   bool success = true;
00450 
00451   string_vector keywords(2);
00452 
00453   keywords[0] = "ndims";
00454   keywords[1] = "rows";
00455 
00456   std::string kw;
00457   octave_idx_type val = 0;
00458 
00459   if (extract_keyword (is, keywords, kw, val, true))
00460     {
00461       if (kw == "ndims")
00462         {
00463           int mdims = static_cast<int> (val);
00464 
00465           if (mdims >= 0)
00466             {
00467               dim_vector dv;
00468               dv.resize (mdims);
00469 
00470               for (int i = 0; i < mdims; i++)
00471                 is >> dv(i);
00472 
00473               if (is)
00474                 {
00475                   NDArray tmp(dv);
00476 
00477                   is >> tmp;
00478 
00479                   if (is)
00480                     matrix = tmp;
00481                   else
00482                     {
00483                       error ("load: failed to load matrix constant");
00484                       success = false;
00485                     }
00486                 }
00487               else
00488                 {
00489                   error ("load: failed to read dimensions");
00490                   success = false;
00491                 }
00492             }
00493           else
00494             {
00495               error ("load: failed to extract number of dimensions");
00496               success = false;
00497             }
00498         }
00499       else if (kw == "rows")
00500         {
00501           octave_idx_type nr = val;
00502           octave_idx_type nc = 0;
00503 
00504           if (nr >= 0 && extract_keyword (is, "columns", nc) && nc >= 0)
00505             {
00506               if (nr > 0 && nc > 0)
00507                 {
00508                   Matrix tmp (nr, nc);
00509                   is >> tmp;
00510                   if (is)
00511                     matrix = tmp;
00512                   else
00513                     {
00514                       error ("load: failed to load matrix constant");
00515                       success = false;
00516                     }
00517                 }
00518               else if (nr == 0 || nc == 0)
00519                 matrix = Matrix (nr, nc);
00520               else
00521                 panic_impossible ();
00522             }
00523           else
00524             {
00525               error ("load: failed to extract number of rows and columns");
00526               success = false;
00527             }
00528         }
00529       else
00530         panic_impossible ();
00531     }
00532   else
00533     {
00534       error ("load: failed to extract number of rows and columns");
00535       success = false;
00536     }
00537 
00538   return success;
00539 }
00540 
00541 bool
00542 octave_matrix::save_binary (std::ostream& os, bool& save_as_floats)
00543 {
00544 
00545   dim_vector d = dims ();
00546   if (d.length() < 1)
00547     return false;
00548 
00549   // Use negative value for ndims to differentiate with old format!!
00550   int32_t tmp = - d.length();
00551   os.write (reinterpret_cast<char *> (&tmp), 4);
00552   for (int i = 0; i < d.length (); i++)
00553     {
00554       tmp = d(i);
00555       os.write (reinterpret_cast<char *> (&tmp), 4);
00556     }
00557 
00558   NDArray m = array_value ();
00559   save_type st = LS_DOUBLE;
00560   if (save_as_floats)
00561     {
00562       if (m.too_large_for_float ())
00563         {
00564           warning ("save: some values too large to save as floats --");
00565           warning ("save: saving as doubles instead");
00566         }
00567       else
00568         st = LS_FLOAT;
00569     }
00570   else if (d.numel () > 8192) // FIXME -- make this configurable.
00571     {
00572       double max_val, min_val;
00573       if (m.all_integers (max_val, min_val))
00574         st = get_save_type (max_val, min_val);
00575     }
00576 
00577   const double *mtmp = m.data ();
00578   write_doubles (os, mtmp, st, d.numel ());
00579 
00580   return true;
00581 }
00582 
00583 bool
00584 octave_matrix::load_binary (std::istream& is, bool swap,
00585                                  oct_mach_info::float_format fmt)
00586 {
00587   char tmp;
00588   int32_t mdims;
00589   if (! is.read (reinterpret_cast<char *> (&mdims), 4))
00590     return false;
00591   if (swap)
00592     swap_bytes<4> (&mdims);
00593   if (mdims < 0)
00594     {
00595       mdims = - mdims;
00596       int32_t di;
00597       dim_vector dv;
00598       dv.resize (mdims);
00599 
00600       for (int i = 0; i < mdims; i++)
00601         {
00602           if (! is.read (reinterpret_cast<char *> (&di), 4))
00603             return false;
00604           if (swap)
00605             swap_bytes<4> (&di);
00606           dv(i) = di;
00607         }
00608 
00609       // Convert an array with a single dimension to be a row vector.
00610       // Octave should never write files like this, other software
00611       // might.
00612 
00613       if (mdims == 1)
00614         {
00615           mdims = 2;
00616           dv.resize (mdims);
00617           dv(1) = dv(0);
00618           dv(0) = 1;
00619         }
00620 
00621       if (! is.read (reinterpret_cast<char *> (&tmp), 1))
00622         return false;
00623 
00624       NDArray m(dv);
00625       double *re = m.fortran_vec ();
00626       read_doubles (is, re, static_cast<save_type> (tmp), dv.numel (), swap, fmt);
00627       if (error_state || ! is)
00628         return false;
00629       matrix = m;
00630     }
00631   else
00632     {
00633       int32_t nr, nc;
00634       nr = mdims;
00635       if (! is.read (reinterpret_cast<char *> (&nc), 4))
00636         return false;
00637       if (swap)
00638         swap_bytes<4> (&nc);
00639       if (! is.read (reinterpret_cast<char *> (&tmp), 1))
00640         return false;
00641       Matrix m (nr, nc);
00642       double *re = m.fortran_vec ();
00643       octave_idx_type len = nr * nc;
00644       read_doubles (is, re, static_cast<save_type> (tmp), len, swap, fmt);
00645       if (error_state || ! is)
00646         return false;
00647       matrix = m;
00648     }
00649   return true;
00650 }
00651 
00652 #if defined (HAVE_HDF5)
00653 
00654 bool
00655 octave_matrix::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
00656 {
00657   dim_vector dv = dims ();
00658   int empty = save_hdf5_empty (loc_id, name, dv);
00659   if (empty)
00660     return (empty > 0);
00661 
00662   int rank = dv.length ();
00663   hid_t space_hid = -1, data_hid = -1;
00664   bool retval = true;
00665   NDArray m = array_value ();
00666 
00667   OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
00668 
00669   // Octave uses column-major, while HDF5 uses row-major ordering
00670   for (int i = 0; i < rank; i++)
00671     hdims[i] = dv (rank-i-1);
00672 
00673   space_hid = H5Screate_simple (rank, hdims, 0);
00674 
00675   if (space_hid < 0) return false;
00676 
00677   hid_t save_type_hid = H5T_NATIVE_DOUBLE;
00678 
00679   if (save_as_floats)
00680     {
00681       if (m.too_large_for_float ())
00682         {
00683           warning ("save: some values too large to save as floats --");
00684           warning ("save: saving as doubles instead");
00685         }
00686       else
00687         save_type_hid = H5T_NATIVE_FLOAT;
00688     }
00689 #if HAVE_HDF5_INT2FLOAT_CONVERSIONS
00690   // hdf5 currently doesn't support float/integer conversions
00691   else
00692     {
00693       double max_val, min_val;
00694 
00695       if (m.all_integers (max_val, min_val))
00696         save_type_hid
00697           = save_type_to_hdf5 (get_save_type (max_val, min_val));
00698     }
00699 #endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */
00700 
00701 #if HAVE_HDF5_18
00702   data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
00703                         H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00704 #else
00705   data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
00706                         H5P_DEFAULT);
00707 #endif
00708   if (data_hid < 0)
00709     {
00710       H5Sclose (space_hid);
00711       return false;
00712     }
00713 
00714   double *mtmp = m.fortran_vec ();
00715   retval = H5Dwrite (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
00716                      H5P_DEFAULT, mtmp) >= 0;
00717 
00718   H5Dclose (data_hid);
00719   H5Sclose (space_hid);
00720 
00721   return retval;
00722 }
00723 
00724 bool
00725 octave_matrix::load_hdf5 (hid_t loc_id, const char *name)
00726 {
00727   bool retval = false;
00728 
00729   dim_vector dv;
00730   int empty = load_hdf5_empty (loc_id, name, dv);
00731   if (empty > 0)
00732     matrix.resize(dv);
00733   if (empty)
00734       return (empty > 0);
00735 
00736 #if HAVE_HDF5_18
00737   hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
00738 #else
00739   hid_t data_hid = H5Dopen (loc_id, name);
00740 #endif
00741   hid_t space_id = H5Dget_space (data_hid);
00742 
00743   hsize_t rank = H5Sget_simple_extent_ndims (space_id);
00744 
00745   if (rank < 1)
00746     {
00747       H5Sclose (space_id);
00748       H5Dclose (data_hid);
00749       return false;
00750     }
00751 
00752   OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
00753   OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
00754 
00755   H5Sget_simple_extent_dims (space_id, hdims, maxdims);
00756 
00757   // Octave uses column-major, while HDF5 uses row-major ordering
00758   if (rank == 1)
00759     {
00760       dv.resize (2);
00761       dv(0) = 1;
00762       dv(1) = hdims[0];
00763     }
00764   else
00765     {
00766       dv.resize (rank);
00767       for (hsize_t i = 0, j = rank - 1; i < rank; i++, j--)
00768         dv(j) = hdims[i];
00769     }
00770 
00771   NDArray m (dv);
00772   double *re = m.fortran_vec ();
00773   if (H5Dread (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
00774                H5P_DEFAULT, re) >= 0)
00775     {
00776       retval = true;
00777       matrix = m;
00778     }
00779 
00780   H5Sclose (space_id);
00781   H5Dclose (data_hid);
00782 
00783   return retval;
00784 }
00785 
00786 #endif
00787 
00788 void
00789 octave_matrix::print_raw (std::ostream& os,
00790                           bool pr_as_read_syntax) const
00791 {
00792   octave_print_internal (os, matrix, pr_as_read_syntax,
00793                          current_print_indent_level ());
00794 }
00795 
00796 mxArray *
00797 octave_matrix::as_mxArray (void) const
00798 {
00799   mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxREAL);
00800 
00801   double *pr = static_cast<double *> (retval->get_data ());
00802 
00803   mwSize nel = numel ();
00804 
00805   const double *p = matrix.data ();
00806 
00807   for (mwIndex i = 0; i < nel; i++)
00808     pr[i] = p[i];
00809 
00810   return retval;
00811 }
00812 
00813 // This uses a smarter strategy for doing the complex->real mappers.  We
00814 // allocate an array for a real result and keep filling it until a complex
00815 // result is produced.
00816 static octave_value
00817 do_rc_map (const NDArray& a, Complex (&fcn) (double))
00818 {
00819   octave_idx_type n = a.numel ();
00820   NoAlias<NDArray> rr (a.dims ());
00821 
00822   for (octave_idx_type i = 0; i < n; i++)
00823     {
00824       octave_quit ();
00825 
00826       Complex tmp = fcn (a(i));
00827       if (tmp.imag () == 0.0)
00828         rr(i) = tmp.real ();
00829       else
00830         {
00831           NoAlias<ComplexNDArray> rc (a.dims ());
00832 
00833           for (octave_idx_type j = 0; j < i; j++)
00834             rc(j) = rr(j);
00835 
00836           rc(i) = tmp;
00837 
00838           for (octave_idx_type j = i+1; j < n; j++)
00839             {
00840               octave_quit ();
00841 
00842               rc(j) = fcn (a(j));
00843             }
00844 
00845           return new octave_complex_matrix (rc);
00846         }
00847     }
00848 
00849   return rr;
00850 }
00851 
00852 octave_value
00853 octave_matrix::map (unary_mapper_t umap) const
00854 {
00855   switch (umap)
00856     {
00857     case umap_imag:
00858       return NDArray (matrix.dims (), 0.0);
00859 
00860     case umap_real:
00861     case umap_conj:
00862       return matrix;
00863 
00864     // Mappers handled specially.
00865 #define ARRAY_METHOD_MAPPER(UMAP, FCN) \
00866     case umap_ ## UMAP: \
00867       return octave_value (matrix.FCN ())
00868 
00869       ARRAY_METHOD_MAPPER (abs, abs);
00870       ARRAY_METHOD_MAPPER (isnan, isnan);
00871       ARRAY_METHOD_MAPPER (isinf, isinf);
00872       ARRAY_METHOD_MAPPER (finite, isfinite);
00873 
00874 #define ARRAY_MAPPER(UMAP, TYPE, FCN) \
00875     case umap_ ## UMAP: \
00876       return octave_value (matrix.map<TYPE> (FCN))
00877 
00878 #define RC_ARRAY_MAPPER(UMAP, TYPE, FCN) \
00879     case umap_ ## UMAP: \
00880       return do_rc_map (matrix, FCN)
00881 
00882       RC_ARRAY_MAPPER (acos, Complex, rc_acos);
00883       RC_ARRAY_MAPPER (acosh, Complex, rc_acosh);
00884       ARRAY_MAPPER (angle, double, ::arg);
00885       ARRAY_MAPPER (arg, double, ::arg);
00886       RC_ARRAY_MAPPER (asin, Complex, rc_asin);
00887       ARRAY_MAPPER (asinh, double, ::asinh);
00888       ARRAY_MAPPER (atan, double, ::atan);
00889       RC_ARRAY_MAPPER (atanh, Complex, rc_atanh);
00890       ARRAY_MAPPER (erf, double, ::erf);
00891       ARRAY_MAPPER (erfinv, double, ::erfinv);
00892       ARRAY_MAPPER (erfc, double, ::erfc);
00893       ARRAY_MAPPER (erfcx, double, ::erfcx);
00894       ARRAY_MAPPER (gamma, double, xgamma);
00895       RC_ARRAY_MAPPER (lgamma, Complex, rc_lgamma);
00896       ARRAY_MAPPER (cbrt, double, ::cbrt);
00897       ARRAY_MAPPER (ceil, double, ::ceil);
00898       ARRAY_MAPPER (cos, double, ::cos);
00899       ARRAY_MAPPER (cosh, double, ::cosh);
00900       ARRAY_MAPPER (exp, double, ::exp);
00901       ARRAY_MAPPER (expm1, double, ::expm1);
00902       ARRAY_MAPPER (fix, double, ::fix);
00903       ARRAY_MAPPER (floor, double, ::floor);
00904       RC_ARRAY_MAPPER (log, Complex, rc_log);
00905       RC_ARRAY_MAPPER (log2, Complex, rc_log2);
00906       RC_ARRAY_MAPPER (log10, Complex, rc_log10);
00907       RC_ARRAY_MAPPER (log1p, Complex, rc_log1p);
00908       ARRAY_MAPPER (round, double, xround);
00909       ARRAY_MAPPER (roundb, double, xroundb);
00910       ARRAY_MAPPER (signum, double, ::signum);
00911       ARRAY_MAPPER (sin, double, ::sin);
00912       ARRAY_MAPPER (sinh, double, ::sinh);
00913       RC_ARRAY_MAPPER (sqrt, Complex, rc_sqrt);
00914       ARRAY_MAPPER (tan, double, ::tan);
00915       ARRAY_MAPPER (tanh, double, ::tanh);
00916       ARRAY_MAPPER (isna, bool, octave_is_NA);
00917 
00918     default:
00919       if (umap >= umap_xisalnum && umap <= umap_xtoupper)
00920         {
00921           octave_value str_conv = convert_to_str (true, true);
00922           return error_state ? octave_value () : str_conv.map (umap);
00923         }
00924       else
00925         return octave_base_value::map (umap);
00926     }
00927 }
00928 
00929 DEFUN (double, args, ,
00930   "-*- texinfo -*-\n\
00931 @deftypefn {Built-in Function} {} double (@var{x})\n\
00932 Convert @var{x} to double precision type.\n\
00933 @seealso{single}\n\
00934 @end deftypefn")
00935 {
00936   // The OCTAVE_TYPE_CONV_BODY3 macro declares retval, so they go
00937   // inside their own scopes, and we don't declare retval here to
00938   // avoid a shadowed declaration warning.
00939 
00940   if (args.length () == 1)
00941     {
00942       if (args(0).is_perm_matrix ())
00943         {
00944           OCTAVE_TYPE_CONV_BODY3 (double, octave_perm_matrix, octave_scalar);
00945         }
00946       else if (args(0).is_diag_matrix ())
00947         {
00948           if (args(0).is_complex_type ())
00949             {
00950               OCTAVE_TYPE_CONV_BODY3 (double, octave_complex_diag_matrix, octave_complex);
00951             }
00952           else
00953             {
00954               OCTAVE_TYPE_CONV_BODY3 (double, octave_diag_matrix, octave_scalar);
00955             }
00956         }
00957       else if (args(0).is_sparse_type ())
00958         {
00959           if (args(0).is_complex_type ())
00960             {
00961               OCTAVE_TYPE_CONV_BODY3 (double, octave_sparse_complex_matrix, octave_complex);
00962             }
00963           else
00964             {
00965               OCTAVE_TYPE_CONV_BODY3 (double, octave_sparse_matrix, octave_scalar);
00966             }
00967         }
00968       else if (args(0).is_complex_type ())
00969         {
00970           OCTAVE_TYPE_CONV_BODY3 (double, octave_complex_matrix, octave_complex);
00971         }
00972       else
00973         {
00974           OCTAVE_TYPE_CONV_BODY3 (double, octave_matrix, octave_scalar);
00975         }
00976     }
00977   else
00978     print_usage ();
00979 
00980   return octave_value ();
00981 }
00982 
00983 /*
00984 
00985 %!assert (class (double (single (1))), "double")
00986 %!assert (class (double (single (1 + i))), "double")
00987 %!assert (class (double (int8 (1))), "double")
00988 %!assert (class (double (uint8 (1))), "double")
00989 %!assert (class (double (int16 (1))), "double")
00990 %!assert (class (double (uint16 (1))), "double")
00991 %!assert (class (double (int32 (1))), "double")
00992 %!assert (class (double (uint32 (1))), "double")
00993 %!assert (class (double (int64 (1))), "double")
00994 %!assert (class (double (uint64 (1))), "double")
00995 %!assert (class (double (true)), "double")
00996 %!assert (class (double ("A")), "double")
00997 %!test
00998 %! x = sparse (logical ([1 0; 0 1]));
00999 %! y = double (x);
01000 %! assert (class (x), "logical");
01001 %! assert (class (y), "double");
01002 %! assert (issparse (y));
01003 %!test
01004 %! x = diag (single ([1 3 2]));
01005 %! y = double (x);
01006 %! assert (class (x), "single");
01007 %! assert (class (y), "double");
01008 %!test
01009 %! x = diag (single ([i 3 2]));
01010 %! y = double (x);
01011 %! assert (class (x), "single");
01012 %! assert (class (y), "double");
01013 
01014 */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines