GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
ov-flt-cx-mat.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2013 John W. Eaton
4 Copyright (C) 2009-2010 VZLU Prague
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <iostream>
29 #include <vector>
30 
31 #include "data-conv.h"
32 #include "lo-ieee.h"
33 #include "lo-specfun.h"
34 #include "lo-mappers.h"
35 #include "mx-base.h"
36 #include "mach-info.h"
37 #include "oct-locbuf.h"
38 
39 #include "gripes.h"
40 #include "mxarray.h"
41 #include "oct-obj.h"
42 #include "oct-stream.h"
43 #include "ops.h"
44 #include "ov-base.h"
45 #include "ov-base-mat.h"
46 #include "ov-base-mat.cc"
47 #include "ov-complex.h"
48 #include "ov-flt-complex.h"
49 #include "ov-cx-mat.h"
50 #include "ov-flt-cx-mat.h"
51 #include "ov-re-mat.h"
52 #include "ov-flt-re-mat.h"
53 #include "ov-scalar.h"
54 #include "ov-float.h"
55 #include "pr-output.h"
56 #include "ops.h"
57 
58 #include "byte-swap.h"
59 #include "ls-oct-ascii.h"
60 #include "ls-hdf5.h"
61 #include "ls-utils.h"
62 
64 
66 
68  "float complex matrix", "single");
69 
72 {
73  octave_base_value *retval = 0;
74 
75  if (matrix.numel () == 1)
76  {
77  FloatComplex c = matrix (0);
78 
79  if (std::imag (c) == 0.0)
80  retval = new octave_float_scalar (std::real (c));
81  else
82  retval = new octave_float_complex (c);
83  }
84  else if (matrix.all_elements_are_real ())
85  retval = new octave_float_matrix (::real (matrix));
86 
87  return retval;
88 }
89 
90 double
91 octave_float_complex_matrix::double_value (bool force_conversion) const
92 {
93  double retval = lo_ieee_nan_value ();
94 
95  if (! force_conversion)
96  gripe_implicit_conversion ("Octave:imag-to-real",
97  "complex matrix", "real scalar");
98 
99  if (rows () > 0 && columns () > 0)
100  {
101  gripe_implicit_conversion ("Octave:array-to-scalar",
102  "complex matrix", "real scalar");
103 
104  retval = std::real (matrix (0, 0));
105  }
106  else
107  gripe_invalid_conversion ("complex matrix", "real scalar");
108 
109  return retval;
110 }
111 
112 float
113 octave_float_complex_matrix::float_value (bool force_conversion) const
114 {
115  float retval = lo_ieee_float_nan_value ();
116 
117  if (! force_conversion)
118  gripe_implicit_conversion ("Octave:imag-to-real",
119  "complex matrix", "real scalar");
120 
121  if (rows () > 0 && columns () > 0)
122  {
123  gripe_implicit_conversion ("Octave:array-to-scalar",
124  "complex matrix", "real scalar");
125 
126  retval = std::real (matrix (0, 0));
127  }
128  else
129  gripe_invalid_conversion ("complex matrix", "real scalar");
130 
131  return retval;
132 }
133 
134 Matrix
135 octave_float_complex_matrix::matrix_value (bool force_conversion) const
136 {
137  Matrix retval;
138 
139  if (! force_conversion)
140  gripe_implicit_conversion ("Octave:imag-to-real",
141  "complex matrix", "real matrix");
142 
143  retval = ::real (matrix.matrix_value ());
144 
145  return retval;
146 }
147 
150 {
151  FloatMatrix retval;
152 
153  if (! force_conversion)
154  gripe_implicit_conversion ("Octave:imag-to-real",
155  "complex matrix", "real matrix");
156 
157  retval = ::real (matrix.matrix_value ());
158 
159  return retval;
160 }
161 
162 Complex
164 {
165  double tmp = lo_ieee_nan_value ();
166 
167  Complex retval (tmp, tmp);
168 
169  if (rows () > 0 && columns () > 0)
170  {
171  gripe_implicit_conversion ("Octave:array-to-scalar",
172  "complex matrix", "complex scalar");
173 
174  retval = matrix (0, 0);
175  }
176  else
177  gripe_invalid_conversion ("complex matrix", "complex scalar");
178 
179  return retval;
180 }
181 
184 {
185  float tmp = lo_ieee_float_nan_value ();
186 
187  FloatComplex retval (tmp, tmp);
188 
189  if (rows () > 0 && columns () > 0)
190  {
191  gripe_implicit_conversion ("Octave:array-to-scalar",
192  "complex matrix", "complex scalar");
193 
194  retval = matrix (0, 0);
195  }
196  else
197  gripe_invalid_conversion ("complex matrix", "complex scalar");
198 
199  return retval;
200 }
201 
204 {
205  return matrix.matrix_value ();
206 }
207 
210 {
212 }
213 
216 {
217  if (matrix.any_element_is_nan ())
219  else if (warn && (! matrix.all_elements_are_real ()
220  || real (matrix).any_element_not_one_or_zero ()))
222 
223  return mx_el_ne (matrix, FloatComplex (0.0));
224 }
225 
228 {
229  charNDArray retval;
230 
231  if (! frc_str_conv)
232  gripe_implicit_conversion ("Octave:num-to-str",
233  "complex matrix", "string");
234  else
235  {
236  retval = charNDArray (dims ());
237  octave_idx_type nel = numel ();
238 
239  for (octave_idx_type i = 0; i < nel; i++)
240  retval.elem (i) = static_cast<char>(std::real (matrix.elem (i)));
241  }
242 
243  return retval;
244 }
245 
248 {
249  return FloatComplexNDArray (matrix);
250 }
251 
254 {
255  SparseMatrix retval;
256 
257  if (! force_conversion)
258  gripe_implicit_conversion ("Octave:imag-to-real",
259  "complex matrix", "real matrix");
260 
261  retval = SparseMatrix (::real (complex_matrix_value ()));
262 
263  return retval;
264 }
265 
268 {
270 }
271 
274 {
275  octave_value retval;
276  if (k == 0 && matrix.ndims () == 2
277  && (matrix.rows () == 1 || matrix.columns () == 1))
279  else
281 
282  return retval;
283 }
284 
287 {
288  octave_value retval;
289 
290  if (matrix.ndims () == 2
291  && (matrix.rows () == 1 || matrix.columns () == 1))
292  {
294 
295  retval = mat.diag (m, n);
296  }
297  else
298  error ("diag: expecting vector argument");
299 
300  return retval;
301 }
302 
303 bool
305 {
306  dim_vector d = dims ();
307  if (d.length () > 2)
308  {
310 
311  os << "# ndims: " << d.length () << "\n";
312 
313  for (int i = 0; i < d.length (); i++)
314  os << " " << d (i);
315 
316  os << "\n" << tmp;
317  }
318  else
319  {
320  // Keep this case, rather than use generic code above for backward
321  // compatiability. Makes load_ascii much more complex!!
322  os << "# rows: " << rows () << "\n"
323  << "# columns: " << columns () << "\n";
324 
325  os << complex_matrix_value ();
326  }
327 
328  return true;
329 }
330 
331 bool
333 {
334  bool success = true;
335 
337 
338  keywords[0] = "ndims";
339  keywords[1] = "rows";
340 
341  std::string kw;
342  octave_idx_type val = 0;
343 
344  if (extract_keyword (is, keywords, kw, val, true))
345  {
346  if (kw == "ndims")
347  {
348  int mdims = static_cast<int> (val);
349 
350  if (mdims >= 0)
351  {
352  dim_vector dv;
353  dv.resize (mdims);
354 
355  for (int i = 0; i < mdims; i++)
356  is >> dv(i);
357 
358  if (is)
359  {
360  FloatComplexNDArray tmp(dv);
361 
362  is >> tmp;
363 
364  if (is)
365  matrix = tmp;
366  else
367  {
368  error ("load: failed to load matrix constant");
369  success = false;
370  }
371  }
372  else
373  {
374  error ("load: failed to read dimensions");
375  success = false;
376  }
377  }
378  else
379  {
380  error ("load: failed to extract number of dimensions");
381  success = false;
382  }
383  }
384  else if (kw == "rows")
385  {
386  octave_idx_type nr = val;
387  octave_idx_type nc = 0;
388 
389  if (nr >= 0 && extract_keyword (is, "columns", nc) && nc >= 0)
390  {
391  if (nr > 0 && nc > 0)
392  {
393  FloatComplexMatrix tmp (nr, nc);
394  is >> tmp;
395  if (is)
396  matrix = tmp;
397  else
398  {
399  error ("load: failed to load matrix constant");
400  success = false;
401  }
402  }
403  else if (nr == 0 || nc == 0)
404  matrix = FloatComplexMatrix (nr, nc);
405  else
406  panic_impossible ();
407  }
408  else
409  {
410  error ("load: failed to extract number of rows and columns");
411  success = false;
412  }
413  }
414  else
415  panic_impossible ();
416  }
417  else
418  {
419  error ("load: failed to extract number of rows and columns");
420  success = false;
421  }
422 
423  return success;
424 }
425 
426 bool
428 {
429  dim_vector d = dims ();
430  if (d.length () < 1)
431  return false;
432 
433  // Use negative value for ndims to differentiate with old format!!
434  int32_t tmp = - d.length ();
435  os.write (reinterpret_cast<char *> (&tmp), 4);
436  for (int i = 0; i < d.length (); i++)
437  {
438  tmp = d(i);
439  os.write (reinterpret_cast<char *> (&tmp), 4);
440  }
441 
443  save_type st = LS_FLOAT;
444  if (d.numel () > 4096) // FIXME: make this configurable.
445  {
446  float max_val, min_val;
447  if (m.all_integers (max_val, min_val))
448  st = get_save_type (max_val, min_val);
449  }
450 
451  const FloatComplex *mtmp = m.data ();
452  write_floats (os, reinterpret_cast<const float *> (mtmp), st, 2 * d.numel ());
453 
454  return true;
455 }
456 
457 bool
458 octave_float_complex_matrix::load_binary (std::istream& is, bool swap,
460 {
461  char tmp;
462  int32_t mdims;
463  if (! is.read (reinterpret_cast<char *> (&mdims), 4))
464  return false;
465  if (swap)
466  swap_bytes<4> (&mdims);
467  if (mdims < 0)
468  {
469  mdims = - mdims;
470  int32_t di;
471  dim_vector dv;
472  dv.resize (mdims);
473 
474  for (int i = 0; i < mdims; i++)
475  {
476  if (! is.read (reinterpret_cast<char *> (&di), 4))
477  return false;
478  if (swap)
479  swap_bytes<4> (&di);
480  dv(i) = di;
481  }
482 
483  // Convert an array with a single dimension to be a row vector.
484  // Octave should never write files like this, other software
485  // might.
486 
487  if (mdims == 1)
488  {
489  mdims = 2;
490  dv.resize (mdims);
491  dv(1) = dv(0);
492  dv(0) = 1;
493  }
494 
495  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
496  return false;
497 
498  FloatComplexNDArray m(dv);
499  FloatComplex *im = m.fortran_vec ();
500  read_floats (is, reinterpret_cast<float *> (im),
501  static_cast<save_type> (tmp), 2 * dv.numel (), swap, fmt);
502  if (error_state || ! is)
503  return false;
504  matrix = m;
505  }
506  else
507  {
508  int32_t nr, nc;
509  nr = mdims;
510  if (! is.read (reinterpret_cast<char *> (&nc), 4))
511  return false;
512  if (swap)
513  swap_bytes<4> (&nc);
514  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
515  return false;
516  FloatComplexMatrix m (nr, nc);
517  FloatComplex *im = m.fortran_vec ();
518  octave_idx_type len = nr * nc;
519  read_floats (is, reinterpret_cast<float *> (im),
520  static_cast<save_type> (tmp), 2*len, swap, fmt);
521  if (error_state || ! is)
522  return false;
523  matrix = m;
524  }
525  return true;
526 }
527 
528 #if defined (HAVE_HDF5)
529 
530 bool
531 octave_float_complex_matrix::save_hdf5 (hid_t loc_id, const char *name, bool)
532 {
533  dim_vector dv = dims ();
534  int empty = save_hdf5_empty (loc_id, name, dv);
535  if (empty)
536  return (empty > 0);
537 
538  int rank = dv.length ();
539  hid_t space_hid = -1, data_hid = -1, type_hid = -1;
540  bool retval = true;
542 
543  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
544 
545  // Octave uses column-major, while HDF5 uses row-major ordering
546  for (int i = 0; i < rank; i++)
547  hdims[i] = dv (rank-i-1);
548 
549  space_hid = H5Screate_simple (rank, hdims, 0);
550  if (space_hid < 0) return false;
551 
552  hid_t save_type_hid = H5T_NATIVE_FLOAT;
553 
554 #if HAVE_HDF5_INT2FLOAT_CONVERSIONS
555  // hdf5 currently doesn't support float/integer conversions
556  else
557  {
558  float max_val, min_val;
559 
560  if (m.all_integers (max_val, min_val))
561  save_type_hid
562  = save_type_to_hdf5 (get_save_type (max_val, min_val));
563  }
564 #endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */
565 
566  type_hid = hdf5_make_complex_type (save_type_hid);
567  if (type_hid < 0)
568  {
569  H5Sclose (space_hid);
570  return false;
571  }
572 #if HAVE_HDF5_18
573  data_hid = H5Dcreate (loc_id, name, type_hid, space_hid,
574  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
575 #else
576  data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, H5P_DEFAULT);
577 #endif
578  if (data_hid < 0)
579  {
580  H5Sclose (space_hid);
581  H5Tclose (type_hid);
582  return false;
583  }
584 
585  hid_t complex_type_hid = hdf5_make_complex_type (H5T_NATIVE_FLOAT);
586  if (complex_type_hid < 0) retval = false;
587 
588  if (retval)
589  {
590  FloatComplex *mtmp = m.fortran_vec ();
591  if (H5Dwrite (data_hid, complex_type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT,
592  mtmp) < 0)
593  {
594  H5Tclose (complex_type_hid);
595  retval = false;
596  }
597  }
598 
599  H5Tclose (complex_type_hid);
600  H5Dclose (data_hid);
601  H5Tclose (type_hid);
602  H5Sclose (space_hid);
603 
604  return retval;
605 }
606 
607 bool
608 octave_float_complex_matrix::load_hdf5 (hid_t loc_id, const char *name)
609 {
610  bool retval = false;
611 
612  dim_vector dv;
613  int empty = load_hdf5_empty (loc_id, name, dv);
614  if (empty > 0)
615  matrix.resize (dv);
616  if (empty)
617  return (empty > 0);
618 
619 #if HAVE_HDF5_18
620  hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
621 #else
622  hid_t data_hid = H5Dopen (loc_id, name);
623 #endif
624  hid_t type_hid = H5Dget_type (data_hid);
625 
626  hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_FLOAT);
627 
628  if (! hdf5_types_compatible (type_hid, complex_type))
629  {
630  H5Tclose (complex_type);
631  H5Dclose (data_hid);
632  return false;
633  }
634 
635  hid_t space_id = H5Dget_space (data_hid);
636 
637  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
638 
639  if (rank < 1)
640  {
641  H5Tclose (complex_type);
642  H5Sclose (space_id);
643  H5Dclose (data_hid);
644  return false;
645  }
646 
647  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
648  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
649 
650  H5Sget_simple_extent_dims (space_id, hdims, maxdims);
651 
652  // Octave uses column-major, while HDF5 uses row-major ordering
653  if (rank == 1)
654  {
655  dv.resize (2);
656  dv(0) = 1;
657  dv(1) = hdims[0];
658  }
659  else
660  {
661  dv.resize (rank);
662  for (hsize_t i = 0, j = rank - 1; i < rank; i++, j--)
663  dv(j) = hdims[i];
664  }
665 
666  FloatComplexNDArray m (dv);
667  FloatComplex *reim = m.fortran_vec ();
668  if (H5Dread (data_hid, complex_type, H5S_ALL, H5S_ALL, H5P_DEFAULT,
669  reim) >= 0)
670  {
671  retval = true;
672  matrix = m;
673  }
674 
675  H5Tclose (complex_type);
676  H5Sclose (space_id);
677  H5Dclose (data_hid);
678 
679  return retval;
680 }
681 
682 #endif
683 
684 void
686  bool pr_as_read_syntax) const
687 {
688  octave_print_internal (os, matrix, pr_as_read_syntax,
690 }
691 
692 mxArray *
694 {
695  mxArray *retval = new mxArray (mxSINGLE_CLASS, dims (), mxCOMPLEX);
696 
697  float *pr = static_cast<float *> (retval->get_data ());
698  float *pi = static_cast<float *> (retval->get_imag_data ());
699 
700  mwSize nel = numel ();
701 
702  const FloatComplex *p = matrix.data ();
703 
704  for (mwIndex i = 0; i < nel; i++)
705  {
706  pr[i] = std::real (p[i]);
707  pi[i] = std::imag (p[i]);
708  }
709 
710  return retval;
711 }
712 
715 {
716  switch (umap)
717  {
718  // Mappers handled specially.
719  case umap_real:
721  case umap_imag:
723  case umap_conj:
725 
726 #define ARRAY_METHOD_MAPPER(UMAP, FCN) \
727  case umap_ ## UMAP: \
728  return octave_value (matrix.FCN ())
729 
731  ARRAY_METHOD_MAPPER (isnan, isnan);
732  ARRAY_METHOD_MAPPER (isinf, isinf);
733  ARRAY_METHOD_MAPPER (finite, isfinite);
734 
735 #define ARRAY_MAPPER(UMAP, TYPE, FCN) \
736  case umap_ ## UMAP: \
737  return octave_value (matrix.map<TYPE> (FCN))
738 
741  ARRAY_MAPPER (angle, float, std::arg);
742  ARRAY_MAPPER (arg, float, std::arg);
753  ARRAY_MAPPER (cos, FloatComplex, std::cos);
754  ARRAY_MAPPER (cosh, FloatComplex, std::cosh);
755  ARRAY_MAPPER (exp, FloatComplex, std::exp);
759  ARRAY_MAPPER (log, FloatComplex, std::log);
761  ARRAY_MAPPER (log10, FloatComplex, std::log10);
763  ARRAY_MAPPER (round, FloatComplex, xround);
764  ARRAY_MAPPER (roundb, FloatComplex, xroundb);
766  ARRAY_MAPPER (sin, FloatComplex, std::sin);
767  ARRAY_MAPPER (sinh, FloatComplex, std::sinh);
768  ARRAY_MAPPER (sqrt, FloatComplex, std::sqrt);
769  ARRAY_MAPPER (tan, FloatComplex, std::tan);
770  ARRAY_MAPPER (tanh, FloatComplex, std::tanh);
771  ARRAY_MAPPER (isna, bool, octave_is_NA);
772 
773  default:
774  return octave_base_value::map (umap);
775  }
776 }