1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29
30 #include <istream>
31 #include <ostream>
32 #include <vector>
33
34 #include "dNDArray.h"
35 #include "fNDArray.h"
36
37 #include "data-conv.h"
38 #include "lo-ieee.h"
39 #include "lo-specfun.h"
40 #include "lo-mappers.h"
41 #include "mx-base.h"
42 #include "mach-info.h"
43 #include "oct-locbuf.h"
44
45 #include "errwarn.h"
46 #include "mxarray.h"
47 #include "ovl.h"
48 #include "oct-hdf5.h"
49 #include "oct-stream.h"
50 #include "ops.h"
51 #include "ov-base.h"
52 #include "ov-base-mat.h"
53 #include "ov-base-mat.cc"
54 #include "ov-complex.h"
55 #include "ov-cx-mat.h"
56 #include "ov-flt-cx-mat.h"
57 #include "ov-re-mat.h"
58 #include "ov-scalar.h"
59 #include "pr-output.h"
60
61 #include "byte-swap.h"
62 #include "ls-oct-text.h"
63 #include "ls-hdf5.h"
64 #include "ls-utils.h"
65
66
67 template class octave_base_matrix<ComplexNDArray>;
68
69 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_complex_matrix,
70 "complex matrix", "double");
71
72 static octave_base_value *
default_numeric_demotion_function(const octave_base_value & a)73 default_numeric_demotion_function (const octave_base_value& a)
74 {
75 const octave_complex_matrix& v = dynamic_cast<const octave_complex_matrix&> (a);
76
77 return new octave_float_complex_matrix (v.float_complex_array_value ());
78 }
79
80 octave_base_value::type_conv_info
numeric_demotion_function(void) const81 octave_complex_matrix::numeric_demotion_function (void) const
82 {
83 return octave_base_value::type_conv_info
84 (default_numeric_demotion_function,
85 octave_float_complex_matrix::static_type_id ());
86 }
87
88 octave_base_value *
try_narrowing_conversion(void)89 octave_complex_matrix::try_narrowing_conversion (void)
90 {
91 octave_base_value *retval = nullptr;
92
93 if (matrix.numel () == 1)
94 {
95 Complex c = matrix (0);
96
97 if (c.imag () == 0.0)
98 retval = new octave_scalar (c.real ());
99 else
100 retval = new octave_complex (c);
101 }
102 else if (matrix.all_elements_are_real ())
103 retval = new octave_matrix (::real (matrix));
104
105 return retval;
106 }
107
108 double
double_value(bool force_conversion) const109 octave_complex_matrix::double_value (bool force_conversion) const
110 {
111 if (! force_conversion)
112 warn_implicit_conversion ("Octave:imag-to-real",
113 "complex matrix", "real scalar");
114
115 if (rows () == 0 || columns () == 0)
116 err_invalid_conversion ("complex matrix", "real scalar");
117
118 warn_implicit_conversion ("Octave:array-to-scalar",
119 "complex matrix", "real scalar");
120
121 return std::real (matrix(0, 0));
122 }
123
124 float
float_value(bool force_conversion) const125 octave_complex_matrix::float_value (bool force_conversion) const
126 {
127 if (! force_conversion)
128 warn_implicit_conversion ("Octave:imag-to-real",
129 "complex matrix", "real scalar");
130
131 if (rows () == 0 || columns () == 0)
132 err_invalid_conversion ("complex matrix", "real scalar");
133
134 warn_implicit_conversion ("Octave:array-to-scalar",
135 "complex matrix", "real scalar");
136
137 return std::real (matrix(0, 0));
138 }
139
140 NDArray
array_value(bool force_conversion) const141 octave_complex_matrix::array_value (bool force_conversion) const
142 {
143 NDArray retval;
144
145 if (! force_conversion)
146 warn_implicit_conversion ("Octave:imag-to-real",
147 "complex matrix", "real matrix");
148
149 retval = ::real (matrix);
150
151 return retval;
152 }
153
154 Matrix
matrix_value(bool force_conversion) const155 octave_complex_matrix::matrix_value (bool force_conversion) const
156 {
157 Matrix retval;
158
159 if (! force_conversion)
160 warn_implicit_conversion ("Octave:imag-to-real",
161 "complex matrix", "real matrix");
162
163 retval = ::real (ComplexMatrix (matrix));
164
165 return retval;
166 }
167
168 FloatMatrix
float_matrix_value(bool force_conversion) const169 octave_complex_matrix::float_matrix_value (bool force_conversion) const
170 {
171 FloatMatrix retval;
172
173 if (! force_conversion)
174 warn_implicit_conversion ("Octave:imag-to-real",
175 "complex matrix", "real matrix");
176
177 retval = ::real (ComplexMatrix (matrix));
178
179 return retval;
180 }
181
182 Complex
complex_value(bool) const183 octave_complex_matrix::complex_value (bool) const
184 {
185 if (rows () == 0 || columns () == 0)
186 err_invalid_conversion ("complex matrix", "complex scalar");
187
188 warn_implicit_conversion ("Octave:array-to-scalar",
189 "complex matrix", "complex scalar");
190
191 return matrix(0, 0);
192 }
193
194 FloatComplex
float_complex_value(bool) const195 octave_complex_matrix::float_complex_value (bool) const
196 {
197 float tmp = lo_ieee_float_nan_value ();
198
199 FloatComplex retval (tmp, tmp);
200
201 if (rows () == 0 || columns () == 0)
202 err_invalid_conversion ("complex matrix", "complex scalar");
203
204 warn_implicit_conversion ("Octave:array-to-scalar",
205 "complex matrix", "complex scalar");
206
207 retval = matrix(0, 0);
208
209 return retval;
210 }
211
212 ComplexMatrix
complex_matrix_value(bool) const213 octave_complex_matrix::complex_matrix_value (bool) const
214 {
215 return ComplexMatrix (matrix);
216 }
217
218 FloatComplexMatrix
float_complex_matrix_value(bool) const219 octave_complex_matrix::float_complex_matrix_value (bool) const
220 {
221 return FloatComplexMatrix (ComplexMatrix (matrix));
222 }
223
224 boolNDArray
bool_array_value(bool warn) const225 octave_complex_matrix::bool_array_value (bool warn) const
226 {
227 if (matrix.any_element_is_nan ())
228 octave::err_nan_to_logical_conversion ();
229 if (warn && (! matrix.all_elements_are_real ()
230 || real (matrix).any_element_not_one_or_zero ()))
231 warn_logical_conversion ();
232
233 return mx_el_ne (matrix, Complex (0.0));
234 }
235
236 charNDArray
char_array_value(bool frc_str_conv) const237 octave_complex_matrix::char_array_value (bool frc_str_conv) const
238 {
239 charNDArray retval;
240
241 if (! frc_str_conv)
242 warn_implicit_conversion ("Octave:num-to-str",
243 "complex matrix", "string");
244 else
245 {
246 retval = charNDArray (dims ());
247 octave_idx_type nel = numel ();
248
249 for (octave_idx_type i = 0; i < nel; i++)
250 retval.elem (i) = static_cast<char> (std::real (matrix.elem (i)));
251 }
252
253 return retval;
254 }
255
256 FloatComplexNDArray
float_complex_array_value(bool) const257 octave_complex_matrix::float_complex_array_value (bool) const
258 {
259 return FloatComplexNDArray (matrix);
260 }
261
262 SparseMatrix
sparse_matrix_value(bool force_conversion) const263 octave_complex_matrix::sparse_matrix_value (bool force_conversion) const
264 {
265 SparseMatrix retval;
266
267 if (! force_conversion)
268 warn_implicit_conversion ("Octave:imag-to-real",
269 "complex matrix", "real matrix");
270
271 retval = SparseMatrix (::real (ComplexMatrix (matrix)));
272
273 return retval;
274 }
275
276 SparseComplexMatrix
sparse_complex_matrix_value(bool) const277 octave_complex_matrix::sparse_complex_matrix_value (bool) const
278 {
279 return SparseComplexMatrix (ComplexMatrix (matrix));
280 }
281
282 octave_value
as_double(void) const283 octave_complex_matrix::as_double (void) const
284 {
285 return matrix;
286 }
287
288 octave_value
as_single(void) const289 octave_complex_matrix::as_single (void) const
290 {
291 return FloatComplexNDArray (matrix);
292 }
293
294 octave_value
diag(octave_idx_type k) const295 octave_complex_matrix::diag (octave_idx_type k) const
296 {
297 octave_value retval;
298 if (k == 0 && matrix.ndims () == 2
299 && (matrix.rows () == 1 || matrix.columns () == 1))
300 retval = ComplexDiagMatrix (DiagArray2<Complex> (matrix));
301 else
302 retval = octave_base_matrix<ComplexNDArray>::diag (k);
303
304 return retval;
305 }
306
307 octave_value
diag(octave_idx_type m,octave_idx_type n) const308 octave_complex_matrix::diag (octave_idx_type m, octave_idx_type n) const
309 {
310 if (matrix.ndims () != 2
311 || (matrix.rows () != 1 && matrix.columns () != 1))
312 error ("diag: expecting vector argument");
313
314 ComplexMatrix mat (matrix);
315
316 return mat.diag (m, n);
317 }
318
319 bool
save_ascii(std::ostream & os)320 octave_complex_matrix::save_ascii (std::ostream& os)
321 {
322 dim_vector dv = dims ();
323 if (dv.ndims () > 2)
324 {
325 ComplexNDArray tmp = complex_array_value ();
326
327 os << "# ndims: " << dv.ndims () << "\n";
328
329 for (int i = 0; i < dv.ndims (); i++)
330 os << ' ' << dv(i);
331
332 os << "\n" << tmp;
333 }
334 else
335 {
336 // Keep this case, rather than use generic code above for backward
337 // compatibility. Makes load_ascii much more complex!!
338 os << "# rows: " << rows () << "\n"
339 << "# columns: " << columns () << "\n";
340
341 os << complex_matrix_value ();
342 }
343
344 return true;
345 }
346
347 bool
load_ascii(std::istream & is)348 octave_complex_matrix::load_ascii (std::istream& is)
349 {
350 string_vector keywords(2);
351
352 keywords[0] = "ndims";
353 keywords[1] = "rows";
354
355 std::string kw;
356 octave_idx_type val = 0;
357
358 if (! extract_keyword (is, keywords, kw, val, true))
359 error ("load: failed to extract number of rows and columns");
360
361 if (kw == "ndims")
362 {
363 int mdims = static_cast<int> (val);
364
365 if (mdims < 0)
366 error ("load: failed to extract number of dimensions");
367
368 dim_vector dv;
369 dv.resize (mdims);
370
371 for (int i = 0; i < mdims; i++)
372 is >> dv(i);
373
374 if (! is)
375 error ("load: failed to read dimensions");
376
377 ComplexNDArray tmp(dv);
378
379 is >> tmp;
380
381 if (! is)
382 error ("load: failed to load matrix constant");
383
384 matrix = tmp;
385 }
386 else if (kw == "rows")
387 {
388 octave_idx_type nr = val;
389 octave_idx_type nc = 0;
390
391 if (nr < 0 || ! extract_keyword (is, "columns", nc) || nc < 0)
392 error ("load: failed to extract number of rows and columns");
393
394 if (nr > 0 && nc > 0)
395 {
396 ComplexMatrix tmp (nr, nc);
397 is >> tmp;
398 if (! is)
399 error ("load: failed to load matrix constant");
400
401 matrix = tmp;
402 }
403 else if (nr == 0 || nc == 0)
404 matrix = ComplexMatrix (nr, nc);
405 else
406 panic_impossible ();
407 }
408 else
409 panic_impossible ();
410
411 return true;
412 }
413
414 bool
save_binary(std::ostream & os,bool save_as_floats)415 octave_complex_matrix::save_binary (std::ostream& os, bool save_as_floats)
416 {
417 dim_vector dv = dims ();
418 if (dv.ndims () < 1)
419 return false;
420
421 // Use negative value for ndims to differentiate with old format!!
422 int32_t tmp = - dv.ndims ();
423 os.write (reinterpret_cast<char *> (&tmp), 4);
424 for (int i = 0; i < dv.ndims (); i++)
425 {
426 tmp = dv(i);
427 os.write (reinterpret_cast<char *> (&tmp), 4);
428 }
429
430 ComplexNDArray m = complex_array_value ();
431 save_type st = LS_DOUBLE;
432 if (save_as_floats)
433 {
434 if (m.too_large_for_float ())
435 {
436 warning ("save: some values too large to save as floats --");
437 warning ("save: saving as doubles instead");
438 }
439 else
440 st = LS_FLOAT;
441 }
442 else if (dv.numel () > 4096) // FIXME: make this configurable.
443 {
444 double max_val, min_val;
445 if (m.all_integers (max_val, min_val))
446 st = get_save_type (max_val, min_val);
447 }
448
449 const Complex *mtmp = m.data ();
450 write_doubles (os, reinterpret_cast<const double *> (mtmp), st,
451 2 * dv.numel ());
452
453 return true;
454 }
455
456 bool
load_binary(std::istream & is,bool swap,octave::mach_info::float_format fmt)457 octave_complex_matrix::load_binary (std::istream& is, bool swap,
458 octave::mach_info::float_format fmt)
459 {
460 char tmp;
461 int32_t mdims;
462 if (! is.read (reinterpret_cast<char *> (&mdims), 4))
463 return false;
464 if (swap)
465 swap_bytes<4> (&mdims);
466 if (mdims < 0)
467 {
468 mdims = - mdims;
469 int32_t di;
470 dim_vector dv;
471 dv.resize (mdims);
472
473 for (int i = 0; i < mdims; i++)
474 {
475 if (! is.read (reinterpret_cast<char *> (&di), 4))
476 return false;
477 if (swap)
478 swap_bytes<4> (&di);
479 dv(i) = di;
480 }
481
482 // Convert an array with a single dimension to be a row vector.
483 // Octave should never write files like this, other software
484 // might.
485
486 if (mdims == 1)
487 {
488 mdims = 2;
489 dv.resize (mdims);
490 dv(1) = dv(0);
491 dv(0) = 1;
492 }
493
494 if (! is.read (reinterpret_cast<char *> (&tmp), 1))
495 return false;
496
497 ComplexNDArray m(dv);
498 Complex *im = m.fortran_vec ();
499 read_doubles (is, reinterpret_cast<double *> (im),
500 static_cast<save_type> (tmp), 2 * dv.numel (), swap, fmt);
501
502 if (! is)
503 return false;
504
505 matrix = m;
506 }
507 else
508 {
509 int32_t nr, nc;
510 nr = mdims;
511 if (! is.read (reinterpret_cast<char *> (&nc), 4))
512 return false;
513 if (swap)
514 swap_bytes<4> (&nc);
515 if (! is.read (reinterpret_cast<char *> (&tmp), 1))
516 return false;
517 ComplexMatrix m (nr, nc);
518 Complex *im = m.fortran_vec ();
519 octave_idx_type len = nr * nc;
520 read_doubles (is, reinterpret_cast<double *> (im),
521 static_cast<save_type> (tmp), 2*len, swap, fmt);
522
523 if (! is)
524 return false;
525
526 matrix = m;
527 }
528 return true;
529 }
530
531 bool
save_hdf5(octave_hdf5_id loc_id,const char * name,bool save_as_floats)532 octave_complex_matrix::save_hdf5 (octave_hdf5_id loc_id, const char *name,
533 bool save_as_floats)
534 {
535 #if defined (HAVE_HDF5)
536
537 dim_vector dv = dims ();
538 int empty = save_hdf5_empty (loc_id, name, dv);
539 if (empty)
540 return (empty > 0);
541
542 int rank = dv.ndims ();
543 hid_t space_hid, data_hid, type_hid;
544 space_hid = data_hid = type_hid = -1;
545 bool retval = true;
546 ComplexNDArray m = complex_array_value ();
547
548 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
549
550 // Octave uses column-major, while HDF5 uses row-major ordering
551 for (int i = 0; i < rank; i++)
552 hdims[i] = dv(rank-i-1);
553
554 space_hid = H5Screate_simple (rank, hdims, nullptr);
555 if (space_hid < 0) return false;
556
557 hid_t save_type_hid = H5T_NATIVE_DOUBLE;
558
559 if (save_as_floats)
560 {
561 if (m.too_large_for_float ())
562 {
563 warning ("save: some values too large to save as floats --");
564 warning ("save: saving as doubles instead");
565 }
566 else
567 save_type_hid = H5T_NATIVE_FLOAT;
568 }
569 #if defined (HAVE_HDF5_INT2FLOAT_CONVERSIONS)
570 // hdf5 currently doesn't support float/integer conversions
571 else
572 {
573 double max_val, min_val;
574
575 if (m.all_integers (max_val, min_val))
576 save_type_hid
577 = save_type_to_hdf5 (get_save_type (max_val, min_val));
578 }
579 #endif
580
581 type_hid = hdf5_make_complex_type (save_type_hid);
582 if (type_hid < 0)
583 {
584 H5Sclose (space_hid);
585 return false;
586 }
587 #if defined (HAVE_HDF5_18)
588 data_hid = H5Dcreate (loc_id, name, type_hid, space_hid,
589 octave_H5P_DEFAULT, octave_H5P_DEFAULT, octave_H5P_DEFAULT);
590 #else
591 data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, octave_H5P_DEFAULT);
592 #endif
593 if (data_hid < 0)
594 {
595 H5Sclose (space_hid);
596 H5Tclose (type_hid);
597 return false;
598 }
599
600 hid_t complex_type_hid = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
601 if (complex_type_hid < 0) retval = false;
602
603 if (retval)
604 {
605 Complex *mtmp = m.fortran_vec ();
606 if (H5Dwrite (data_hid, complex_type_hid, octave_H5S_ALL, octave_H5S_ALL,
607 octave_H5P_DEFAULT, mtmp)
608 < 0)
609 {
610 H5Tclose (complex_type_hid);
611 retval = false;
612 }
613 }
614
615 H5Tclose (complex_type_hid);
616 H5Dclose (data_hid);
617 H5Tclose (type_hid);
618 H5Sclose (space_hid);
619
620 return retval;
621
622 #else
623 octave_unused_parameter (loc_id);
624 octave_unused_parameter (name);
625 octave_unused_parameter (save_as_floats);
626
627 warn_save ("hdf5");
628
629 return false;
630 #endif
631 }
632
633 bool
load_hdf5(octave_hdf5_id loc_id,const char * name)634 octave_complex_matrix::load_hdf5 (octave_hdf5_id loc_id, const char *name)
635 {
636 bool retval = false;
637
638 #if defined (HAVE_HDF5)
639
640 dim_vector dv;
641 int empty = load_hdf5_empty (loc_id, name, dv);
642 if (empty > 0)
643 matrix.resize (dv);
644 if (empty)
645 return (empty > 0);
646
647 #if defined (HAVE_HDF5_18)
648 hid_t data_hid = H5Dopen (loc_id, name, octave_H5P_DEFAULT);
649 #else
650 hid_t data_hid = H5Dopen (loc_id, name);
651 #endif
652 hid_t type_hid = H5Dget_type (data_hid);
653
654 hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
655
656 if (! hdf5_types_compatible (type_hid, complex_type))
657 {
658 H5Tclose (complex_type);
659 H5Dclose (data_hid);
660 return false;
661 }
662
663 hid_t space_id = H5Dget_space (data_hid);
664
665 hsize_t rank = H5Sget_simple_extent_ndims (space_id);
666
667 if (rank < 1)
668 {
669 H5Tclose (complex_type);
670 H5Sclose (space_id);
671 H5Dclose (data_hid);
672 return false;
673 }
674
675 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
676 OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
677
678 H5Sget_simple_extent_dims (space_id, hdims, maxdims);
679
680 // Octave uses column-major, while HDF5 uses row-major ordering
681 if (rank == 1)
682 {
683 dv.resize (2);
684 dv(0) = 1;
685 dv(1) = hdims[0];
686 }
687 else
688 {
689 dv.resize (rank);
690 for (hsize_t i = 0, j = rank - 1; i < rank; i++, j--)
691 dv(j) = hdims[i];
692 }
693
694 ComplexNDArray m (dv);
695 Complex *reim = m.fortran_vec ();
696 if (H5Dread (data_hid, complex_type, octave_H5S_ALL, octave_H5S_ALL,
697 octave_H5P_DEFAULT, reim)
698 >= 0)
699 {
700 retval = true;
701 matrix = m;
702 }
703
704 H5Tclose (complex_type);
705 H5Sclose (space_id);
706 H5Dclose (data_hid);
707
708 #else
709 octave_unused_parameter (loc_id);
710 octave_unused_parameter (name);
711
712 warn_load ("hdf5");
713 #endif
714
715 return retval;
716 }
717
718 void
print_raw(std::ostream & os,bool pr_as_read_syntax) const719 octave_complex_matrix::print_raw (std::ostream& os,
720 bool pr_as_read_syntax) const
721 {
722 octave_print_internal (os, matrix, pr_as_read_syntax,
723 current_print_indent_level ());
724 }
725
726 mxArray *
as_mxArray(void) const727 octave_complex_matrix::as_mxArray (void) const
728 {
729 mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxCOMPLEX);
730
731 double *pr = static_cast<double *> (retval->get_data ());
732 double *pi = static_cast<double *> (retval->get_imag_data ());
733
734 mwSize nel = numel ();
735
736 const Complex *p = matrix.data ();
737
738 for (mwIndex i = 0; i < nel; i++)
739 {
740 pr[i] = std::real (p[i]);
741 pi[i] = std::imag (p[i]);
742 }
743
744 return retval;
745 }
746
747 octave_value
map(unary_mapper_t umap) const748 octave_complex_matrix::map (unary_mapper_t umap) const
749 {
750 switch (umap)
751 {
752 // Mappers handled specially.
753 case umap_real:
754 return ::real (matrix);
755 case umap_imag:
756 return ::imag (matrix);
757 case umap_conj:
758 return ::conj (matrix);
759
760 // Special cases for Matlab compatibility.
761 case umap_xtolower:
762 case umap_xtoupper:
763 return matrix;
764
765 #define ARRAY_METHOD_MAPPER(UMAP, FCN) \
766 case umap_ ## UMAP: \
767 return octave_value (matrix.FCN ())
768
769 ARRAY_METHOD_MAPPER (abs, abs);
770 ARRAY_METHOD_MAPPER (isnan, isnan);
771 ARRAY_METHOD_MAPPER (isinf, isinf);
772 ARRAY_METHOD_MAPPER (isfinite, isfinite);
773
774 #define ARRAY_MAPPER(UMAP, TYPE, FCN) \
775 case umap_ ## UMAP: \
776 return octave_value (matrix.map<TYPE> (FCN))
777
778 ARRAY_MAPPER (acos, Complex, octave::math::acos);
779 ARRAY_MAPPER (acosh, Complex, octave::math::acosh);
780 ARRAY_MAPPER (angle, double, std::arg);
781 ARRAY_MAPPER (arg, double, std::arg);
782 ARRAY_MAPPER (asin, Complex, octave::math::asin);
783 ARRAY_MAPPER (asinh, Complex, octave::math::asinh);
784 ARRAY_MAPPER (atan, Complex, octave::math::atan);
785 ARRAY_MAPPER (atanh, Complex, octave::math::atanh);
786 ARRAY_MAPPER (erf, Complex, octave::math::erf);
787 ARRAY_MAPPER (erfc, Complex, octave::math::erfc);
788 ARRAY_MAPPER (erfcx, Complex, octave::math::erfcx);
789 ARRAY_MAPPER (erfi, Complex, octave::math::erfi);
790 ARRAY_MAPPER (dawson, Complex, octave::math::dawson);
791 ARRAY_MAPPER (ceil, Complex, octave::math::ceil);
792 ARRAY_MAPPER (cos, Complex, std::cos);
793 ARRAY_MAPPER (cosh, Complex, std::cosh);
794 ARRAY_MAPPER (exp, Complex, std::exp);
795 ARRAY_MAPPER (expm1, Complex, octave::math::expm1);
796 ARRAY_MAPPER (fix, Complex, octave::math::fix);
797 ARRAY_MAPPER (floor, Complex, octave::math::floor);
798 ARRAY_MAPPER (log, Complex, std::log);
799 ARRAY_MAPPER (log2, Complex, octave::math::log2);
800 ARRAY_MAPPER (log10, Complex, std::log10);
801 ARRAY_MAPPER (log1p, Complex, octave::math::log1p);
802 ARRAY_MAPPER (round, Complex, octave::math::round);
803 ARRAY_MAPPER (roundb, Complex, octave::math::roundb);
804 ARRAY_MAPPER (signum, Complex, octave::math::signum);
805 ARRAY_MAPPER (sin, Complex, std::sin);
806 ARRAY_MAPPER (sinh, Complex, std::sinh);
807 ARRAY_MAPPER (sqrt, Complex, std::sqrt);
808 ARRAY_MAPPER (tan, Complex, std::tan);
809 ARRAY_MAPPER (tanh, Complex, std::tanh);
810 ARRAY_MAPPER (isna, bool, octave::math::isna);
811
812 default:
813 return octave_base_value::map (umap);
814 }
815 }
816