GNU Octave  4.0.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
ls-mat4.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2015 John W. Eaton
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 <cfloat>
28 #include <cstring>
29 #include <cctype>
30 
31 #include <fstream>
32 #include <iomanip>
33 #include <iostream>
34 #include <string>
35 #include <vector>
36 
37 #include "byte-swap.h"
38 #include "data-conv.h"
39 #include "file-ops.h"
40 #include "glob-match.h"
41 #include "lo-mappers.h"
42 #include "mach-info.h"
43 #include "oct-env.h"
44 #include "oct-time.h"
45 #include "quit.h"
46 #include "str-vec.h"
47 #include "oct-locbuf.h"
48 
49 #include "Cell.h"
50 #include "defun.h"
51 #include "error.h"
52 #include "gripes.h"
53 #include "load-save.h"
54 #include "oct-obj.h"
55 #include "oct-map.h"
56 #include "ov-cell.h"
57 #include "pager.h"
58 #include "pt-exp.h"
59 #include "sysdep.h"
60 #include "unwind-prot.h"
61 #include "utils.h"
62 #include "variables.h"
63 #include "version.h"
64 #include "dMatrix.h"
65 #include "dSparse.h"
66 
67 #include "ls-mat4.h"
68 
69 // Read LEN elements of data from IS in the format specified by
70 // PRECISION, placing the result in DATA. If SWAP is TRUE, swap
71 // the bytes of each element before copying to DATA. FLT_FMT
72 // specifies the format of the data if we are reading floating point
73 // numbers.
74 
75 static void
76 read_mat_binary_data (std::istream& is, double *data, int precision,
77  int len, bool swap,
79 {
80  switch (precision)
81  {
82  case 0:
83  read_doubles (is, data, LS_DOUBLE, len, swap, flt_fmt);
84  break;
85 
86  case 1:
87  read_doubles (is, data, LS_FLOAT, len, swap, flt_fmt);
88  break;
89 
90  case 2:
91  read_doubles (is, data, LS_INT, len, swap, flt_fmt);
92  break;
93 
94  case 3:
95  read_doubles (is, data, LS_SHORT, len, swap, flt_fmt);
96  break;
97 
98  case 4:
99  read_doubles (is, data, LS_U_SHORT, len, swap, flt_fmt);
100  break;
101 
102  case 5:
103  read_doubles (is, data, LS_U_CHAR, len, swap, flt_fmt);
104  break;
105 
106  default:
107  break;
108  }
109 }
110 
111 int
112 read_mat_file_header (std::istream& is, bool& swap, int32_t& mopt,
113  int32_t& nr, int32_t& nc,
114  int32_t& imag, int32_t& len,
115  int quiet)
116 {
117  swap = false;
118 
119  // We expect to fail here, at the beginning of a record, so not
120  // being able to read another mopt value should not result in an
121  // error.
122 
123  is.read (reinterpret_cast<char *> (&mopt), 4);
124  if (! is)
125  return 1;
126 
127  if (! is.read (reinterpret_cast<char *> (&nr), 4))
128  goto data_read_error;
129 
130  if (! is.read (reinterpret_cast<char *> (&nc), 4))
131  goto data_read_error;
132 
133  if (! is.read (reinterpret_cast<char *> (&imag), 4))
134  goto data_read_error;
135 
136  if (! is.read (reinterpret_cast<char *> (&len), 4))
137  goto data_read_error;
138 
139 // If mopt is nonzero and the byte order is swapped, mopt will be
140 // bigger than we expect, so we swap bytes.
141 //
142 // If mopt is zero, it means the file was written on a little endian
143 // machine, and we only need to swap if we are running on a big endian
144 // machine.
145 //
146 // Gag me.
147 
148  if (oct_mach_info::words_big_endian () && mopt == 0)
149  swap = true;
150 
151  // mopt is signed, therefore byte swap may result in negative value.
152 
153  if (mopt > 9999 || mopt < 0)
154  swap = true;
155 
156  if (swap)
157  {
158  swap_bytes<4> (&mopt);
159  swap_bytes<4> (&nr);
160  swap_bytes<4> (&nc);
161  swap_bytes<4> (&imag);
162  swap_bytes<4> (&len);
163  }
164 
165  if (mopt > 9999 || mopt < 0 || imag > 1 || imag < 0)
166  {
167  if (! quiet)
168  error ("load: can't read binary file");
169  return -1;
170  }
171 
172  return 0;
173 
174 data_read_error:
175  return -1;
176 }
177 
178 // We don't just use a cast here, because we need to be able to detect
179 // possible errors.
180 
183 {
185 
186  switch (mach)
187  {
188  case 0:
190  break;
191 
192  case 1:
194  break;
195 
196  case 2:
197  case 3:
198  case 4:
199  default:
201  break;
202  }
203 
204  return flt_fmt;
205 }
206 
207 int
209 {
210  int retval = -1;
211 
212  switch (flt_fmt)
213  {
215  retval = 0;
216  break;
217 
219  retval = 1;
220  break;
221 
222  default:
223  break;
224  }
225 
226  return retval;
227 }
228 
229 // Extract one value (scalar, matrix, string, etc.) from stream IS and
230 // place it in TC, returning the name of the variable.
231 //
232 // The data is expected to be in Matlab version 4 .mat format, though
233 // not all the features of that format are supported.
234 //
235 // FILENAME is used for error messages.
236 //
237 // This format provides no way to tag the data as global.
238 
239 std::string
240 read_mat_binary_data (std::istream& is, const std::string& filename,
241  octave_value& tc)
242 {
243  std::string retval;
244 
245  // These are initialized here instead of closer to where they are
246  // first used to avoid errors from gcc about goto crossing
247  // initialization of variable.
248 
249  Matrix re;
251  bool swap = false;
252  int type = 0;
253  int prec = 0;
254  int order = 0;
255  int mach = 0;
256  int dlen = 0;
257 
258  int32_t mopt, nr, nc, imag, len;
259 
260  int err = read_mat_file_header (is, swap, mopt, nr, nc, imag, len);
261  if (err)
262  {
263  if (err < 0)
264  goto data_read_error;
265  else
266  return retval;
267  }
268 
269  type = mopt % 10; // Full, sparse, etc.
270  mopt /= 10; // Eliminate first digit.
271  prec = mopt % 10; // double, float, int, etc.
272  mopt /= 10; // Eliminate second digit.
273  order = mopt % 10; // Row or column major ordering.
274  mopt /= 10; // Eliminate third digit.
275  mach = mopt % 10; // IEEE, VAX, etc.
276 
277  flt_fmt = mopt_digit_to_float_format (mach);
278 
279  if (flt_fmt == oct_mach_info::flt_fmt_unknown)
280  {
281  error ("load: unrecognized binary format!");
282  return retval;
283  }
284 
285  if (imag && type == 1)
286  {
287  error ("load: encountered complex matrix with string flag set!");
288  return retval;
289  }
290 
291  // LEN includes the terminating character, and the file is also
292  // supposed to include it, but apparently not all files do. Either
293  // way, I think this should work.
294 
295  {
296  OCTAVE_LOCAL_BUFFER (char, name, len+1);
297  name[len] = '\0';
298  if (! is.read (name, len))
299  goto data_read_error;
300  retval = name;
301 
302  dlen = nr * nc;
303  if (dlen < 0)
304  goto data_read_error;
305 
306  if (order)
307  {
308  octave_idx_type tmp = nr;
309  nr = nc;
310  nc = tmp;
311  }
312 
313  if (type == 2)
314  {
315  if (nc == 4)
316  {
317  octave_idx_type nr_new, nc_new;
318  Array<Complex> data (dim_vector (1, nr - 1));
319  Array<octave_idx_type> c (dim_vector (1, nr - 1));
320  Array<octave_idx_type> r (dim_vector (1, nr - 1));
321  OCTAVE_LOCAL_BUFFER (double, dtmp, nr);
322  OCTAVE_LOCAL_BUFFER (double, ctmp, nr);
323 
324  read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt);
325  for (octave_idx_type i = 0; i < nr - 1; i++)
326  r.xelem (i) = dtmp[i] - 1;
327  nr_new = dtmp[nr - 1];
328  read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt);
329  for (octave_idx_type i = 0; i < nr - 1; i++)
330  c.xelem (i) = dtmp[i] - 1;
331  nc_new = dtmp[nr - 1];
332  read_mat_binary_data (is, dtmp, prec, nr - 1, swap, flt_fmt);
333  read_mat_binary_data (is, ctmp, prec, 1, swap, flt_fmt);
334  read_mat_binary_data (is, ctmp, prec, nr - 1, swap, flt_fmt);
335 
336  for (octave_idx_type i = 0; i < nr - 1; i++)
337  data.xelem (i) = Complex (dtmp[i], ctmp[i]);
338  read_mat_binary_data (is, ctmp, prec, 1, swap, flt_fmt);
339 
340  SparseComplexMatrix smc = SparseComplexMatrix (data, r, c,
341  nr_new, nc_new);
342 
343  tc = order ? smc.transpose () : smc;
344  }
345  else
346  {
347  octave_idx_type nr_new, nc_new;
348  Array<double> data (dim_vector (1, nr - 1));
349  Array<octave_idx_type> c (dim_vector (1, nr - 1));
350  Array<octave_idx_type> r (dim_vector (1, nr - 1));
351  OCTAVE_LOCAL_BUFFER (double, dtmp, nr);
352 
353  read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt);
354  for (octave_idx_type i = 0; i < nr - 1; i++)
355  r.xelem (i) = dtmp[i] - 1;
356  nr_new = dtmp[nr - 1];
357  read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt);
358  for (octave_idx_type i = 0; i < nr - 1; i++)
359  c.xelem (i) = dtmp[i] - 1;
360  nc_new = dtmp[nr - 1];
361  read_mat_binary_data (is, data.fortran_vec (), prec, nr - 1,
362  swap, flt_fmt);
363  read_mat_binary_data (is, dtmp, prec, 1, swap, flt_fmt);
364 
365  SparseMatrix sm = SparseMatrix (data, r, c, nr_new, nc_new);
366 
367  tc = order ? sm.transpose () : sm;
368  }
369  }
370  else
371  {
372  re.resize (nr, nc);
373 
374  read_mat_binary_data (is, re.fortran_vec (), prec, dlen, swap, flt_fmt);
375 
376  if (! is || error_state)
377  {
378  error ("load: reading matrix data for '%s'", name);
379  goto data_read_error;
380  }
381 
382  if (imag)
383  {
384  Matrix im (nr, nc);
385 
386  read_mat_binary_data (is, im.fortran_vec (), prec, dlen, swap,
387  flt_fmt);
388 
389  if (! is || error_state)
390  {
391  error ("load: reading imaginary matrix data for '%s'", name);
392  goto data_read_error;
393  }
394 
395  ComplexMatrix ctmp (nr, nc);
396 
397  for (octave_idx_type j = 0; j < nc; j++)
398  for (octave_idx_type i = 0; i < nr; i++)
399  ctmp (i, j) = Complex (re (i, j), im (i, j));
400 
401  tc = order ? ctmp.transpose () : ctmp;
402  }
403  else
404  tc = order ? re.transpose () : re;
405 
406  if (type == 1)
407  tc = tc.convert_to_str (false, true, '\'');
408  }
409 
410  return retval;
411  }
412 
413 data_read_error:
414  error ("load: trouble reading binary file '%s'", filename.c_str ());
415  return retval;
416 }
417 
418 // Save the data from TC along with the corresponding NAME on stream OS
419 // in the MatLab version 4 binary format.
420 
421 bool
422 save_mat_binary_data (std::ostream& os, const octave_value& tc,
423  const std::string& name)
424 {
425  int32_t mopt = 0;
426 
427  mopt += tc.is_sparse_type () ? 2 : tc.is_string () ? 1 : 0;
428 
431 
432  mopt += 1000 * float_format_to_mopt_digit (flt_fmt);
433 
434  os.write (reinterpret_cast<char *> (&mopt), 4);
435 
436  octave_idx_type len;
437  int32_t nr = tc.rows ();
438 
439  int32_t nc = tc.columns ();
440 
441  if (tc.is_sparse_type ())
442  {
443  len = tc.nnz ();
444  uint32_t nnz = len + 1;
445  os.write (reinterpret_cast<char *> (&nnz), 4);
446 
447  uint32_t iscmplx = tc.is_complex_type () ? 4 : 3;
448  os.write (reinterpret_cast<char *> (&iscmplx), 4);
449 
450  uint32_t tmp = 0;
451  os.write (reinterpret_cast<char *> (&tmp), 4);
452  }
453  else
454  {
455  os.write (reinterpret_cast<char *> (&nr), 4);
456  os.write (reinterpret_cast<char *> (&nc), 4);
457 
458  int32_t imag = tc.is_complex_type () ? 1 : 0;
459  os.write (reinterpret_cast<char *> (&imag), 4);
460 
461  len = nr * nc;
462  }
463 
464  // LEN includes the terminating character, and the file is also
465  // supposed to include it.
466 
467  int32_t name_len = name.length () + 1;
468 
469  os.write (reinterpret_cast<char *> (&name_len), 4);
470  os << name << '\0';
471 
472  if (tc.is_string ())
473  {
474  unwind_protect frame;
475 
476  charMatrix chm = tc.char_matrix_value ();
477 
478  octave_idx_type nrow = chm.rows ();
479  octave_idx_type ncol = chm.cols ();
480 
481  OCTAVE_LOCAL_BUFFER (double, buf, ncol*nrow);
482 
483  for (octave_idx_type i = 0; i < nrow; i++)
484  {
485  std::string tstr = chm.row_as_string (i);
486  const char *s = tstr.data ();
487 
488  for (octave_idx_type j = 0; j < ncol; j++)
489  buf[j*nrow+i] = static_cast<double> (*s++ & 0x00FF);
490  }
491  std::streamsize n_bytes = static_cast<std::streamsize> (nrow) *
492  static_cast<std::streamsize> (ncol) *
493  sizeof (double);
494  os.write (reinterpret_cast<char *> (buf), n_bytes);
495  }
496  else if (tc.is_range ())
497  {
498  Range r = tc.range_value ();
499  double base = r.base ();
500  double inc = r.inc ();
501  octave_idx_type nel = r.nelem ();
502  for (octave_idx_type i = 0; i < nel; i++)
503  {
504  double x = base + i * inc;
505  os.write (reinterpret_cast<char *> (&x), 8);
506  }
507  }
508  else if (tc.is_real_scalar ())
509  {
510  double tmp = tc.double_value ();
511  os.write (reinterpret_cast<char *> (&tmp), 8);
512  }
513  else if (tc.is_sparse_type ())
514  {
515  double ds;
516  OCTAVE_LOCAL_BUFFER (double, dtmp, len);
517  if (tc.is_complex_matrix ())
518  {
520 
521  for (octave_idx_type i = 0; i < len; i++)
522  dtmp[i] = m.ridx (i) + 1;
523  std::streamsize n_bytes = 8 * static_cast<std::streamsize> (len);
524  os.write (reinterpret_cast<const char *> (dtmp), n_bytes);
525  ds = nr;
526  os.write (reinterpret_cast<const char *> (&ds), 8);
527 
528  octave_idx_type ii = 0;
529  for (octave_idx_type j = 0; j < nc; j++)
530  for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++)
531  dtmp[ii++] = j + 1;
532  os.write (reinterpret_cast<const char *> (dtmp), n_bytes);
533  ds = nc;
534  os.write (reinterpret_cast<const char *> (&ds), 8);
535 
536  for (octave_idx_type i = 0; i < len; i++)
537  dtmp[i] = std::real (m.data (i));
538  os.write (reinterpret_cast<const char *> (dtmp), n_bytes);
539  ds = 0.;
540  os.write (reinterpret_cast<const char *> (&ds), 8);
541 
542  for (octave_idx_type i = 0; i < len; i++)
543  dtmp[i] = std::imag (m.data (i));
544  os.write (reinterpret_cast<const char *> (dtmp), n_bytes);
545  os.write (reinterpret_cast<const char *> (&ds), 8);
546  }
547  else
548  {
550 
551  for (octave_idx_type i = 0; i < len; i++)
552  dtmp[i] = m.ridx (i) + 1;
553  std::streamsize n_bytes = 8 * static_cast<std::streamsize> (len);
554  os.write (reinterpret_cast<const char *> (dtmp), n_bytes);
555  ds = nr;
556  os.write (reinterpret_cast<const char *> (&ds), 8);
557 
558  octave_idx_type ii = 0;
559  for (octave_idx_type j = 0; j < nc; j++)
560  for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++)
561  dtmp[ii++] = j + 1;
562  os.write (reinterpret_cast<const char *> (dtmp), n_bytes);
563  ds = nc;
564  os.write (reinterpret_cast<const char *> (&ds), 8);
565 
566  os.write (reinterpret_cast<const char *> (m.data ()), n_bytes);
567  ds = 0.;
568  os.write (reinterpret_cast<const char *> (&ds), 8);
569  }
570  }
571  else if (tc.is_real_matrix ())
572  {
573  Matrix m = tc.matrix_value ();
574  std::streamsize n_bytes = 8 * static_cast<std::streamsize> (len);
575  os.write (reinterpret_cast<const char *> (m.data ()), n_bytes);
576  }
577  else if (tc.is_complex_scalar ())
578  {
579  Complex tmp = tc.complex_value ();
580  os.write (reinterpret_cast<char *> (&tmp), 16);
581  }
582  else if (tc.is_complex_matrix ())
583  {
584  ComplexMatrix m_cmplx = tc.complex_matrix_value ();
585  Matrix m = ::real (m_cmplx);
586  std::streamsize n_bytes = 8 * static_cast<std::streamsize> (len);
587  os.write (reinterpret_cast<const char *> (m.data ()), n_bytes);
588  m = ::imag (m_cmplx);
589  os.write (reinterpret_cast<const char *> (m.data ()), n_bytes);
590  }
591  else
592  gripe_wrong_type_arg ("save", tc, false);
593 
594  return ! os.fail ();
595 }
octave_idx_type nnz(void) const
Definition: ov.h:492
bool is_range(void) const
Definition: ov.h:571
T * data(void)
Definition: Sparse.h:509
void gripe_wrong_type_arg(const char *name, const char *s, bool is_error)
Definition: gripes.cc:135
octave_idx_type rows(void) const
Definition: ov.h:473
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:130
SparseMatrix transpose(void) const
Definition: dSparse.h:133
octave_idx_type nelem(void) const
Definition: Range.h:64
bool is_complex_scalar(void) const
Definition: ov.h:541
Definition: Range.h:31
void error(const char *fmt,...)
Definition: error.cc:476
octave_idx_type * cidx(void)
Definition: Sparse.h:531
static void read_mat_binary_data(std::istream &is, double *data, int precision, int len, bool swap, oct_mach_info::float_format flt_fmt)
Definition: ls-mat4.cc:76
std::string row_as_string(octave_idx_type, bool strip_ws=false) const
Definition: chMatrix.cc:84
octave_idx_type rows(void) const
Definition: Array.h:313
SparseComplexMatrix transpose(void) const
Definition: CSparse.h:137
int read_mat_file_header(std::istream &is, bool &swap, int32_t &mopt, int32_t &nr, int32_t &nc, int32_t &imag, int32_t &len, int quiet)
Definition: ls-mat4.cc:112
octave_idx_type columns(void) const
Definition: ov.h:475
void swap_bytes< 4 >(void *ptr)
Definition: byte-swap.h:59
octave_value convert_to_str(bool pad=false, bool force=false, char type= '\'') const
Definition: ov.h:1017
bool is_complex_matrix(void) const
Definition: ov.h:544
bool is_sparse_type(void) const
Definition: ov.h:666
bool is_real_scalar(void) const
Definition: ov.h:535
Range range_value(void) const
Definition: ov.h:903
bool is_string(void) const
Definition: ov.h:562
double inc(void) const
Definition: Range.h:63
const T * data(void) const
Definition: Array.h:479
int error_state
Definition: error.cc:101
bool is_complex_type(void) const
Definition: ov.h:654
int float_format_to_mopt_digit(oct_mach_info::float_format flt_fmt)
Definition: ls-mat4.cc:208
Matrix transpose(void) const
Definition: dMatrix.h:114
static bool words_big_endian(void)
Definition: mach-info.cc:171
Definition: dMatrix.h:35
ComplexMatrix transpose(void) const
Definition: CMatrix.h:151
oct_mach_info::float_format mopt_digit_to_float_format(int mach)
Definition: ls-mat4.cc:182
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:824
void read_doubles(std::istream &is, double *data, save_type type, octave_idx_type len, bool swap, oct_mach_info::float_format fmt)
Definition: data-conv.cc:778
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:773
charMatrix char_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:814
T & xelem(octave_idx_type n)
Definition: Array.h:353
Handles the reference counting for all the derived classes.
Definition: Array.h:45
octave_idx_type * ridx(void)
Definition: Sparse.h:518
static float_format native_float_format(void)
Definition: mach-info.cc:164
ComplexMatrix complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:791
bool save_mat_binary_data(std::ostream &os, const octave_value &tc, const std::string &name)
Definition: ls-mat4.cc:422
Complex complex_value(bool frc_str_conv=false) const
Definition: ov.h:785
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:197
double base(void) const
Definition: Range.h:61
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:162
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:820
std::complex< double > Complex
Definition: oct-cmplx.h:29
const T * fortran_vec(void) const
Definition: Array.h:481
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:156
double double_value(bool frc_str_conv=false) const
Definition: ov.h:759
octave_idx_type cols(void) const
Definition: Array.h:321
F77_RET_T const double * x
bool is_real_matrix(void) const
Definition: ov.h:538