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-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-cx-mat.h"
49 #include "ov-flt-cx-mat.h"
50 #include "ov-re-mat.h"
51 #include "ov-scalar.h"
52 #include "pr-output.h"
53 
54 #include "byte-swap.h"
55 #include "ls-oct-ascii.h"
56 #include "ls-hdf5.h"
57 #include "ls-utils.h"
58 
60 
62 
64  "complex matrix", "double");
65 
66 static octave_base_value *
68 {
70 
71  return new octave_float_complex_matrix (v.float_complex_array_value ());
72 }
73 
76 {
80 }
81 
84 {
85  octave_base_value *retval = 0;
86 
87  if (matrix.numel () == 1)
88  {
89  Complex c = matrix (0);
90 
91  if (std::imag (c) == 0.0)
92  retval = new octave_scalar (std::real (c));
93  else
94  retval = new octave_complex (c);
95  }
96  else if (matrix.all_elements_are_real ())
97  retval = new octave_matrix (::real (matrix));
98 
99  return retval;
100 }
101 
102 double
103 octave_complex_matrix::double_value (bool force_conversion) const
104 {
105  double retval = lo_ieee_nan_value ();
106 
107  if (! force_conversion)
108  gripe_implicit_conversion ("Octave:imag-to-real",
109  "complex matrix", "real scalar");
110 
111  if (rows () > 0 && columns () > 0)
112  {
113  gripe_implicit_conversion ("Octave:array-to-scalar",
114  "complex matrix", "real scalar");
115 
116  retval = std::real (matrix (0, 0));
117  }
118  else
119  gripe_invalid_conversion ("complex matrix", "real scalar");
120 
121  return retval;
122 }
123 
124 float
125 octave_complex_matrix::float_value (bool force_conversion) const
126 {
127  float retval = lo_ieee_float_nan_value ();
128 
129  if (! force_conversion)
130  gripe_implicit_conversion ("Octave:imag-to-real",
131  "complex matrix", "real scalar");
132 
133  if (rows () > 0 && columns () > 0)
134  {
135  gripe_implicit_conversion ("Octave:array-to-scalar",
136  "complex matrix", "real scalar");
137 
138  retval = std::real (matrix (0, 0));
139  }
140  else
141  gripe_invalid_conversion ("complex matrix", "real scalar");
142 
143  return retval;
144 }
145 
146 Matrix
147 octave_complex_matrix::matrix_value (bool force_conversion) const
148 {
149  Matrix retval;
150 
151  if (! force_conversion)
152  gripe_implicit_conversion ("Octave:imag-to-real",
153  "complex matrix", "real matrix");
154 
155  retval = ::real (matrix.matrix_value ());
156 
157  return retval;
158 }
159 
161 octave_complex_matrix::float_matrix_value (bool force_conversion) const
162 {
163  FloatMatrix retval;
164 
165  if (! force_conversion)
166  gripe_implicit_conversion ("Octave:imag-to-real",
167  "complex matrix", "real matrix");
168 
169  retval = ::real (matrix.matrix_value ());
170 
171  return retval;
172 }
173 
174 Complex
176 {
177  double tmp = lo_ieee_nan_value ();
178 
179  Complex retval (tmp, tmp);
180 
181  if (rows () > 0 && columns () > 0)
182  {
183  gripe_implicit_conversion ("Octave:array-to-scalar",
184  "complex matrix", "complex scalar");
185 
186  retval = matrix (0, 0);
187  }
188  else
189  gripe_invalid_conversion ("complex matrix", "complex scalar");
190 
191  return retval;
192 }
193 
196 {
197  float tmp = lo_ieee_float_nan_value ();
198 
199  FloatComplex retval (tmp, tmp);
200 
201  if (rows () > 0 && columns () > 0)
202  {
203  gripe_implicit_conversion ("Octave:array-to-scalar",
204  "complex matrix", "complex scalar");
205 
206  retval = matrix (0, 0);
207  }
208  else
209  gripe_invalid_conversion ("complex matrix", "complex scalar");
210 
211  return retval;
212 }
213 
216 {
217  return matrix.matrix_value ();
218 }
219 
222 {
224 }
225 
228 {
229  if (matrix.any_element_is_nan ())
231  else if (warn && (! matrix.all_elements_are_real ()
232  || real (matrix).any_element_not_one_or_zero ()))
234 
235  return mx_el_ne (matrix, Complex (0.0));
236 }
237 
240 {
241  charNDArray retval;
242 
243  if (! frc_str_conv)
244  gripe_implicit_conversion ("Octave:num-to-str",
245  "complex matrix", "string");
246  else
247  {
248  retval = charNDArray (dims ());
249  octave_idx_type nel = numel ();
250 
251  for (octave_idx_type i = 0; i < nel; i++)
252  retval.elem (i) = static_cast<char>(std::real (matrix.elem (i)));
253  }
254 
255  return retval;
256 }
257 
260 {
261  return FloatComplexNDArray (matrix);
262 }
263 
265 octave_complex_matrix::sparse_matrix_value (bool force_conversion) const
266 {
267  SparseMatrix retval;
268 
269  if (! force_conversion)
270  gripe_implicit_conversion ("Octave:imag-to-real",
271  "complex matrix", "real matrix");
272 
273  retval = SparseMatrix (::real (matrix.matrix_value ()));
274 
275  return retval;
276 }
277 
280 {
282 }
283 
286 {
287  octave_value retval;
288  if (k == 0 && matrix.ndims () == 2
289  && (matrix.rows () == 1 || matrix.columns () == 1))
291  else
293 
294  return retval;
295 }
296 
299 {
300  octave_value retval;
301 
302  if (matrix.ndims () == 2
303  && (matrix.rows () == 1 || matrix.columns () == 1))
304  {
306 
307  retval = mat.diag (m, n);
308  }
309  else
310  error ("diag: expecting vector argument");
311 
312  return retval;
313 }
314 
315 bool
317 {
318  dim_vector d = dims ();
319  if (d.length () > 2)
320  {
322 
323  os << "# ndims: " << d.length () << "\n";
324 
325  for (int i = 0; i < d.length (); i++)
326  os << " " << d (i);
327 
328  os << "\n" << tmp;
329  }
330  else
331  {
332  // Keep this case, rather than use generic code above for backward
333  // compatiability. Makes load_ascii much more complex!!
334  os << "# rows: " << rows () << "\n"
335  << "# columns: " << columns () << "\n";
336 
337  os << complex_matrix_value ();
338  }
339 
340  return true;
341 }
342 
343 bool
345 {
346  bool success = true;
347 
349 
350  keywords[0] = "ndims";
351  keywords[1] = "rows";
352 
353  std::string kw;
354  octave_idx_type val = 0;
355 
356  if (extract_keyword (is, keywords, kw, val, true))
357  {
358  if (kw == "ndims")
359  {
360  int mdims = static_cast<int> (val);
361 
362  if (mdims >= 0)
363  {
364  dim_vector dv;
365  dv.resize (mdims);
366 
367  for (int i = 0; i < mdims; i++)
368  is >> dv(i);
369 
370  if (is)
371  {
372  ComplexNDArray tmp(dv);
373 
374  is >> tmp;
375 
376  if (is)
377  matrix = tmp;
378  else
379  {
380  error ("load: failed to load matrix constant");
381  success = false;
382  }
383  }
384  else
385  {
386  error ("load: failed to read dimensions");
387  success = false;
388  }
389  }
390  else
391  {
392  error ("load: failed to extract number of dimensions");
393  success = false;
394  }
395  }
396  else if (kw == "rows")
397  {
398  octave_idx_type nr = val;
399  octave_idx_type nc = 0;
400 
401  if (nr >= 0 && extract_keyword (is, "columns", nc) && nc >= 0)
402  {
403  if (nr > 0 && nc > 0)
404  {
405  ComplexMatrix tmp (nr, nc);
406  is >> tmp;
407  if (is)
408  matrix = tmp;
409  else
410  {
411  error ("load: failed to load matrix constant");
412  success = false;
413  }
414  }
415  else if (nr == 0 || nc == 0)
416  matrix = ComplexMatrix (nr, nc);
417  else
418  panic_impossible ();
419  }
420  else
421  {
422  error ("load: failed to extract number of rows and columns");
423  success = false;
424  }
425  }
426  else
427  panic_impossible ();
428  }
429  else
430  {
431  error ("load: failed to extract number of rows and columns");
432  success = false;
433  }
434 
435  return success;
436 }
437 
438 bool
439 octave_complex_matrix::save_binary (std::ostream& os, bool& save_as_floats)
440 {
441  dim_vector d = dims ();
442  if (d.length () < 1)
443  return false;
444 
445  // Use negative value for ndims to differentiate with old format!!
446  int32_t tmp = - d.length ();
447  os.write (reinterpret_cast<char *> (&tmp), 4);
448  for (int i = 0; i < d.length (); i++)
449  {
450  tmp = d(i);
451  os.write (reinterpret_cast<char *> (&tmp), 4);
452  }
453 
455  save_type st = LS_DOUBLE;
456  if (save_as_floats)
457  {
458  if (m.too_large_for_float ())
459  {
460  warning ("save: some values too large to save as floats --");
461  warning ("save: saving as doubles instead");
462  }
463  else
464  st = LS_FLOAT;
465  }
466  else if (d.numel () > 4096) // FIXME: make this configurable.
467  {
468  double max_val, min_val;
469  if (m.all_integers (max_val, min_val))
470  st = get_save_type (max_val, min_val);
471  }
472 
473 
474  const Complex *mtmp = m.data ();
475  write_doubles (os, reinterpret_cast<const double *> (mtmp), st,
476  2 * d.numel ());
477 
478  return true;
479 }
480 
481 bool
482 octave_complex_matrix::load_binary (std::istream& is, bool swap,
484 {
485  char tmp;
486  int32_t mdims;
487  if (! is.read (reinterpret_cast<char *> (&mdims), 4))
488  return false;
489  if (swap)
490  swap_bytes<4> (&mdims);
491  if (mdims < 0)
492  {
493  mdims = - mdims;
494  int32_t di;
495  dim_vector dv;
496  dv.resize (mdims);
497 
498  for (int i = 0; i < mdims; i++)
499  {
500  if (! is.read (reinterpret_cast<char *> (&di), 4))
501  return false;
502  if (swap)
503  swap_bytes<4> (&di);
504  dv(i) = di;
505  }
506 
507  // Convert an array with a single dimension to be a row vector.
508  // Octave should never write files like this, other software
509  // might.
510 
511  if (mdims == 1)
512  {
513  mdims = 2;
514  dv.resize (mdims);
515  dv(1) = dv(0);
516  dv(0) = 1;
517  }
518 
519  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
520  return false;
521 
522  ComplexNDArray m(dv);
523  Complex *im = m.fortran_vec ();
524  read_doubles (is, reinterpret_cast<double *> (im),
525  static_cast<save_type> (tmp), 2 * dv.numel (), swap, fmt);
526  if (error_state || ! is)
527  return false;
528  matrix = m;
529  }
530  else
531  {
532  int32_t nr, nc;
533  nr = mdims;
534  if (! is.read (reinterpret_cast<char *> (&nc), 4))
535  return false;
536  if (swap)
537  swap_bytes<4> (&nc);
538  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
539  return false;
540  ComplexMatrix m (nr, nc);
541  Complex *im = m.fortran_vec ();
542  octave_idx_type len = nr * nc;
543  read_doubles (is, reinterpret_cast<double *> (im),
544  static_cast<save_type> (tmp), 2*len, swap, fmt);
545  if (error_state || ! is)
546  return false;
547  matrix = m;
548  }
549  return true;
550 }
551 
552 #if defined (HAVE_HDF5)
553 
554 bool
555 octave_complex_matrix::save_hdf5 (hid_t loc_id, const char *name,
556  bool save_as_floats)
557 {
558  dim_vector dv = dims ();
559  int empty = save_hdf5_empty (loc_id, name, dv);
560  if (empty)
561  return (empty > 0);
562 
563  int rank = dv.length ();
564  hid_t space_hid = -1, data_hid = -1, type_hid = -1;
565  bool retval = true;
567 
568  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
569 
570  // Octave uses column-major, while HDF5 uses row-major ordering
571  for (int i = 0; i < rank; i++)
572  hdims[i] = dv (rank-i-1);
573 
574  space_hid = H5Screate_simple (rank, hdims, 0);
575  if (space_hid < 0) return false;
576 
577  hid_t save_type_hid = H5T_NATIVE_DOUBLE;
578 
579  if (save_as_floats)
580  {
581  if (m.too_large_for_float ())
582  {
583  warning ("save: some values too large to save as floats --");
584  warning ("save: saving as doubles instead");
585  }
586  else
587  save_type_hid = H5T_NATIVE_FLOAT;
588  }
589 #if HAVE_HDF5_INT2FLOAT_CONVERSIONS
590  // hdf5 currently doesn't support float/integer conversions
591  else
592  {
593  double max_val, min_val;
594 
595  if (m.all_integers (max_val, min_val))
596  save_type_hid
597  = save_type_to_hdf5 (get_save_type (max_val, min_val));
598  }
599 #endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */
600 
601  type_hid = hdf5_make_complex_type (save_type_hid);
602  if (type_hid < 0)
603  {
604  H5Sclose (space_hid);
605  return false;
606  }
607 #if HAVE_HDF5_18
608  data_hid = H5Dcreate (loc_id, name, type_hid, space_hid,
609  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
610 #else
611  data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, H5P_DEFAULT);
612 #endif
613  if (data_hid < 0)
614  {
615  H5Sclose (space_hid);
616  H5Tclose (type_hid);
617  return false;
618  }
619 
620  hid_t complex_type_hid = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
621  if (complex_type_hid < 0) retval = false;
622 
623  if (retval)
624  {
625  Complex *mtmp = m.fortran_vec ();
626  if (H5Dwrite (data_hid, complex_type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT,
627  mtmp) < 0)
628  {
629  H5Tclose (complex_type_hid);
630  retval = false;
631  }
632  }
633 
634  H5Tclose (complex_type_hid);
635  H5Dclose (data_hid);
636  H5Tclose (type_hid);
637  H5Sclose (space_hid);
638 
639  return retval;
640 }
641 
642 bool
643 octave_complex_matrix::load_hdf5 (hid_t loc_id, const char *name)
644 {
645  bool retval = false;
646 
647  dim_vector dv;
648  int empty = load_hdf5_empty (loc_id, name, dv);
649  if (empty > 0)
650  matrix.resize (dv);
651  if (empty)
652  return (empty > 0);
653 
654 #if HAVE_HDF5_18
655  hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
656 #else
657  hid_t data_hid = H5Dopen (loc_id, name);
658 #endif
659  hid_t type_hid = H5Dget_type (data_hid);
660 
661  hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
662 
663  if (! hdf5_types_compatible (type_hid, complex_type))
664  {
665  H5Tclose (complex_type);
666  H5Dclose (data_hid);
667  return false;
668  }
669 
670  hid_t space_id = H5Dget_space (data_hid);
671 
672  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
673 
674  if (rank < 1)
675  {
676  H5Tclose (complex_type);
677  H5Sclose (space_id);
678  H5Dclose (data_hid);
679  return false;
680  }
681 
682  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
683  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
684 
685  H5Sget_simple_extent_dims (space_id, hdims, maxdims);
686 
687  // Octave uses column-major, while HDF5 uses row-major ordering
688  if (rank == 1)
689  {
690  dv.resize (2);
691  dv(0) = 1;
692  dv(1) = hdims[0];
693  }
694  else
695  {
696  dv.resize (rank);
697  for (hsize_t i = 0, j = rank - 1; i < rank; i++, j--)
698  dv(j) = hdims[i];
699  }
700 
701  ComplexNDArray m (dv);
702  Complex *reim = m.fortran_vec ();
703  if (H5Dread (data_hid, complex_type, H5S_ALL, H5S_ALL, H5P_DEFAULT,
704  reim) >= 0)
705  {
706  retval = true;
707  matrix = m;
708  }
709 
710  H5Tclose (complex_type);
711  H5Sclose (space_id);
712  H5Dclose (data_hid);
713 
714  return retval;
715 }
716 
717 #endif
718 
719 void
721  bool pr_as_read_syntax) const
722 {
723  octave_print_internal (os, matrix, pr_as_read_syntax,
725 }
726 
727 mxArray *
729 {
730  mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxCOMPLEX);
731 
732  double *pr = static_cast<double *> (retval->get_data ());
733  double *pi = static_cast<double *> (retval->get_imag_data ());
734 
735  mwSize nel = numel ();
736 
737  const Complex *p = matrix.data ();
738 
739  for (mwIndex i = 0; i < nel; i++)
740  {
741  pr[i] = std::real (p[i]);
742  pi[i] = std::imag (p[i]);
743  }
744 
745  return retval;
746 }
747 
750 {
751  switch (umap)
752  {
753  // Mappers handled specially.
754  case umap_real:
756  case umap_imag:
758  case umap_conj:
760 
761 #define ARRAY_METHOD_MAPPER(UMAP, FCN) \
762  case umap_ ## UMAP: \
763  return octave_value (matrix.FCN ())
764 
766  ARRAY_METHOD_MAPPER (isnan, isnan);
767  ARRAY_METHOD_MAPPER (isinf, isinf);
768  ARRAY_METHOD_MAPPER (finite, isfinite);
769 
770 #define ARRAY_MAPPER(UMAP, TYPE, FCN) \
771  case umap_ ## UMAP: \
772  return octave_value (matrix.map<TYPE> (FCN))
773 
776  ARRAY_MAPPER (angle, double, std::arg);
777  ARRAY_MAPPER (arg, double, std::arg);
782  ARRAY_MAPPER (erf, Complex, ::erf);
788  ARRAY_MAPPER (cos, Complex, std::cos);
789  ARRAY_MAPPER (cosh, Complex, std::cosh);
790  ARRAY_MAPPER (exp, Complex, std::exp);
792  ARRAY_MAPPER (fix, Complex, ::fix);
794  ARRAY_MAPPER (log, Complex, std::log);
795  ARRAY_MAPPER (log2, Complex, xlog2);
796  ARRAY_MAPPER (log10, Complex, std::log10);
798  ARRAY_MAPPER (round, Complex, xround);
799  ARRAY_MAPPER (roundb, Complex, xroundb);
801  ARRAY_MAPPER (sin, Complex, std::sin);
802  ARRAY_MAPPER (sinh, Complex, std::sinh);
803  ARRAY_MAPPER (sqrt, Complex, std::sqrt);
804  ARRAY_MAPPER (tan, Complex, std::tan);
805  ARRAY_MAPPER (tanh, Complex, std::tanh);
806  ARRAY_MAPPER (isna, bool, octave_is_NA);
807 
808  default:
809  return octave_base_value::map (umap);
810  }
811 }