GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ov-complex.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2024 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 <sstream>
33 
34 #include "lo-ieee.h"
35 #include "lo-specfun.h"
36 #include "lo-mappers.h"
37 
38 #include "mxarray.h"
39 #include "ovl.h"
40 #include "oct-hdf5.h"
41 #include "oct-stream.h"
42 #include "ops.h"
43 #include "ov-complex.h"
44 #include "ov-flt-complex.h"
45 #include "ov-base.h"
46 #include "ov-base-scalar.h"
47 #include "ov-base-scalar.cc"
48 #include "ov-cx-mat.h"
49 #include "ov-scalar.h"
50 #include "errwarn.h"
51 #include "pr-output.h"
52 #include "ops.h"
53 
54 #include "ls-oct-text.h"
55 #include "ls-hdf5.h"
56 
57 // Prevent implicit instantiations on some systems (Windows, others?)
58 // that can lead to duplicate definitions of static data members.
59 
60 extern template class octave_base_scalar<double>;
61 extern template class octave_base_scalar<FloatComplex>;
62 
63 template class octave_base_scalar<Complex>;
64 
66  "complex scalar", "double");
67 
69 
70 // Complain if a complex value is used as a subscript.
71 
72 class complex_index_exception : public index_exception
73 {
74 public:
75 
76  complex_index_exception (const std::string& value)
77  : index_exception (value)
78  {
79  // Virtual, but the one we want to call is defined in this class.
80  update_message ();
81  }
82 
83  OCTAVE_DEFAULT_COPY_MOVE (complex_index_exception)
84 
85  ~complex_index_exception () = default;
86 
87  void update_message ()
88  {
89  set_message (expression ()
90  + ": subscripts must be real (forgot to initialize i or j?)");
91  }
92 
93  // ID of error to throw.
94  const char * err_id () const
95  {
96  return "Octave:invalid-index";
97  }
98 
99  index_exception * dup ()
100  {
101  complex_index_exception *retval = new complex_index_exception {*this};
102  retval->set_identifier (retval->err_id ());
103  return retval;
104  }
105 };
106 
107 OCTAVE_END_NAMESPACE(octave)
108 
109 static octave_base_value *
110 default_numeric_demotion_function (const octave_base_value& a)
111 {
112  const octave_complex& v = dynamic_cast<const octave_complex&> (a);
113 
114  return new octave_float_complex (v.float_complex_value ());
115 }
116 
119 {
120  return
121  octave_base_value::type_conv_info (default_numeric_demotion_function,
123 }
124 
127 {
128  octave_base_value *retval = nullptr;
129 
130  double im = scalar.imag ();
131 
132  if (im == 0.0)
133  retval = new octave_scalar (scalar.real ());
134 
135  return retval;
136 }
137 
139 octave_complex::do_index_op (const octave_value_list& idx, bool resize_ok)
140 {
141  // FIXME: this doesn't solve the problem of
142  //
143  // a = i; a([1,1], [1,1], [1,1])
144  //
145  // and similar constructions. Hmm...
146 
147  // FIXME: using this constructor avoids narrowing the
148  // 1x1 matrix back to a scalar value. Need a better solution
149  // to this problem.
150 
152 
153  return tmp.index_op (idx, resize_ok);
154 }
155 
156 // Can't make an index_vector from a complex number. Throw an error.
159 {
160  std::ostringstream buf;
161  buf << scalar.real () << std::showpos << scalar.imag () << 'i';
162  octave::complex_index_exception cie (buf.str ());
163 
164  throw cie;
165 }
166 
167 double
168 octave_complex::double_value (bool force_conversion) const
169 {
170  if (! force_conversion)
171  warn_implicit_conversion ("Octave:imag-to-real",
172  "complex scalar", "real scalar");
173 
174  return scalar.real ();
175 }
176 
177 float
178 octave_complex::float_value (bool force_conversion) const
179 {
180  if (! force_conversion)
181  warn_implicit_conversion ("Octave:imag-to-real",
182  "complex scalar", "real scalar");
183 
184  return scalar.real ();
185 }
186 
187 Matrix
188 octave_complex::matrix_value (bool force_conversion) const
189 {
190  Matrix retval;
191 
192  if (! force_conversion)
193  warn_implicit_conversion ("Octave:imag-to-real",
194  "complex scalar", "real matrix");
195 
196  retval = Matrix (1, 1, scalar.real ());
197 
198  return retval;
199 }
200 
202 octave_complex::float_matrix_value (bool force_conversion) const
203 {
204  FloatMatrix retval;
205 
206  if (! force_conversion)
207  warn_implicit_conversion ("Octave:imag-to-real",
208  "complex scalar", "real matrix");
209 
210  retval = FloatMatrix (1, 1, scalar.real ());
211 
212  return retval;
213 }
214 
215 NDArray
216 octave_complex::array_value (bool force_conversion) const
217 {
218  NDArray retval;
219 
220  if (! force_conversion)
221  warn_implicit_conversion ("Octave:imag-to-real",
222  "complex scalar", "real matrix");
223 
224  retval = NDArray (dim_vector (1, 1), scalar.real ());
225 
226  return retval;
227 }
228 
230 octave_complex::float_array_value (bool force_conversion) const
231 {
232  FloatNDArray retval;
233 
234  if (! force_conversion)
235  warn_implicit_conversion ("Octave:imag-to-real",
236  "complex scalar", "real matrix");
237 
238  retval = FloatNDArray (dim_vector (1, 1), scalar.real ());
239 
240  return retval;
241 }
242 
243 Complex
245 {
246  return scalar;
247 }
248 
251 {
252  return static_cast<FloatComplex> (scalar);
253 }
254 
257 {
258  return ComplexMatrix (1, 1, scalar);
259 }
260 
263 {
264  return FloatComplexMatrix (1, 1, static_cast<FloatComplex> (scalar));
265 }
266 
268 octave_complex::complex_array_value (bool /* force_conversion */) const
269 {
270  return ComplexNDArray (dim_vector (1, 1), scalar);
271 }
272 
274 octave_complex::float_complex_array_value (bool /* force_conversion */) const
275 {
276  return FloatComplexNDArray (dim_vector (1, 1),
277  static_cast<FloatComplex> (scalar));
278 }
279 
281 octave_complex::resize (const dim_vector& dv, bool fill) const
282 {
283  if (fill)
284  {
285  ComplexNDArray retval (dv, Complex (0));
286 
287  if (dv.numel ())
288  retval(0) = scalar;
289 
290  return retval;
291  }
292  else
293  {
294  ComplexNDArray retval (dv);
295 
296  if (dv.numel ())
297  retval(0) = scalar;
298 
299  return retval;
300  }
301 }
302 
305 {
306  return scalar;
307 }
308 
311 {
312  return FloatComplex (scalar);
313 }
314 
317 {
318  return ComplexDiagMatrix (Array<Complex> (dim_vector (1, 1), scalar), m, n);
319 }
320 
321 bool
322 octave_complex::save_ascii (std::ostream& os)
323 {
324  Complex c = complex_value ();
325 
326  octave::write_value<Complex> (os, c);
327 
328  os << "\n";
329 
330  return true;
331 }
332 
333 bool
334 octave_complex::load_ascii (std::istream& is)
335 {
336  scalar = octave::read_value<Complex> (is);
337 
338  if (! is)
339  error ("load: failed to load complex scalar constant");
340 
341  return true;
342 }
343 
344 bool
345 octave_complex::save_binary (std::ostream& os, bool /* save_as_floats */)
346 {
347  char tmp = static_cast<char> (LS_DOUBLE);
348  os.write (reinterpret_cast<char *> (&tmp), 1);
349  Complex ctmp = complex_value ();
350  os.write (reinterpret_cast<char *> (&ctmp), 16);
351 
352  return true;
353 }
354 
355 bool
356 octave_complex::load_binary (std::istream& is, bool swap,
358 {
359  char tmp;
360  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
361  return false;
362 
363  Complex ctmp;
364  read_doubles (is, reinterpret_cast<double *> (&ctmp),
365  static_cast<save_type> (tmp), 2, swap, fmt);
366 
367  if (! is)
368  return false;
369 
370  scalar = ctmp;
371  return true;
372 }
373 
374 bool
375 octave_complex::save_hdf5 (octave_hdf5_id loc_id, const char *name,
376  bool /* save_as_floats */)
377 {
378  bool retval = false;
379 
380 #if defined (HAVE_HDF5)
381 
382  hsize_t dimens[3] = {0};
383  hid_t space_hid, type_hid, data_hid;
384  space_hid = type_hid = data_hid = -1;
385 
386  space_hid = H5Screate_simple (0, dimens, nullptr);
387  if (space_hid < 0)
388  return false;
389 
390  type_hid = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
391  if (type_hid < 0)
392  {
393  H5Sclose (space_hid);
394  return false;
395  }
396 #if defined (HAVE_HDF5_18)
397  data_hid = H5Dcreate (loc_id, name, type_hid, space_hid,
400 #else
401  data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, octave_H5P_DEFAULT);
402 #endif
403  if (data_hid < 0)
404  {
405  H5Sclose (space_hid);
406  H5Tclose (type_hid);
407  return false;
408  }
409 
410  Complex tmp = complex_value ();
411  retval = H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
412  octave_H5P_DEFAULT, &tmp) >= 0;
413 
414  H5Dclose (data_hid);
415  H5Tclose (type_hid);
416  H5Sclose (space_hid);
417 
418 #else
419  octave_unused_parameter (loc_id);
420  octave_unused_parameter (name);
421 
422  warn_save ("hdf5");
423 #endif
424 
425  return retval;
426 }
427 
428 bool
429 octave_complex::load_hdf5 (octave_hdf5_id loc_id, const char *name)
430 {
431  bool retval = false;
432 
433 #if defined (HAVE_HDF5)
434 
435 #if defined (HAVE_HDF5_18)
436  hid_t data_hid = H5Dopen (loc_id, name, octave_H5P_DEFAULT);
437 #else
438  hid_t data_hid = H5Dopen (loc_id, name);
439 #endif
440  hid_t type_hid = H5Dget_type (data_hid);
441 
442  hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
443 
444  if (! hdf5_types_compatible (type_hid, complex_type))
445  {
446  H5Tclose (complex_type);
447  H5Dclose (data_hid);
448  return false;
449  }
450 
451  hid_t space_id = H5Dget_space (data_hid);
452  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
453 
454  if (rank != 0)
455  {
456  H5Tclose (complex_type);
457  H5Sclose (space_id);
458  H5Dclose (data_hid);
459  return false;
460  }
461 
462  // complex scalar:
463  Complex ctmp;
464  if (H5Dread (data_hid, complex_type, octave_H5S_ALL, octave_H5S_ALL,
465  octave_H5P_DEFAULT, &ctmp) >= 0)
466  {
467  retval = true;
468  scalar = ctmp;
469  }
470 
471  H5Tclose (complex_type);
472  H5Sclose (space_id);
473  H5Dclose (data_hid);
474 
475 #else
476  octave_unused_parameter (loc_id);
477  octave_unused_parameter (name);
478 
479  warn_load ("hdf5");
480 #endif
481 
482  return retval;
483 }
484 
485 mxArray *
486 octave_complex::as_mxArray (bool interleaved) const
487 {
488  mxArray *retval = new mxArray (interleaved, mxDOUBLE_CLASS, 1, 1, mxCOMPLEX);
489 
490  if (interleaved)
491  {
492  mxComplexDouble *pd
493  = reinterpret_cast<mxComplexDouble *> (retval->get_complex_doubles ());
494 
495  pd[0].real = scalar.real ();
496  pd[0].imag = scalar.imag ();
497  }
498  else
499  {
500  mxDouble *pr = static_cast<mxDouble *> (retval->get_data ());
501  mxDouble *pi = static_cast<mxDouble *> (retval->get_imag_data ());
502 
503  pr[0] = scalar.real ();
504  pi[0] = scalar.imag ();
505  }
506 
507  return retval;
508 }
509 
512 {
513  switch (umap)
514  {
515 #define SCALAR_MAPPER(UMAP, FCN) \
516  case umap_ ## UMAP: \
517  return octave_value (FCN (scalar))
518 
519  SCALAR_MAPPER (abs, std::abs);
522  SCALAR_MAPPER (angle, std::arg);
523  SCALAR_MAPPER (arg, std::arg);
535  SCALAR_MAPPER (cos, std::cos);
536  SCALAR_MAPPER (cosh, std::cosh);
537  SCALAR_MAPPER (exp, std::exp);
542  SCALAR_MAPPER (log, std::log);
544  SCALAR_MAPPER (log10, std::log10);
550  SCALAR_MAPPER (sin, std::sin);
551  SCALAR_MAPPER (sinh, std::sinh);
552  SCALAR_MAPPER (sqrt, std::sqrt);
553  SCALAR_MAPPER (tan, std::tan);
554  SCALAR_MAPPER (tanh, std::tanh);
559 
560  // Special cases for Matlab compatibility.
561  case umap_xtolower:
562  case umap_xtoupper:
563  return scalar;
564 
565  default:
566  return octave_base_value::map (umap);
567  }
568 }
ComplexColumnVector conj(const ComplexColumnVector &a)
Definition: CColVector.cc:217
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:130
Definition: dMatrix.h:42
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:335
void * get_imag_data() const
Definition: mxarray.h:511
void * get_data() const
Definition: mxarray.h:473
mxComplexDouble * get_complex_doubles() const
Definition: mxarray.h:505
virtual octave_value map(unary_mapper_t) const
Definition: ov-base.cc:1181
void warn_load(const char *type) const
Definition: ov-base.cc:1157
void warn_save(const char *type) const
Definition: ov-base.cc:1166
float float_value(bool=false) const
Definition: ov-complex.cc:178
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
Definition: ov-complex.cc:356
bool save_binary(std::ostream &os, bool save_as_floats)
Definition: ov-complex.cc:345
FloatComplex float_complex_value(bool=false) const
Definition: ov-complex.cc:250
NDArray array_value(bool=false) const
Definition: ov-complex.cc:216
FloatComplexMatrix float_complex_matrix_value(bool=false) const
Definition: ov-complex.cc:262
octave_value diag(octave_idx_type m, octave_idx_type n) const
Definition: ov-complex.cc:316
bool load_hdf5(octave_hdf5_id loc_id, const char *name)
Definition: ov-complex.cc:429
mxArray * as_mxArray(bool interleaved) const
Definition: ov-complex.cc:486
ComplexMatrix complex_matrix_value(bool=false) const
Definition: ov-complex.cc:256
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
Definition: ov-complex.cc:375
bool save_ascii(std::ostream &os)
Definition: ov-complex.cc:322
octave_value map(unary_mapper_t umap) const
Definition: ov-complex.cc:511
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov-complex.cc:139
octave_value as_single() const
Definition: ov-complex.cc:310
octave_base_value * try_narrowing_conversion()
Definition: ov-complex.cc:126
FloatNDArray float_array_value(bool=false) const
Definition: ov-complex.cc:230
octave::idx_vector index_vector(bool=false) const
Definition: ov-complex.cc:158
octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov-complex.cc:281
FloatMatrix float_matrix_value(bool=false) const
Definition: ov-complex.cc:202
type_conv_info numeric_demotion_function() const
Definition: ov-complex.cc:118
bool load_ascii(std::istream &is)
Definition: ov-complex.cc:334
ComplexNDArray complex_array_value(bool=false) const
Definition: ov-complex.cc:268
FloatComplexNDArray float_complex_array_value(bool=false) const
Definition: ov-complex.cc:274
Matrix matrix_value(bool=false) const
Definition: ov-complex.cc:188
octave_value as_double() const
Definition: ov-complex.cc:304
double double_value(bool=false) const
Definition: ov-complex.cc:168
Complex complex_value(bool=false) const
Definition: ov-complex.cc:244
static int static_type_id()
octave_value index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov.h:504
const octave_hdf5_id octave_H5P_DEFAULT
const octave_hdf5_id octave_H5S_ALL
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:137
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:143
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
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:776
save_type
Definition: data-conv.h:87
@ LS_DOUBLE
Definition: data-conv.h:95
void() error(const char *fmt,...)
Definition: error.cc:988
void warn_implicit_conversion(const char *id, const char *from, const char *to)
Definition: errwarn.cc:344
octave::idx_vector idx_vector
Definition: idx-vector.h:1022
Complex log2(const Complex &x)
Definition: lo-mappers.cc:141
Complex asin(const Complex &x)
Definition: lo-mappers.cc:107
bool isna(double x)
Definition: lo-mappers.cc:47
Complex acos(const Complex &x)
Definition: lo-mappers.cc:85
Complex atan(const Complex &x)
Definition: lo-mappers.h:71
double roundb(double x)
Definition: lo-mappers.h:147
bool isfinite(double x)
Definition: lo-mappers.h:192
bool isinf(double x)
Definition: lo-mappers.h:203
double signum(double x)
Definition: lo-mappers.h:229
double round(double x)
Definition: lo-mappers.h:136
bool isnan(bool)
Definition: lo-mappers.h:178
std::complex< T > floor(const std::complex< T > &x)
Definition: lo-mappers.h:130
std::complex< T > ceil(const std::complex< T > &x)
Definition: lo-mappers.h:103
double fix(double x)
Definition: lo-mappers.h:118
double dawson(double x)
Definition: lo-specfun.cc:1467
Complex expm1(const Complex &x)
Definition: lo-specfun.cc:1835
Complex log1p(const Complex &x)
Definition: lo-specfun.cc:1919
double asinh(double x)
Definition: lo-specfun.h:58
double atanh(double x)
Definition: lo-specfun.h:63
double acosh(double x)
Definition: lo-specfun.h:40
octave_hdf5_id hdf5_make_complex_type(octave_hdf5_id num_type)
Definition: ls-hdf5.cc:405
bool hdf5_types_compatible(octave_hdf5_id t1, octave_hdf5_id t2)
Definition: ls-hdf5.cc:269
float_format
Definition: mach-info.h:38
void mxArray
Definition: mex.h:58
T octave_idx_type m
Definition: mx-inlines.cc:781
octave_idx_type n
Definition: mx-inlines.cc:761
@ mxDOUBLE_CLASS
Definition: mxtypes.h:64
double mxDouble
Definition: mxtypes.h:91
@ mxCOMPLEX
Definition: mxtypes.h:81
std::complex< double > erfc(std::complex< double > z, double relerr=0)
std::complex< double > erfcx(std::complex< double > z, double relerr=0)
std::complex< double > erfi(std::complex< double > z, double relerr=0)
std::complex< double > erf(std::complex< double > z, double relerr=0)
std::complex< double > Complex
Definition: oct-cmplx.h:33
std::complex< float > FloatComplex
Definition: oct-cmplx.h:34
int64_t octave_hdf5_id
#define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)
Definition: ov-base.h:235
#define SCALAR_MAPPER(UMAP, FCN)
template int8_t abs(int8_t)
mxDouble real
Definition: mxtypes.h:104
mxDouble imag
Definition: mxtypes.h:104