ls-mat4.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <cfloat>
00028 #include <cstring>
00029 #include <cctype>
00030 
00031 #include <fstream>
00032 #include <iomanip>
00033 #include <iostream>
00034 #include <string>
00035 #include <vector>
00036 
00037 #include "byte-swap.h"
00038 #include "data-conv.h"
00039 #include "file-ops.h"
00040 #include "glob-match.h"
00041 #include "lo-mappers.h"
00042 #include "mach-info.h"
00043 #include "oct-env.h"
00044 #include "oct-time.h"
00045 #include "quit.h"
00046 #include "str-vec.h"
00047 #include "oct-locbuf.h"
00048 
00049 #include "Cell.h"
00050 #include "defun.h"
00051 #include "error.h"
00052 #include "gripes.h"
00053 #include "load-save.h"
00054 #include "oct-obj.h"
00055 #include "oct-map.h"
00056 #include "ov-cell.h"
00057 #include "pager.h"
00058 #include "pt-exp.h"
00059 #include "sysdep.h"
00060 #include "unwind-prot.h"
00061 #include "utils.h"
00062 #include "variables.h"
00063 #include "version.h"
00064 #include "dMatrix.h"
00065 #include "dSparse.h"
00066 
00067 #include "ls-mat4.h"
00068 
00069 // Read LEN elements of data from IS in the format specified by
00070 // PRECISION, placing the result in DATA.  If SWAP is TRUE, swap
00071 // the bytes of each element before copying to DATA.  FLT_FMT
00072 // specifies the format of the data if we are reading floating point
00073 // numbers.
00074 
00075 static void
00076 read_mat_binary_data (std::istream& is, double *data, int precision,
00077                       int len, bool swap,
00078                       oct_mach_info::float_format flt_fmt)
00079 {
00080   switch (precision)
00081     {
00082     case 0:
00083       read_doubles (is, data, LS_DOUBLE, len, swap, flt_fmt);
00084       break;
00085 
00086     case 1:
00087       read_doubles (is, data, LS_FLOAT, len, swap, flt_fmt);
00088       break;
00089 
00090     case 2:
00091       read_doubles (is, data, LS_INT, len, swap, flt_fmt);
00092       break;
00093 
00094     case 3:
00095       read_doubles (is, data, LS_SHORT, len, swap, flt_fmt);
00096       break;
00097 
00098     case 4:
00099       read_doubles (is, data, LS_U_SHORT, len, swap, flt_fmt);
00100       break;
00101 
00102     case 5:
00103       read_doubles (is, data, LS_U_CHAR, len, swap, flt_fmt);
00104       break;
00105 
00106     default:
00107       break;
00108     }
00109 }
00110 
00111 int
00112 read_mat_file_header (std::istream& is, bool& swap, int32_t& mopt,
00113                       int32_t& nr, int32_t& nc,
00114                       int32_t& imag, int32_t& len,
00115                       int quiet)
00116 {
00117   swap = false;
00118 
00119   // We expect to fail here, at the beginning of a record, so not
00120   // being able to read another mopt value should not result in an
00121   // error.
00122 
00123   is.read (reinterpret_cast<char *> (&mopt), 4);
00124   if (! is)
00125     return 1;
00126 
00127   if (! is.read (reinterpret_cast<char *> (&nr), 4))
00128     goto data_read_error;
00129 
00130   if (! is.read (reinterpret_cast<char *> (&nc), 4))
00131     goto data_read_error;
00132 
00133   if (! is.read (reinterpret_cast<char *> (&imag), 4))
00134     goto data_read_error;
00135 
00136   if (! is.read (reinterpret_cast<char *> (&len), 4))
00137     goto data_read_error;
00138 
00139 // If mopt is nonzero and the byte order is swapped, mopt will be
00140 // bigger than we expect, so we swap bytes.
00141 //
00142 // If mopt is zero, it means the file was written on a little endian
00143 // machine, and we only need to swap if we are running on a big endian
00144 // machine.
00145 //
00146 // Gag me.
00147 
00148   if (oct_mach_info::words_big_endian () && mopt == 0)
00149     swap = true;
00150 
00151   // mopt is signed, therefore byte swap may result in negative value.
00152 
00153   if (mopt > 9999 || mopt < 0)
00154     swap = true;
00155 
00156   if (swap)
00157     {
00158       swap_bytes<4> (&mopt);
00159       swap_bytes<4> (&nr);
00160       swap_bytes<4> (&nc);
00161       swap_bytes<4> (&imag);
00162       swap_bytes<4> (&len);
00163     }
00164 
00165   if (mopt > 9999 || mopt < 0 || imag > 1 || imag < 0)
00166     {
00167       if (! quiet)
00168         error ("load: can't read binary file");
00169       return -1;
00170     }
00171 
00172   return 0;
00173 
00174  data_read_error:
00175   return -1;
00176 }
00177 
00178 // We don't just use a cast here, because we need to be able to detect
00179 // possible errors.
00180 
00181 oct_mach_info::float_format
00182 mopt_digit_to_float_format (int mach)
00183 {
00184   oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown;
00185 
00186   switch (mach)
00187     {
00188     case 0:
00189       flt_fmt = oct_mach_info::flt_fmt_ieee_little_endian;
00190       break;
00191 
00192     case 1:
00193       flt_fmt = oct_mach_info::flt_fmt_ieee_big_endian;
00194       break;
00195 
00196     case 2:
00197       flt_fmt = oct_mach_info::flt_fmt_vax_d;
00198       break;
00199 
00200     case 3:
00201       flt_fmt = oct_mach_info::flt_fmt_vax_g;
00202       break;
00203 
00204     case 4:
00205       flt_fmt = oct_mach_info::flt_fmt_cray;
00206       break;
00207 
00208     default:
00209       flt_fmt = oct_mach_info::flt_fmt_unknown;
00210       break;
00211     }
00212 
00213   return flt_fmt;
00214 }
00215 
00216 int
00217 float_format_to_mopt_digit (oct_mach_info::float_format flt_fmt)
00218 {
00219   int retval = -1;
00220 
00221   switch (flt_fmt)
00222     {
00223     case oct_mach_info::flt_fmt_ieee_little_endian:
00224       retval = 0;
00225       break;
00226 
00227     case oct_mach_info::flt_fmt_ieee_big_endian:
00228       retval = 1;
00229       break;
00230 
00231     case oct_mach_info::flt_fmt_vax_d:
00232       retval = 2;
00233       break;
00234 
00235     case oct_mach_info::flt_fmt_vax_g:
00236       retval = 3;
00237       break;
00238 
00239     case oct_mach_info::flt_fmt_cray:
00240       retval = 4;
00241       break;
00242 
00243     default:
00244       break;
00245     }
00246 
00247   return retval;
00248 }
00249 
00250 // Extract one value (scalar, matrix, string, etc.) from stream IS and
00251 // place it in TC, returning the name of the variable.
00252 //
00253 // The data is expected to be in Matlab version 4 .mat format, though
00254 // not all the features of that format are supported.
00255 //
00256 // FILENAME is used for error messages.
00257 //
00258 // This format provides no way to tag the data as global.
00259 
00260 std::string
00261 read_mat_binary_data (std::istream& is, const std::string& filename,
00262                       octave_value& tc)
00263 {
00264   std::string retval;
00265 
00266   // These are initialized here instead of closer to where they are
00267   // first used to avoid errors from gcc about goto crossing
00268   // initialization of variable.
00269 
00270   Matrix re;
00271   oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown;
00272   bool swap = false;
00273   int type = 0;
00274   int prec = 0;
00275   int order = 0;
00276   int mach = 0;
00277   int dlen = 0;
00278 
00279   int32_t mopt, nr, nc, imag, len;
00280 
00281   int err = read_mat_file_header (is, swap, mopt, nr, nc, imag, len);
00282   if (err)
00283     {
00284       if (err < 0)
00285         goto data_read_error;
00286       else
00287         return retval;
00288     }
00289 
00290   type = mopt % 10;  // Full, sparse, etc.
00291   mopt /= 10;        // Eliminate first digit.
00292   prec = mopt % 10;  // double, float, int, etc.
00293   mopt /= 10;        // Eliminate second digit.
00294   order = mopt % 10; // Row or column major ordering.
00295   mopt /= 10;        // Eliminate third digit.
00296   mach = mopt % 10;  // IEEE, VAX, etc.
00297 
00298   flt_fmt = mopt_digit_to_float_format (mach);
00299 
00300   if (flt_fmt == oct_mach_info::flt_fmt_unknown)
00301     {
00302       error ("load: unrecognized binary format!");
00303       return retval;
00304     }
00305 
00306   if (imag && type == 1)
00307     {
00308       error ("load: encountered complex matrix with string flag set!");
00309       return retval;
00310     }
00311 
00312   // LEN includes the terminating character, and the file is also
00313   // supposed to include it, but apparently not all files do.  Either
00314   // way, I think this should work.
00315 
00316   {
00317     OCTAVE_LOCAL_BUFFER (char, name, len+1);
00318     name[len] = '\0';
00319     if (! is.read (name, len))
00320       goto data_read_error;
00321     retval = name;
00322 
00323     dlen = nr * nc;
00324     if (dlen < 0)
00325       goto data_read_error;
00326 
00327     if (order)
00328       {
00329         octave_idx_type tmp = nr;
00330         nr = nc;
00331         nc = tmp;
00332       }
00333 
00334     if (type == 2)
00335       {
00336         if (nc == 4)
00337           {
00338             octave_idx_type nr_new, nc_new;
00339             Array<Complex> data (dim_vector (1, nr - 1));
00340             Array<octave_idx_type> c (dim_vector (1, nr - 1));
00341             Array<octave_idx_type> r (dim_vector (1, nr - 1));
00342             OCTAVE_LOCAL_BUFFER (double, dtmp, nr);
00343             OCTAVE_LOCAL_BUFFER (double, ctmp, nr);
00344 
00345             read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt);
00346             for (octave_idx_type i = 0; i < nr - 1; i++)
00347               r.xelem(i) = dtmp[i] - 1;
00348             nr_new = dtmp[nr - 1];
00349             read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt);
00350             for (octave_idx_type i = 0; i < nr - 1; i++)
00351               c.xelem(i) = dtmp[i] - 1;
00352             nc_new = dtmp[nr - 1];
00353             read_mat_binary_data (is, dtmp, prec, nr - 1, swap, flt_fmt);
00354             read_mat_binary_data (is, ctmp, prec, 1, swap, flt_fmt);
00355             read_mat_binary_data (is, ctmp, prec, nr - 1, swap, flt_fmt);
00356 
00357             for (octave_idx_type i = 0; i < nr - 1; i++)
00358               data.xelem(i) = Complex (dtmp[i], ctmp[i]);
00359             read_mat_binary_data (is, ctmp, prec, 1, swap, flt_fmt);
00360 
00361             SparseComplexMatrix smc = SparseComplexMatrix (data, r, c,
00362                                                            nr_new, nc_new);
00363 
00364             tc = order ? smc.transpose () : smc;
00365           }
00366         else
00367           {
00368             octave_idx_type nr_new, nc_new;
00369             Array<double> data (dim_vector (1, nr - 1));
00370             Array<octave_idx_type> c (dim_vector (1, nr - 1));
00371             Array<octave_idx_type> r (dim_vector (1, nr - 1));
00372             OCTAVE_LOCAL_BUFFER (double, dtmp, nr);
00373 
00374             read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt);
00375             for (octave_idx_type i = 0; i < nr - 1; i++)
00376               r.xelem(i) = dtmp[i] - 1;
00377             nr_new = dtmp[nr - 1];
00378             read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt);
00379             for (octave_idx_type i = 0; i < nr - 1; i++)
00380               c.xelem(i) = dtmp[i] - 1;
00381             nc_new = dtmp[nr - 1];
00382             read_mat_binary_data (is, data.fortran_vec (), prec, nr - 1, swap, flt_fmt);
00383             read_mat_binary_data (is, dtmp, prec, 1, swap, flt_fmt);
00384 
00385             SparseMatrix sm = SparseMatrix (data, r, c, nr_new, nc_new);
00386 
00387             tc = order ? sm.transpose () : sm;
00388           }
00389       }
00390     else
00391       {
00392         re.resize (nr, nc);
00393 
00394         read_mat_binary_data (is, re.fortran_vec (), prec, dlen, swap, flt_fmt);
00395 
00396         if (! is || error_state)
00397           {
00398             error ("load: reading matrix data for '%s'", name);
00399             goto data_read_error;
00400           }
00401 
00402         if (imag)
00403           {
00404             Matrix im (nr, nc);
00405 
00406             read_mat_binary_data (is, im.fortran_vec (), prec, dlen, swap,
00407                                   flt_fmt);
00408 
00409             if (! is || error_state)
00410               {
00411                 error ("load: reading imaginary matrix data for '%s'", name);
00412                 goto data_read_error;
00413               }
00414 
00415             ComplexMatrix ctmp (nr, nc);
00416 
00417             for (octave_idx_type j = 0; j < nc; j++)
00418               for (octave_idx_type i = 0; i < nr; i++)
00419                 ctmp (i, j) = Complex (re (i, j), im (i, j));
00420 
00421             tc = order ? ctmp.transpose () : ctmp;
00422           }
00423         else
00424           tc = order ? re.transpose () : re;
00425 
00426         if (type == 1)
00427           tc = tc.convert_to_str (false, true, '\'');
00428       }
00429 
00430       return retval;
00431     }
00432 
00433  data_read_error:
00434   error ("load: trouble reading binary file '%s'", filename.c_str ());
00435   return retval;
00436 }
00437 
00438 // Save the data from TC along with the corresponding NAME on stream OS
00439 // in the MatLab version 4 binary format.
00440 
00441 bool
00442 save_mat_binary_data (std::ostream& os, const octave_value& tc,
00443                       const std::string& name)
00444 {
00445   int32_t mopt = 0;
00446 
00447   mopt += tc.is_sparse_type () ? 2 : tc.is_string () ? 1 : 0;
00448 
00449   oct_mach_info::float_format flt_fmt =
00450     oct_mach_info::native_float_format ();;
00451 
00452   mopt += 1000 * float_format_to_mopt_digit (flt_fmt);
00453 
00454   os.write (reinterpret_cast<char *> (&mopt), 4);
00455 
00456   octave_idx_type len;
00457   int32_t nr = tc.rows ();
00458 
00459   int32_t nc = tc.columns ();
00460 
00461   if (tc.is_sparse_type ())
00462     {
00463       len = tc.nnz ();
00464       uint32_t nnz = len + 1;
00465       os.write (reinterpret_cast<char *> (&nnz), 4);
00466 
00467       uint32_t iscmplx = tc.is_complex_type () ? 4 : 3;
00468       os.write (reinterpret_cast<char *> (&iscmplx), 4);
00469 
00470       uint32_t tmp = 0;
00471       os.write (reinterpret_cast<char *> (&tmp), 4);
00472     }
00473   else
00474     {
00475       os.write (reinterpret_cast<char *> (&nr), 4);
00476       os.write (reinterpret_cast<char *> (&nc), 4);
00477 
00478       int32_t imag = tc.is_complex_type () ? 1 : 0;
00479       os.write (reinterpret_cast<char *> (&imag), 4);
00480 
00481       len = nr * nc;
00482     }
00483 
00484 
00485   // LEN includes the terminating character, and the file is also
00486   // supposed to include it.
00487 
00488   int32_t name_len = name.length () + 1;
00489 
00490   os.write (reinterpret_cast<char *> (&name_len), 4);
00491   os << name << '\0';
00492 
00493   if (tc.is_string ())
00494     {
00495       unwind_protect frame;
00496 
00497       charMatrix chm = tc.char_matrix_value ();
00498 
00499       octave_idx_type nrow = chm.rows ();
00500       octave_idx_type ncol = chm.cols ();
00501 
00502       OCTAVE_LOCAL_BUFFER (double, buf, ncol*nrow);
00503 
00504       for (octave_idx_type i = 0; i < nrow; i++)
00505         {
00506           std::string tstr = chm.row_as_string (i);
00507           const char *s = tstr.data ();
00508 
00509           for (octave_idx_type j = 0; j < ncol; j++)
00510             buf[j*nrow+i] = static_cast<double> (*s++ & 0x00FF);
00511         }
00512       os.write (reinterpret_cast<char *> (buf), nrow*ncol*sizeof(double));
00513     }
00514   else if (tc.is_range ())
00515     {
00516       Range r = tc.range_value ();
00517       double base = r.base ();
00518       double inc = r.inc ();
00519       octave_idx_type nel = r.nelem ();
00520       for (octave_idx_type i = 0; i < nel; i++)
00521         {
00522           double x = base + i * inc;
00523           os.write (reinterpret_cast<char *> (&x), 8);
00524         }
00525     }
00526   else if (tc.is_real_scalar ())
00527     {
00528       double tmp = tc.double_value ();
00529       os.write (reinterpret_cast<char *> (&tmp), 8);
00530     }
00531   else if (tc.is_sparse_type ())
00532     {
00533       double ds;
00534       OCTAVE_LOCAL_BUFFER (double, dtmp, len);
00535       if (tc.is_complex_matrix ())
00536         {
00537           SparseComplexMatrix m = tc.sparse_complex_matrix_value ();
00538 
00539           for (octave_idx_type i = 0; i < len; i++)
00540             dtmp [i] = m.ridx(i) + 1;
00541           os.write (reinterpret_cast<const char *> (dtmp), 8 * len);
00542           ds = nr;
00543           os.write (reinterpret_cast<const char *> (&ds), 8);
00544 
00545           octave_idx_type ii = 0;
00546           for (octave_idx_type j = 0; j < nc; j++)
00547             for (octave_idx_type i = m.cidx(j); i < m.cidx(j+1); i++)
00548               dtmp[ii++] = j + 1;
00549           os.write (reinterpret_cast<const char *> (dtmp), 8 * len);
00550           ds = nc;
00551           os.write (reinterpret_cast<const char *> (&ds), 8);
00552 
00553           for (octave_idx_type i = 0; i < len; i++)
00554             dtmp [i] = std::real (m.data(i));
00555           os.write (reinterpret_cast<const char *> (dtmp), 8 * len);
00556           ds = 0.;
00557           os.write (reinterpret_cast<const char *> (&ds), 8);
00558 
00559           for (octave_idx_type i = 0; i < len; i++)
00560             dtmp [i] = std::imag (m.data(i));
00561           os.write (reinterpret_cast<const char *> (dtmp), 8 * len);
00562           os.write (reinterpret_cast<const char *> (&ds), 8);
00563         }
00564       else
00565         {
00566           SparseMatrix m = tc.sparse_matrix_value ();
00567 
00568           for (octave_idx_type i = 0; i < len; i++)
00569             dtmp [i] = m.ridx(i) + 1;
00570           os.write (reinterpret_cast<const char *> (dtmp), 8 * len);
00571           ds = nr;
00572           os.write (reinterpret_cast<const char *> (&ds), 8);
00573 
00574           octave_idx_type ii = 0;
00575           for (octave_idx_type j = 0; j < nc; j++)
00576             for (octave_idx_type i = m.cidx(j); i < m.cidx(j+1); i++)
00577               dtmp[ii++] = j + 1;
00578           os.write (reinterpret_cast<const char *> (dtmp), 8 * len);
00579           ds = nc;
00580           os.write (reinterpret_cast<const char *> (&ds), 8);
00581 
00582           os.write (reinterpret_cast<const char *> (m.data ()), 8 * len);
00583           ds = 0.;
00584           os.write (reinterpret_cast<const char *> (&ds), 8);
00585         }
00586     }
00587   else if (tc.is_real_matrix ())
00588     {
00589       Matrix m = tc.matrix_value ();
00590       os.write (reinterpret_cast<const char *> (m.data ()), 8 * len);
00591     }
00592   else if (tc.is_complex_scalar ())
00593     {
00594       Complex tmp = tc.complex_value ();
00595       os.write (reinterpret_cast<char *> (&tmp), 16);
00596     }
00597   else if (tc.is_complex_matrix ())
00598     {
00599       ComplexMatrix m_cmplx = tc.complex_matrix_value ();
00600       Matrix m = ::real (m_cmplx);
00601       os.write (reinterpret_cast<const char *> (m.data ()), 8 * len);
00602       m = ::imag (m_cmplx);
00603       os.write (reinterpret_cast<const char *> (m.data ()), 8 * len);
00604     }
00605   else
00606     gripe_wrong_type_arg ("save", tc, false);
00607 
00608   return os;
00609 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines