GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ls-mat4.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2018 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
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License 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 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <iomanip>
28 #include <iostream>
29 #include <string>
30 
31 #include "byte-swap.h"
32 #include "dMatrix.h"
33 #include "dSparse.h"
34 #include "data-conv.h"
35 #include "file-ops.h"
36 #include "glob-match.h"
37 #include "lo-mappers.h"
38 #include "mach-info.h"
39 #include "oct-env.h"
40 #include "oct-locbuf.h"
41 #include "oct-time.h"
42 #include "quit.h"
43 
44 #include "ls-mat4.h"
45 #include "Cell.h"
46 #include "defun.h"
47 #include "error.h"
48 #include "errwarn.h"
49 #include "load-save.h"
50 #include "oct-map.h"
51 #include "ov-cell.h"
52 #include "ovl.h"
53 #include "pager.h"
54 #include "pt-exp.h"
55 #include "sysdep.h"
56 #include "unwind-prot.h"
57 #include "utils.h"
58 #include "variables.h"
59 #include "version.h"
60 
61 
62 // Read LEN elements of data from IS in the format specified by
63 // PRECISION, placing the result in DATA. If SWAP is TRUE, swap
64 // the bytes of each element before copying to DATA. FLT_FMT
65 // specifies the format of the data if we are reading floating point
66 // numbers.
67 
68 static void
69 read_mat_binary_data (std::istream& is, double *data, int precision,
70  int len, bool swap,
72 {
73  switch (precision)
74  {
75  case 0:
76  read_doubles (is, data, LS_DOUBLE, len, swap, flt_fmt);
77  break;
78 
79  case 1:
80  read_doubles (is, data, LS_FLOAT, len, swap, flt_fmt);
81  break;
82 
83  case 2:
84  read_doubles (is, data, LS_INT, len, swap, flt_fmt);
85  break;
86 
87  case 3:
88  read_doubles (is, data, LS_SHORT, len, swap, flt_fmt);
89  break;
90 
91  case 4:
92  read_doubles (is, data, LS_U_SHORT, len, swap, flt_fmt);
93  break;
94 
95  case 5:
96  read_doubles (is, data, LS_U_CHAR, len, swap, flt_fmt);
97  break;
98 
99  default:
100  break;
101  }
102 }
103 
104 int
105 read_mat_file_header (std::istream& is, bool& swap, int32_t& mopt,
106  int32_t& nr, int32_t& nc,
107  int32_t& imag, int32_t& len,
108  int quiet)
109 {
110  swap = false;
111 
112  // We expect to fail here, at the beginning of a record, so not
113  // being able to read another mopt value should not result in an
114  // error.
115 
116  is.read (reinterpret_cast<char *> (&mopt), 4);
117  if (! is)
118  return 1;
119 
120  if (! is.read (reinterpret_cast<char *> (&nr), 4))
121  return -1;
122 
123  if (! is.read (reinterpret_cast<char *> (&nc), 4))
124  return -1;
125 
126  if (! is.read (reinterpret_cast<char *> (&imag), 4))
127  return -1;
128 
129  if (! is.read (reinterpret_cast<char *> (&len), 4))
130  return -1;
131 
132 // If mopt is nonzero and the byte order is swapped, mopt will be
133 // bigger than we expect, so we swap bytes.
134 //
135 // If mopt is zero, it means the file was written on a little endian machine,
136 // and we only need to swap if we are running on a big endian machine.
137 //
138 // Gag me.
139 
140  if (octave::mach_info::words_big_endian () && mopt == 0)
141  swap = true;
142 
143  // mopt is signed, therefore byte swap may result in negative value.
144 
145  if (mopt > 9999 || mopt < 0)
146  swap = true;
147 
148  if (swap)
149  {
150  swap_bytes<4> (&mopt);
151  swap_bytes<4> (&nr);
152  swap_bytes<4> (&nc);
153  swap_bytes<4> (&imag);
154  swap_bytes<4> (&len);
155  }
156 
157  if (mopt > 9999 || mopt < 0 || imag > 1 || imag < 0)
158  {
159  if (! quiet)
160  error ("load: can't read binary file");
161 
162  return -1;
163  }
164 
165  return 0;
166 }
167 
168 // We don't just use a cast here, because we need to be able to detect
169 // possible errors.
170 
173 {
175 
176  switch (mach)
177  {
178  case 0:
180  break;
181 
182  case 1:
184  break;
185 
186  case 2:
187  case 3:
188  case 4:
189  default:
191  break;
192  }
193 
194  return flt_fmt;
195 }
196 
197 int
199 {
200  int retval = -1;
201 
202  switch (flt_fmt)
203  {
205  retval = 0;
206  break;
207 
209  retval = 1;
210  break;
211 
212  default:
213  break;
214  }
215 
216  return retval;
217 }
218 
219 // Extract one value (scalar, matrix, string, etc.) from stream IS and
220 // place it in TC, returning the name of the variable.
221 //
222 // The data is expected to be in Matlab version 4 .mat format, though
223 // not all the features of that format are supported.
224 //
225 // FILENAME is used for error messages.
226 //
227 // This format provides no way to tag the data as global.
228 
231  octave_value& tc)
232 {
234 
235  bool swap = false;
236  int32_t mopt, nr, nc, imag, len;
237 
238  int err = read_mat_file_header (is, swap, mopt, nr, nc, imag, len);
239  if (err)
240  {
241  if (err < 0)
242  error ("load: trouble reading binary file '%s'", filename.c_str ());
243 
244  return retval;
245  }
246 
247  int type = 0;
248  int prec = 0;
249  int order = 0;
250  int mach = 0;
251 
252  type = mopt % 10; // Full, sparse, etc.
253  mopt /= 10; // Eliminate first digit.
254  prec = mopt % 10; // double, float, int, etc.
255  mopt /= 10; // Eliminate second digit.
256  order = mopt % 10; // Row or column major ordering.
257  mopt /= 10; // Eliminate third digit.
258  mach = mopt % 10; // IEEE, VAX, etc.
259 
262 
264  error ("load: unrecognized binary format!");
265 
266  if (imag && type == 1)
267  error ("load: encountered complex matrix with string flag set!");
268 
269  int dlen = 0;
270 
271  // LEN includes the terminating character, and the file is also
272  // supposed to include it, but apparently not all files do. Either
273  // way, I think this should work.
274 
275  {
276  OCTAVE_LOCAL_BUFFER (char, name, len+1);
277  name[len] = '\0';
278  if (! is.read (name, len))
279  error ("load: trouble reading binary file '%s'", filename.c_str ());
280  retval = name;
281 
282  dlen = nr * nc;
283  if (dlen < 0)
284  error ("load: trouble reading binary file '%s'", filename.c_str ());
285 
286  if (order)
287  {
288  octave_idx_type tmp = nr;
289  nr = nc;
290  nc = tmp;
291  }
292 
293  if (type == 2)
294  {
295  if (nc == 4)
296  {
297  octave_idx_type nr_new, nc_new;
298  Array<Complex> data (dim_vector (1, nr - 1));
299  Array<octave_idx_type> c (dim_vector (1, nr - 1));
300  Array<octave_idx_type> r (dim_vector (1, nr - 1));
301  OCTAVE_LOCAL_BUFFER (double, dtmp, nr);
302  OCTAVE_LOCAL_BUFFER (double, ctmp, nr);
303 
304  read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt);
305  for (octave_idx_type i = 0; i < nr - 1; i++)
306  r.xelem (i) = dtmp[i] - 1;
307  nr_new = dtmp[nr - 1];
308  read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt);
309  for (octave_idx_type i = 0; i < nr - 1; i++)
310  c.xelem (i) = dtmp[i] - 1;
311  nc_new = dtmp[nr - 1];
312  read_mat_binary_data (is, dtmp, prec, nr - 1, swap, flt_fmt);
313  read_mat_binary_data (is, ctmp, prec, 1, swap, flt_fmt);
314  read_mat_binary_data (is, ctmp, prec, nr - 1, swap, flt_fmt);
315 
316  for (octave_idx_type i = 0; i < nr - 1; i++)
317  data.xelem (i) = Complex (dtmp[i], ctmp[i]);
318  read_mat_binary_data (is, ctmp, prec, 1, swap, flt_fmt);
319 
320  SparseComplexMatrix smc = SparseComplexMatrix (data, r, c,
321  nr_new, nc_new);
322 
323  tc = (order ? smc.transpose () : smc);
324  }
325  else
326  {
327  octave_idx_type nr_new, nc_new;
328  Array<double> data (dim_vector (1, nr - 1));
329  Array<octave_idx_type> c (dim_vector (1, nr - 1));
330  Array<octave_idx_type> r (dim_vector (1, nr - 1));
331  OCTAVE_LOCAL_BUFFER (double, dtmp, nr);
332 
333  read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt);
334  for (octave_idx_type i = 0; i < nr - 1; i++)
335  r.xelem (i) = dtmp[i] - 1;
336  nr_new = dtmp[nr - 1];
337  read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt);
338  for (octave_idx_type i = 0; i < nr - 1; i++)
339  c.xelem (i) = dtmp[i] - 1;
340  nc_new = dtmp[nr - 1];
341  read_mat_binary_data (is, data.fortran_vec (), prec, nr - 1,
342  swap, flt_fmt);
343  read_mat_binary_data (is, dtmp, prec, 1, swap, flt_fmt);
344 
345  SparseMatrix sm = SparseMatrix (data, r, c, nr_new, nc_new);
346 
347  tc = (order ? sm.transpose () : sm);
348  }
349  }
350  else
351  {
352  Matrix re (nr, nc);
353 
354  read_mat_binary_data (is, re.fortran_vec (), prec, dlen, swap, flt_fmt);
355 
356  if (! is)
357  error ("load: reading matrix data for '%s'", name);
358 
359  if (imag)
360  {
361  Matrix im (nr, nc);
362 
363  read_mat_binary_data (is, im.fortran_vec (), prec, dlen, swap,
364  flt_fmt);
365 
366  if (! is)
367  error ("load: reading imaginary matrix data for '%s'", name);
368 
369  ComplexMatrix ctmp (nr, nc);
370 
371  for (octave_idx_type j = 0; j < nc; j++)
372  for (octave_idx_type i = 0; i < nr; i++)
373  ctmp (i,j) = Complex (re(i,j), im(i,j));
374 
375  tc = (order ? ctmp.transpose () : ctmp);
376  }
377  else
378  tc = (order ? re.transpose () : re);
379 
380  if (type == 1)
381  tc = tc.convert_to_str (false, true, '\'');
382  }
383 
384  return retval;
385  }
386 }
387 
388 // Save the data from TC along with the corresponding NAME on stream OS
389 // in the MatLab version 4 binary format.
390 
391 bool
392 save_mat_binary_data (std::ostream& os, const octave_value& tc,
393  const std::string& name)
394 {
395  int32_t mopt = 0;
396 
397  mopt += tc.issparse () ? 2 : tc.is_string () ? 1 : 0;
398 
401 
402  mopt += 1000 * float_format_to_mopt_digit (flt_fmt);
403 
404  os.write (reinterpret_cast<char *> (&mopt), 4);
405 
406  octave_idx_type len;
407  int32_t nr = tc.rows ();
408 
409  int32_t nc = tc.columns ();
410 
411  if (tc.issparse ())
412  {
413  len = tc.nnz ();
414  uint32_t nnz = len + 1;
415  os.write (reinterpret_cast<char *> (&nnz), 4);
416 
417  uint32_t iscmplx = (tc.iscomplex () ? 4 : 3);
418  os.write (reinterpret_cast<char *> (&iscmplx), 4);
419 
420  uint32_t tmp = 0;
421  os.write (reinterpret_cast<char *> (&tmp), 4);
422  }
423  else
424  {
425  os.write (reinterpret_cast<char *> (&nr), 4);
426  os.write (reinterpret_cast<char *> (&nc), 4);
427 
428  int32_t imag = (tc.iscomplex () ? 1 : 0);
429  os.write (reinterpret_cast<char *> (&imag), 4);
430 
431  len = nr * nc;
432  }
433 
434  // LEN includes the terminating character, and the file is also
435  // supposed to include it.
436 
437  int32_t name_len = name.length () + 1;
438 
439  os.write (reinterpret_cast<char *> (&name_len), 4);
440  os << name << '\0';
441 
442  if (tc.is_string ())
443  {
445 
446  charMatrix chm = tc.char_matrix_value ();
447 
448  octave_idx_type nrow = chm.rows ();
449  octave_idx_type ncol = chm.cols ();
450 
451  OCTAVE_LOCAL_BUFFER (double, buf, ncol*nrow);
452 
453  for (octave_idx_type i = 0; i < nrow; i++)
454  {
455  std::string tstr = chm.row_as_string (i);
456  const char *s = tstr.data ();
457 
458  for (octave_idx_type j = 0; j < ncol; j++)
459  buf[j*nrow+i] = static_cast<double> (*s++ & 0x00FF);
460  }
461  std::streamsize n_bytes = static_cast<std::streamsize> (nrow) *
462  static_cast<std::streamsize> (ncol) *
463  sizeof (double);
464  os.write (reinterpret_cast<char *> (buf), n_bytes);
465  }
466  else if (tc.is_range ())
467  {
468  Range r = tc.range_value ();
469  double base = r.base ();
470  double inc = r.inc ();
471  octave_idx_type nel = r.numel ();
472  for (octave_idx_type i = 0; i < nel; i++)
473  {
474  double x = base + i * inc;
475  os.write (reinterpret_cast<char *> (&x), 8);
476  }
477  }
478  else if (tc.is_real_scalar ())
479  {
480  double tmp = tc.double_value ();
481  os.write (reinterpret_cast<char *> (&tmp), 8);
482  }
483  else if (tc.issparse ())
484  {
485  double ds;
486  OCTAVE_LOCAL_BUFFER (double, dtmp, len);
487  if (tc.is_complex_matrix ())
488  {
490 
491  for (octave_idx_type i = 0; i < len; i++)
492  dtmp[i] = m.ridx (i) + 1;
493  std::streamsize n_bytes = 8 * static_cast<std::streamsize> (len);
494  os.write (reinterpret_cast<const char *> (dtmp), n_bytes);
495  ds = nr;
496  os.write (reinterpret_cast<const char *> (&ds), 8);
497 
498  octave_idx_type ii = 0;
499  for (octave_idx_type j = 0; j < nc; j++)
500  for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++)
501  dtmp[ii++] = j + 1;
502  os.write (reinterpret_cast<const char *> (dtmp), n_bytes);
503  ds = nc;
504  os.write (reinterpret_cast<const char *> (&ds), 8);
505 
506  for (octave_idx_type i = 0; i < len; i++)
507  dtmp[i] = std::real (m.data (i));
508  os.write (reinterpret_cast<const char *> (dtmp), n_bytes);
509  ds = 0.;
510  os.write (reinterpret_cast<const char *> (&ds), 8);
511 
512  for (octave_idx_type i = 0; i < len; i++)
513  dtmp[i] = std::imag (m.data (i));
514  os.write (reinterpret_cast<const char *> (dtmp), n_bytes);
515  os.write (reinterpret_cast<const char *> (&ds), 8);
516  }
517  else
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  os.write (reinterpret_cast<const char *> (m.data ()), n_bytes);
537  ds = 0.;
538  os.write (reinterpret_cast<const char *> (&ds), 8);
539  }
540  }
541  else if (tc.is_real_matrix ())
542  {
543  Matrix m = tc.matrix_value ();
544  std::streamsize n_bytes = 8 * static_cast<std::streamsize> (len);
545  os.write (reinterpret_cast<const char *> (m.data ()), n_bytes);
546  }
547  else if (tc.is_complex_scalar ())
548  {
549  Complex tmp = tc.complex_value ();
550  os.write (reinterpret_cast<char *> (&tmp), 16);
551  }
552  else if (tc.is_complex_matrix ())
553  {
554  ComplexMatrix m_cmplx = tc.complex_matrix_value ();
555  Matrix m = ::real (m_cmplx);
556  std::streamsize n_bytes = 8 * static_cast<std::streamsize> (len);
557  os.write (reinterpret_cast<const char *> (m.data ()), n_bytes);
558  m = ::imag (m_cmplx);
559  os.write (reinterpret_cast<const char *> (m.data ()), n_bytes);
560  }
561  else
562  // FIXME: Should this just error out rather than warn?
563  warn_wrong_type_arg ("save", tc);
564 
565  return ! os.fail ();
566 }
octave_idx_type write(const octave_value &data, octave_idx_type block_size, oct_data_conv::data_type output_type, octave_idx_type skip, mach_info::float_format flt_fmt)
Definition: oct-stream.cc:6704
octave_idx_type rows(void) const
Definition: Array.h:404
T * data(void)
Definition: Sparse.h:486
Range range_value(void) const
Definition: ov.h:970
SparseComplexMatrix transpose(void) const
Definition: CSparse.h:142
const T * data(void) const
Definition: Array.h:582
bool is_real_matrix(void) const
Definition: ov.h:553
octave_idx_type * cidx(void)
Definition: Sparse.h:508
const T * fortran_vec(void) const
Definition: Array.h:584
Definition: Range.h:33
bool is_complex_scalar(void) const
Definition: ov.h:556
void error(const char *fmt,...)
Definition: error.cc:578
SparseMatrix transpose(void) const
Definition: dSparse.h:130
std::string filename
Definition: urlwrite.cc:121
octave::mach_info::float_format flt_fmt
Definition: load-save.cc:736
Complex complex_value(bool frc_str_conv=false) const
Definition: ov.h:846
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
Definition: file-io.cc:587
s
Definition: file-io.cc:2729
ComplexMatrix transpose(void) const
Definition: CMatrix.h:168
charMatrix char_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:875
octave_idx_type cols(void) const
Definition: Array.h:412
double base(void) const
Definition: Range.h:78
bool swap
Definition: load-save.cc:738
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:105
Matrix transpose(void) const
Definition: dMatrix.h:132
nd deftypefn *std::string name
Definition: sysdep.cc:647
void swap_bytes< 4 >(void *ptr)
Definition: byte-swap.h:60
int float_format_to_mopt_digit(octave::mach_info::float_format flt_fmt)
Definition: ls-mat4.cc:198
void read_doubles(std::istream &is, double *data, save_type type, octave_idx_type len, bool swap, octave::mach_info::float_format fmt)
Definition: data-conv.cc:772
octave_idx_type columns(void) const
Definition: ov.h:474
float_format native_float_format(void)
Definition: mach-info.cc:62
octave_idx_type numel(void) const
Definition: Range.h:85
octave_idx_type rows(void) const
Definition: ov.h:472
double tmp
Definition: data.cc:6252
bool issparse(void) const
Definition: ov.h:730
octave_value retval
Definition: data.cc:6246
bool is_complex_matrix(void) const
Definition: ov.h:559
octave_idx_type * ridx(void)
Definition: Sparse.h:495
idx type
Definition: ov.cc:3114
Definition: dMatrix.h:36
bool words_big_endian(void)
Definition: mach-info.cc:69
octave_value convert_to_str(bool pad=false, bool force=false, char type='\'') const
Definition: ov.h:1251
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:885
T & xelem(octave_idx_type n)
Definition: Array.h:458
octave::mach_info::float_format mopt_digit_to_float_format(int mach)
Definition: ls-mat4.cc:172
octave::unwind_protect frame
Definition: graphics.cc:12190
std::string row_as_string(octave_idx_type, bool strip_ws=false) const
Definition: chMatrix.cc:80
octave_idx_type nnz(void) const
Definition: ov.h:496
bool save_mat_binary_data(std::ostream &os, const octave_value &tc, const std::string &name)
Definition: ls-mat4.cc:392
void warn_wrong_type_arg(const char *name, const octave_value &tc)
Definition: errwarn.cc:366
double double_value(bool frc_str_conv=false) const
Definition: ov.h:822
static void read_mat_binary_data(std::istream &is, double *data, int precision, int len, bool swap, octave::mach_info::float_format flt_fmt)
Definition: ls-mat4.cc:69
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:881
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:41
bool iscomplex(void) const
Definition: ov.h:710
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:141
for i
Definition: data.cc:5264
bool is_string(void) const
Definition: ov.h:577
OCTAVE_EXPORT octave_value_list error nd deftypefn *const octave_scalar_map err
Definition: error.cc:1049
ComplexMatrix complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:852
std::complex< double > Complex
Definition: oct-cmplx.h:31
bool is_range(void) const
Definition: ov.h:586
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:135
write the output to stdout if nargout is
Definition: load-save.cc:1612
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
bool is_real_scalar(void) const
Definition: ov.h:550
octave::stream os
Definition: file-io.cc:627
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:834
F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE * x
double inc(void) const
Definition: Range.h:80