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-re-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 <limits>
30 #include <vector>
31 
32 #include "data-conv.h"
33 #include "lo-ieee.h"
34 #include "lo-utils.h"
35 #include "lo-specfun.h"
36 #include "lo-mappers.h"
37 #include "mach-info.h"
38 #include "mx-base.h"
39 #include "quit.h"
40 #include "oct-locbuf.h"
41 
42 #include "defun.h"
43 #include "gripes.h"
44 #include "mxarray.h"
45 #include "oct-obj.h"
46 #include "oct-lvalue.h"
47 #include "oct-stream.h"
48 #include "ops.h"
49 #include "ov-base.h"
50 #include "ov-base-mat.h"
51 #include "ov-base-mat.cc"
52 #include "ov-scalar.h"
53 #include "ov-float.h"
54 #include "ov-flt-complex.h"
55 #include "ov-re-mat.h"
56 #include "ov-flt-re-mat.h"
57 #include "ov-flt-cx-mat.h"
58 #include "ov-re-sparse.h"
59 #include "ov-flt-re-diag.h"
60 #include "ov-flt-cx-diag.h"
61 #include "ov-type-conv.h"
62 #include "pr-output.h"
63 #include "variables.h"
64 #include "ops.h"
65 
66 #include "byte-swap.h"
67 #include "ls-oct-ascii.h"
68 #include "ls-utils.h"
69 #include "ls-hdf5.h"
70 
72 
74 
76  "single");
77 
80 {
81  octave_base_value *retval = 0;
82 
83  if (matrix.nelem () == 1)
84  retval = new octave_float_scalar (matrix (0));
85 
86  return retval;
87 }
88 
89 double
91 {
92  double retval = lo_ieee_nan_value ();
93 
94  if (numel () > 0)
95  {
96  gripe_implicit_conversion ("Octave:array-to-scalar",
97  "real matrix", "real scalar");
98 
99  retval = matrix (0, 0);
100  }
101  else
102  gripe_invalid_conversion ("real matrix", "real scalar");
103 
104  return retval;
105 }
106 
107 float
109 {
110  float retval = lo_ieee_float_nan_value ();
111 
112  if (numel () > 0)
113  {
114  gripe_implicit_conversion ("Octave:array-to-scalar",
115  "real matrix", "real scalar");
116 
117  retval = matrix (0, 0);
118  }
119  else
120  gripe_invalid_conversion ("real matrix", "real scalar");
121 
122  return retval;
123 }
124 
125 // FIXME
126 
127 Matrix
129 {
130  return Matrix (matrix.matrix_value ());
131 }
132 
135 {
136  return matrix.matrix_value ();
137 }
138 
139 Complex
141 {
142  double tmp = lo_ieee_nan_value ();
143 
144  Complex retval (tmp, tmp);
145 
146  if (rows () > 0 && columns () > 0)
147  {
148  gripe_implicit_conversion ("Octave:array-to-scalar",
149  "real matrix", "complex scalar");
150 
151  retval = matrix (0, 0);
152  }
153  else
154  gripe_invalid_conversion ("real matrix", "complex scalar");
155 
156  return retval;
157 }
158 
161 {
162  double tmp = lo_ieee_float_nan_value ();
163 
164  FloatComplex retval (tmp, tmp);
165 
166  if (rows () > 0 && columns () > 0)
167  {
168  gripe_implicit_conversion ("Octave:array-to-scalar",
169  "real matrix", "complex scalar");
170 
171  retval = matrix (0, 0);
172  }
173  else
174  gripe_invalid_conversion ("real matrix", "complex scalar");
175 
176  return retval;
177 }
178 
179 // FIXME
180 
183 {
184  return ComplexMatrix (matrix.matrix_value ());
185 }
186 
189 {
191 }
192 
195 {
196  return ComplexNDArray (matrix);
197 }
198 
201 {
202  return FloatComplexNDArray (matrix);
203 }
204 
205 NDArray
207 {
208  return NDArray (matrix);
209 }
210 
213 {
214  if (matrix.any_element_is_nan ())
216  else if (warn && matrix.any_element_not_one_or_zero ())
218 
219  return boolNDArray (matrix);
220 }
221 
224 {
225  charNDArray retval (dims ());
226 
227  octave_idx_type nel = numel ();
228 
229  for (octave_idx_type i = 0; i < nel; i++)
230  retval.elem (i) = static_cast<char>(matrix.elem (i));
231 
232  return retval;
233 }
234 
237 {
238  return SparseMatrix (matrix_value ());
239 }
240 
243 {
244  // FIXME: Need a SparseComplexMatrix (Matrix) constructor to make
245  // this function more efficient. Then this should become
246  // return SparseComplexMatrix (matrix.matrix_value ());
248 }
249 
252 {
253  octave_value retval;
254  if (k == 0 && matrix.ndims () == 2
255  && (matrix.rows () == 1 || matrix.columns () == 1))
257  else
259 
260  return retval;
261 }
262 
265 {
266  octave_value retval;
267 
268  if (matrix.ndims () == 2
269  && (matrix.rows () == 1 || matrix.columns () == 1))
270  {
272 
273  retval = mat.diag (m, n);
274  }
275  else
276  error ("diag: expecting vector argument");
277 
278  return retval;
279 }
280 
283 {
284  octave_value retval;
285  dim_vector dv = dims ();
286  octave_idx_type nel = dv.numel ();
287 
288  charNDArray chm (dv);
289 
290  bool warned = false;
291 
292  for (octave_idx_type i = 0; i < nel; i++)
293  {
294  octave_quit ();
295 
296  float d = matrix (i);
297 
298  if (xisnan (d))
299  {
301  return retval;
302  }
303  else
304  {
305  int ival = NINT (d);
306 
307  if (ival < 0 || ival > std::numeric_limits<unsigned char>::max ())
308  {
309  // FIXME: is there something better we could do?
310 
311  ival = 0;
312 
313  if (! warned)
314  {
315  ::warning ("range error for conversion to character value");
316  warned = true;
317  }
318  }
319 
320  chm (i) = static_cast<char> (ival);
321  }
322  }
323 
324  retval = octave_value (chm, type);
325 
326  return retval;
327 }
328 
329 bool
331 {
332  dim_vector d = dims ();
333 
334  if (d.length () > 2)
335  {
337 
338  os << "# ndims: " << d.length () << "\n";
339 
340  for (int i=0; i < d.length (); i++)
341  os << " " << d (i);
342 
343  os << "\n" << tmp;
344  }
345  else
346  {
347  // Keep this case, rather than use generic code above for backward
348  // compatiability. Makes load_ascii much more complex!!
349  os << "# rows: " << rows () << "\n"
350  << "# columns: " << columns () << "\n";
351 
352  os << float_matrix_value ();
353  }
354 
355  return true;
356 }
357 
358 bool
360 {
361  bool success = true;
362 
364 
365  keywords[0] = "ndims";
366  keywords[1] = "rows";
367 
368  std::string kw;
369  octave_idx_type val = 0;
370 
371  if (extract_keyword (is, keywords, kw, val, true))
372  {
373  if (kw == "ndims")
374  {
375  int mdims = static_cast<int> (val);
376 
377  if (mdims >= 0)
378  {
379  dim_vector dv;
380  dv.resize (mdims);
381 
382  for (int i = 0; i < mdims; i++)
383  is >> dv(i);
384 
385  if (is)
386  {
387  FloatNDArray tmp(dv);
388 
389  is >> tmp;
390 
391  if (is)
392  matrix = tmp;
393  else
394  {
395  error ("load: failed to load matrix constant");
396  success = false;
397  }
398  }
399  else
400  {
401  error ("load: failed to read dimensions");
402  success = false;
403  }
404  }
405  else
406  {
407  error ("load: failed to extract number of dimensions");
408  success = false;
409  }
410  }
411  else if (kw == "rows")
412  {
413  octave_idx_type nr = val;
414  octave_idx_type nc = 0;
415 
416  if (nr >= 0 && extract_keyword (is, "columns", nc) && nc >= 0)
417  {
418  if (nr > 0 && nc > 0)
419  {
420  FloatMatrix tmp (nr, nc);
421  is >> tmp;
422  if (is)
423  matrix = tmp;
424  else
425  {
426  error ("load: failed to load matrix constant");
427  success = false;
428  }
429  }
430  else if (nr == 0 || nc == 0)
431  matrix = FloatMatrix (nr, nc);
432  else
433  panic_impossible ();
434  }
435  else
436  {
437  error ("load: failed to extract number of rows and columns");
438  success = false;
439  }
440  }
441  else
442  panic_impossible ();
443  }
444  else
445  {
446  error ("load: failed to extract number of rows and columns");
447  success = false;
448  }
449 
450  return success;
451 }
452 
453 bool
454 octave_float_matrix::save_binary (std::ostream& os, bool&)
455 {
456 
457  dim_vector d = dims ();
458  if (d.length () < 1)
459  return false;
460 
461  // Use negative value for ndims to differentiate with old format!!
462  int32_t tmp = - d.length ();
463  os.write (reinterpret_cast<char *> (&tmp), 4);
464  for (int i = 0; i < d.length (); i++)
465  {
466  tmp = d(i);
467  os.write (reinterpret_cast<char *> (&tmp), 4);
468  }
469 
471  save_type st = LS_FLOAT;
472  if (d.numel () > 8192) // FIXME: make this configurable.
473  {
474  float max_val, min_val;
475  if (m.all_integers (max_val, min_val))
476  st = get_save_type (max_val, min_val);
477  }
478 
479  const float *mtmp = m.data ();
480  write_floats (os, mtmp, st, d.numel ());
481 
482  return true;
483 }
484 
485 bool
486 octave_float_matrix::load_binary (std::istream& is, bool swap,
488 {
489  char tmp;
490  int32_t mdims;
491  if (! is.read (reinterpret_cast<char *> (&mdims), 4))
492  return false;
493  if (swap)
494  swap_bytes<4> (&mdims);
495  if (mdims < 0)
496  {
497  mdims = - mdims;
498  int32_t di;
499  dim_vector dv;
500  dv.resize (mdims);
501 
502  for (int i = 0; i < mdims; i++)
503  {
504  if (! is.read (reinterpret_cast<char *> (&di), 4))
505  return false;
506  if (swap)
507  swap_bytes<4> (&di);
508  dv(i) = di;
509  }
510 
511  // Convert an array with a single dimension to be a row vector.
512  // Octave should never write files like this, other software
513  // might.
514 
515  if (mdims == 1)
516  {
517  mdims = 2;
518  dv.resize (mdims);
519  dv(1) = dv(0);
520  dv(0) = 1;
521  }
522 
523  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
524  return false;
525 
526  FloatNDArray m(dv);
527  float *re = m.fortran_vec ();
528  read_floats (is, re, static_cast<save_type> (tmp), dv.numel (),
529  swap, fmt);
530  if (error_state || ! is)
531  return false;
532  matrix = m;
533  }
534  else
535  {
536  int32_t nr, nc;
537  nr = mdims;
538  if (! is.read (reinterpret_cast<char *> (&nc), 4))
539  return false;
540  if (swap)
541  swap_bytes<4> (&nc);
542  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
543  return false;
544  FloatMatrix m (nr, nc);
545  float *re = m.fortran_vec ();
546  octave_idx_type len = nr * nc;
547  read_floats (is, re, static_cast<save_type> (tmp), len, swap, fmt);
548  if (error_state || ! is)
549  return false;
550  matrix = m;
551  }
552  return true;
553 }
554 
555 #if defined (HAVE_HDF5)
556 
557 bool
558 octave_float_matrix::save_hdf5 (hid_t loc_id, const char *name, bool)
559 {
560  dim_vector dv = dims ();
561  int empty = save_hdf5_empty (loc_id, name, dv);
562  if (empty)
563  return (empty > 0);
564 
565  int rank = dv.length ();
566  hid_t space_hid = -1, data_hid = -1;
567  bool retval = true;
568  FloatNDArray m = array_value ();
569 
570  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
571 
572  // Octave uses column-major, while HDF5 uses row-major ordering
573  for (int i = 0; i < rank; i++)
574  hdims[i] = dv (rank-i-1);
575 
576  space_hid = H5Screate_simple (rank, hdims, 0);
577 
578  if (space_hid < 0) return false;
579 
580  hid_t save_type_hid = H5T_NATIVE_FLOAT;
581 
582 #if HAVE_HDF5_INT2FLOAT_CONVERSIONS
583  // hdf5 currently doesn't support float/integer conversions
584  else
585  {
586  float max_val, min_val;
587 
588  if (m.all_integers (max_val, min_val))
589  save_type_hid
590  = save_type_to_hdf5 (get_save_type (max_val, min_val));
591  }
592 #endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */
593 #if HAVE_HDF5_18
594  data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
595  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
596 #else
597  data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
598  H5P_DEFAULT);
599 #endif
600  if (data_hid < 0)
601  {
602  H5Sclose (space_hid);
603  return false;
604  }
605 
606  float *mtmp = m.fortran_vec ();
607  retval = H5Dwrite (data_hid, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL,
608  H5P_DEFAULT, mtmp) >= 0;
609 
610  H5Dclose (data_hid);
611  H5Sclose (space_hid);
612 
613  return retval;
614 }
615 
616 bool
617 octave_float_matrix::load_hdf5 (hid_t loc_id, const char *name)
618 {
619  bool retval = false;
620 
621  dim_vector dv;
622  int empty = load_hdf5_empty (loc_id, name, dv);
623  if (empty > 0)
624  matrix.resize (dv);
625  if (empty)
626  return (empty > 0);
627 
628 #if HAVE_HDF5_18
629  hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
630 #else
631  hid_t data_hid = H5Dopen (loc_id, name);
632 #endif
633  hid_t space_id = H5Dget_space (data_hid);
634 
635  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
636 
637  if (rank < 1)
638  {
639  H5Sclose (space_id);
640  H5Dclose (data_hid);
641  return false;
642  }
643 
644  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
645  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
646 
647  H5Sget_simple_extent_dims (space_id, hdims, maxdims);
648 
649  // Octave uses column-major, while HDF5 uses row-major ordering
650  if (rank == 1)
651  {
652  dv.resize (2);
653  dv(0) = 1;
654  dv(1) = hdims[0];
655  }
656  else
657  {
658  dv.resize (rank);
659  for (hsize_t i = 0, j = rank - 1; i < rank; i++, j--)
660  dv(j) = hdims[i];
661  }
662 
663  FloatNDArray m (dv);
664  float *re = m.fortran_vec ();
665  if (H5Dread (data_hid, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL,
666  H5P_DEFAULT, re) >= 0)
667  {
668  retval = true;
669  matrix = m;
670  }
671 
672  H5Sclose (space_id);
673  H5Dclose (data_hid);
674 
675  return retval;
676 }
677 
678 #endif
679 
680 void
682  bool pr_as_read_syntax) const
683 {
684  octave_print_internal (os, matrix, pr_as_read_syntax,
686 }
687 
688 mxArray *
690 {
691  mxArray *retval = new mxArray (mxSINGLE_CLASS, dims (), mxREAL);
692 
693  float *pr = static_cast<float *> (retval->get_data ());
694 
695  mwSize nel = numel ();
696 
697  const float *p = matrix.data ();
698 
699  for (mwIndex i = 0; i < nel; i++)
700  pr[i] = p[i];
701 
702  return retval;
703 }
704 
705 // This uses a smarter strategy for doing the complex->real mappers. We
706 // allocate an array for a real result and keep filling it until a complex
707 // result is produced.
708 static octave_value
709 do_rc_map (const FloatNDArray& a, FloatComplex (&fcn) (float))
710 {
711  octave_idx_type n = a.numel ();
712  NoAlias<FloatNDArray> rr (a.dims ());
713 
714  for (octave_idx_type i = 0; i < n; i++)
715  {
716  octave_quit ();
717 
718  FloatComplex tmp = fcn (a(i));
719  if (tmp.imag () == 0.0)
720  rr(i) = tmp.real ();
721  else
722  {
724 
725  for (octave_idx_type j = 0; j < i; j++)
726  rc(j) = rr(j);
727 
728  rc(i) = tmp;
729 
730  for (octave_idx_type j = i+1; j < n; j++)
731  {
732  octave_quit ();
733 
734  rc(j) = fcn (a(j));
735  }
736 
737  return new octave_float_complex_matrix (rc);
738  }
739  }
740 
741  return rr;
742 }
743 
746 {
747  switch (umap)
748  {
749  case umap_imag:
750  return FloatNDArray (matrix.dims (), 0.0);
751 
752  case umap_real:
753  case umap_conj:
754  return matrix;
755 
756  // Mappers handled specially.
757 #define ARRAY_METHOD_MAPPER(UMAP, FCN) \
758  case umap_ ## UMAP: \
759  return octave_value (matrix.FCN ())
760 
762  ARRAY_METHOD_MAPPER (isnan, isnan);
763  ARRAY_METHOD_MAPPER (isinf, isinf);
764  ARRAY_METHOD_MAPPER (finite, isfinite);
765 
766 #define ARRAY_MAPPER(UMAP, TYPE, FCN) \
767  case umap_ ## UMAP: \
768  return octave_value (matrix.map<TYPE> (FCN))
769 
770 #define RC_ARRAY_MAPPER(UMAP, TYPE, FCN) \
771  case umap_ ## UMAP: \
772  return do_rc_map (matrix, FCN)
773 
776  ARRAY_MAPPER (angle, float, ::arg);
777  ARRAY_MAPPER (arg, float, ::arg);
779  ARRAY_MAPPER (asinh, float, ::asinhf);
780  ARRAY_MAPPER (atan, float, ::atanf);
782  ARRAY_MAPPER (erf, float, ::erff);
783  ARRAY_MAPPER (erfinv, float, ::erfinv);
784  ARRAY_MAPPER (erfcinv, float, ::erfcinv);
785  ARRAY_MAPPER (erfc, float, ::erfcf);
786  ARRAY_MAPPER (erfcx, float, ::erfcx);
787  ARRAY_MAPPER (erfi, float, ::erfi);
788  ARRAY_MAPPER (dawson, float, ::dawson);
789  ARRAY_MAPPER (gamma, float, xgamma);
791  ARRAY_MAPPER (cbrt, float, ::cbrtf);
792  ARRAY_MAPPER (ceil, float, ::ceilf);
793  ARRAY_MAPPER (cos, float, ::cosf);
794  ARRAY_MAPPER (cosh, float, ::coshf);
795  ARRAY_MAPPER (exp, float, ::expf);
796  ARRAY_MAPPER (expm1, float, ::expm1f);
797  ARRAY_MAPPER (fix, float, ::fix);
798  ARRAY_MAPPER (floor, float, ::floorf);
803  ARRAY_MAPPER (round, float, xround);
804  ARRAY_MAPPER (roundb, float, xroundb);
805  ARRAY_MAPPER (signum, float, ::signum);
806  ARRAY_MAPPER (sin, float, ::sinf);
807  ARRAY_MAPPER (sinh, float, ::sinhf);
809  ARRAY_MAPPER (tan, float, ::tanf);
810  ARRAY_MAPPER (tanh, float, ::tanhf);
811  ARRAY_MAPPER (isna, bool, octave_is_NA);
812  ARRAY_MAPPER (xsignbit, float, xsignbit);
813 
814  default:
815  return octave_base_value::map (umap);
816  }
817 }
818 
819 DEFUN (single, args, ,
820  "-*- texinfo -*-\n\
821 @deftypefn {Built-in Function} {} single (@var{x})\n\
822 Convert @var{x} to single precision type.\n\
823 @seealso{double}\n\
824 @end deftypefn")
825 {
826  // The OCTAVE_TYPE_CONV_BODY3 macro declares retval, so they go
827  // inside their own scopes, and we don't declare retval here to
828  // avoid a shadowed declaration warning.
829 
830  if (args.length () == 1)
831  {
832  if (args(0).is_diag_matrix ())
833  {
834  if (args(0).is_complex_type ())
835  {
838  }
839  else
840  {
843  }
844  }
845  else if (args(0).is_sparse_type ())
846  {
847  error ("single: sparse type does not support single precision");
848  }
849  else if (args(0).is_complex_type ())
850  {
853  }
854  else
855  {
858  }
859  }
860  else
861  print_usage ();
862 
863  return octave_value ();
864 }
865 
866 /*
867 %!assert (class (single (1)), "single")
868 %!assert (class (single (1 + i)), "single")
869 %!assert (class (single (int8 (1))), "single")
870 %!assert (class (single (uint8 (1))), "single")
871 %!assert (class (single (int16 (1))), "single")
872 %!assert (class (single (uint16 (1))), "single")
873 %!assert (class (single (int32 (1))), "single")
874 %!assert (class (single (uint32 (1))), "single")
875 %!assert (class (single (int64 (1))), "single")
876 %!assert (class (single (uint64 (1))), "single")
877 %!assert (class (single (true)), "single")
878 %!assert (class (single ("A")), "single")
879 %!error (single (sparse (1)))
880 %!test
881 %! x = diag ([1 3 2]);
882 %! y = single (x);
883 %! assert (class (x), "double");
884 %! assert (class (y), "single");
885 %!test
886 %! x = diag ([i 3 2]);
887 %! y = single (x);
888 %! assert (class (x), "double");
889 %! assert (class (y), "single");
890 */