GNU Octave 7.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-2022 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
60extern template class octave_base_scalar<double>;
61extern template class octave_base_scalar<FloatComplex>;
62
63template class octave_base_scalar<Complex>;
64
66 "complex scalar", "double");
67
68namespace octave
69{
70 // Complain if a complex value is used as a subscript.
71
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 ~complex_index_exception (void) = default;
84
85 void update_message (void)
86 {
87 set_message (expression ()
88 + ": subscripts must be real (forgot to initialize i or j?)");
89 }
90
91 // ID of error to throw.
92 const char * err_id (void) const
93 {
94 return "Octave:invalid-index";
95 }
96 };
97}
98
99static octave_base_value *
101{
102 const octave_complex& v = dynamic_cast<const octave_complex&> (a);
103
105}
106
109{
110 return
113}
114
117{
118 octave_base_value *retval = nullptr;
119
120 double im = scalar.imag ();
121
122 if (im == 0.0)
123 retval = new octave_scalar (scalar.real ());
124
125 return retval;
126}
127
130{
131 // FIXME: this doesn't solve the problem of
132 //
133 // a = i; a([1,1], [1,1], [1,1])
134 //
135 // and similar constructions. Hmm...
136
137 // FIXME: using this constructor avoids narrowing the
138 // 1x1 matrix back to a scalar value. Need a better solution
139 // to this problem.
140
142
143 return tmp.index_op (idx, resize_ok);
144}
145
146// Can't make an index_vector from a complex number. Throw an error.
149{
150 std::ostringstream buf;
151 buf << scalar.real () << std::showpos << scalar.imag () << 'i';
152 octave::complex_index_exception cie (buf.str ());
153
154 throw cie;
155}
156
157double
158octave_complex::double_value (bool force_conversion) const
159{
160 if (! force_conversion)
161 warn_implicit_conversion ("Octave:imag-to-real",
162 "complex scalar", "real scalar");
163
164 return scalar.real ();
165}
166
167float
168octave_complex::float_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
177Matrix
178octave_complex::matrix_value (bool force_conversion) const
179{
180 Matrix retval;
181
182 if (! force_conversion)
183 warn_implicit_conversion ("Octave:imag-to-real",
184 "complex scalar", "real matrix");
185
186 retval = Matrix (1, 1, scalar.real ());
187
188 return retval;
189}
190
192octave_complex::float_matrix_value (bool force_conversion) const
193{
194 FloatMatrix retval;
195
196 if (! force_conversion)
197 warn_implicit_conversion ("Octave:imag-to-real",
198 "complex scalar", "real matrix");
199
200 retval = FloatMatrix (1, 1, scalar.real ());
201
202 return retval;
203}
204
206octave_complex::array_value (bool force_conversion) const
207{
208 NDArray retval;
209
210 if (! force_conversion)
211 warn_implicit_conversion ("Octave:imag-to-real",
212 "complex scalar", "real matrix");
213
214 retval = NDArray (dim_vector (1, 1), scalar.real ());
215
216 return retval;
217}
218
220octave_complex::float_array_value (bool force_conversion) const
221{
222 FloatNDArray retval;
223
224 if (! force_conversion)
225 warn_implicit_conversion ("Octave:imag-to-real",
226 "complex scalar", "real matrix");
227
228 retval = FloatNDArray (dim_vector (1, 1), scalar.real ());
229
230 return retval;
231}
232
235{
236 return scalar;
237}
238
241{
242 return static_cast<FloatComplex> (scalar);
243}
244
247{
248 return ComplexMatrix (1, 1, scalar);
249}
250
253{
254 return FloatComplexMatrix (1, 1, static_cast<FloatComplex> (scalar));
255}
256
258octave_complex::complex_array_value (bool /* force_conversion */) const
259{
260 return ComplexNDArray (dim_vector (1, 1), scalar);
261}
262
264octave_complex::float_complex_array_value (bool /* force_conversion */) const
265{
266 return FloatComplexNDArray (dim_vector (1, 1),
267 static_cast<FloatComplex> (scalar));
268}
269
271octave_complex::resize (const dim_vector& dv, bool fill) const
272{
273 if (fill)
274 {
275 ComplexNDArray retval (dv, Complex (0));
276
277 if (dv.numel ())
278 retval(0) = scalar;
279
280 return retval;
281 }
282 else
283 {
284 ComplexNDArray retval (dv);
285
286 if (dv.numel ())
287 retval(0) = scalar;
288
289 return retval;
290 }
291}
292
295{
296 return scalar;
297}
298
301{
302 return FloatComplex (scalar);
303}
304
307{
308 return ComplexDiagMatrix (Array<Complex> (dim_vector (1, 1), scalar), m, n);
309}
310
311bool
313{
314 Complex c = complex_value ();
315
316 octave::write_value<Complex> (os, c);
317
318 os << "\n";
319
320 return true;
321}
322
323bool
325{
326 scalar = octave::read_value<Complex> (is);
327
328 if (! is)
329 error ("load: failed to load complex scalar constant");
330
331 return true;
332}
333
334bool
335octave_complex::save_binary (std::ostream& os, bool /* save_as_floats */)
336{
337 char tmp = static_cast<char> (LS_DOUBLE);
338 os.write (reinterpret_cast<char *> (&tmp), 1);
339 Complex ctmp = complex_value ();
340 os.write (reinterpret_cast<char *> (&ctmp), 16);
341
342 return true;
343}
344
345bool
346octave_complex::load_binary (std::istream& is, bool swap,
348{
349 char tmp;
350 if (! is.read (reinterpret_cast<char *> (&tmp), 1))
351 return false;
352
353 Complex ctmp;
354 read_doubles (is, reinterpret_cast<double *> (&ctmp),
355 static_cast<save_type> (tmp), 2, swap, fmt);
356
357 if (! is)
358 return false;
359
360 scalar = ctmp;
361 return true;
362}
363
364bool
366 bool /* save_as_floats */)
367{
368 bool retval = false;
369
370#if defined (HAVE_HDF5)
371
372 hsize_t dimens[3] = {0};
373 hid_t space_hid, type_hid, data_hid;
374 space_hid = type_hid = data_hid = -1;
375
376 space_hid = H5Screate_simple (0, dimens, nullptr);
377 if (space_hid < 0)
378 return false;
379
380 type_hid = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
381 if (type_hid < 0)
382 {
383 H5Sclose (space_hid);
384 return false;
385 }
386#if defined (HAVE_HDF5_18)
387 data_hid = H5Dcreate (loc_id, name, type_hid, space_hid,
389#else
390 data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, octave_H5P_DEFAULT);
391#endif
392 if (data_hid < 0)
393 {
394 H5Sclose (space_hid);
395 H5Tclose (type_hid);
396 return false;
397 }
398
399 Complex tmp = complex_value ();
400 retval = H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
401 octave_H5P_DEFAULT, &tmp) >= 0;
402
403 H5Dclose (data_hid);
404 H5Tclose (type_hid);
405 H5Sclose (space_hid);
406
407#else
408 octave_unused_parameter (loc_id);
409 octave_unused_parameter (name);
410
411 warn_save ("hdf5");
412#endif
413
414 return retval;
415}
416
417bool
419{
420 bool retval = false;
421
422#if defined (HAVE_HDF5)
423
424#if defined (HAVE_HDF5_18)
425 hid_t data_hid = H5Dopen (loc_id, name, octave_H5P_DEFAULT);
426#else
427 hid_t data_hid = H5Dopen (loc_id, name);
428#endif
429 hid_t type_hid = H5Dget_type (data_hid);
430
431 hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
432
433 if (! hdf5_types_compatible (type_hid, complex_type))
434 {
435 H5Tclose (complex_type);
436 H5Dclose (data_hid);
437 return false;
438 }
439
440 hid_t space_id = H5Dget_space (data_hid);
441 hsize_t rank = H5Sget_simple_extent_ndims (space_id);
442
443 if (rank != 0)
444 {
445 H5Tclose (complex_type);
446 H5Sclose (space_id);
447 H5Dclose (data_hid);
448 return false;
449 }
450
451 // complex scalar:
452 Complex ctmp;
453 if (H5Dread (data_hid, complex_type, octave_H5S_ALL, octave_H5S_ALL,
454 octave_H5P_DEFAULT, &ctmp) >= 0)
455 {
456 retval = true;
457 scalar = ctmp;
458 }
459
460 H5Tclose (complex_type);
461 H5Sclose (space_id);
462 H5Dclose (data_hid);
463
464#else
465 octave_unused_parameter (loc_id);
466 octave_unused_parameter (name);
467
468 warn_load ("hdf5");
469#endif
470
471 return retval;
472}
473
474mxArray *
475octave_complex::as_mxArray (bool interleaved) const
476{
477 mxArray *retval = new mxArray (interleaved, mxDOUBLE_CLASS, 1, 1, mxCOMPLEX);
478
479 if (interleaved)
480 {
481 mxComplexDouble *pd
482 = reinterpret_cast<mxComplexDouble *> (retval->get_complex_doubles ());
483
484 pd[0].real = scalar.real ();
485 pd[0].imag = scalar.imag ();
486 }
487 else
488 {
489 mxDouble *pr = static_cast<mxDouble *> (retval->get_data ());
490 mxDouble *pi = static_cast<mxDouble *> (retval->get_imag_data ());
491
492 pr[0] = scalar.real ();
493 pi[0] = scalar.imag ();
494 }
495
496 return retval;
497}
498
501{
502 switch (umap)
503 {
504#define SCALAR_MAPPER(UMAP, FCN) \
505 case umap_ ## UMAP: \
506 return octave_value (FCN (scalar))
507
511 SCALAR_MAPPER (angle, std::arg);
512 SCALAR_MAPPER (arg, std::arg);
524 SCALAR_MAPPER (cos, std::cos);
525 SCALAR_MAPPER (cosh, std::cosh);
526 SCALAR_MAPPER (exp, std::exp);
531 SCALAR_MAPPER (log, std::log);
533 SCALAR_MAPPER (log10, std::log10);
539 SCALAR_MAPPER (sin, std::sin);
540 SCALAR_MAPPER (sinh, std::sinh);
541 SCALAR_MAPPER (sqrt, std::sqrt);
542 SCALAR_MAPPER (tan, std::tan);
543 SCALAR_MAPPER (tanh, std::tanh);
548
549 // Special cases for Matlab compatibility.
550 case umap_xtolower:
551 case umap_xtoupper:
552 return scalar;
553
554 default:
555 return octave_base_value::map (umap);
556 }
557}
ComplexColumnVector conj(const ComplexColumnVector &a)
Definition: CColVector.cc:217
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
mxComplexDouble * get_complex_doubles(void) const
Definition: mxarray.h:529
void * get_data(void) const
Definition: mxarray.h:497
void * get_imag_data(void) const
Definition: mxarray.h:562
const char * err_id(void) const
Definition: ov-complex.cc:92
~complex_index_exception(void)=default
complex_index_exception(const std::string &value)
Definition: ov-complex.cc:76
virtual octave_value map(unary_mapper_t) const
Definition: ov-base.cc:1176
OCTINTERP_API void warn_load(const char *type) const
Definition: ov-base.cc:1152
OCTINTERP_API void warn_save(const char *type) const
Definition: ov-base.cc:1161
OCTINTERP_API float float_value(bool=false) const
Definition: ov-complex.cc:168
octave_base_value * try_narrowing_conversion(void)
Definition: ov-complex.cc:116
OCTINTERP_API bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
Definition: ov-complex.cc:346
OCTINTERP_API bool save_binary(std::ostream &os, bool save_as_floats)
Definition: ov-complex.cc:335
OCTINTERP_API octave_value as_single(void) const
Definition: ov-complex.cc:300
OCTINTERP_API FloatComplex float_complex_value(bool=false) const
Definition: ov-complex.cc:240
OCTINTERP_API NDArray array_value(bool=false) const
Definition: ov-complex.cc:206
OCTINTERP_API FloatComplexMatrix float_complex_matrix_value(bool=false) const
Definition: ov-complex.cc:252
OCTINTERP_API octave_value diag(octave_idx_type m, octave_idx_type n) const
Definition: ov-complex.cc:306
OCTINTERP_API bool load_hdf5(octave_hdf5_id loc_id, const char *name)
Definition: ov-complex.cc:418
OCTINTERP_API mxArray * as_mxArray(bool interleaved) const
Definition: ov-complex.cc:475
OCTINTERP_API ComplexMatrix complex_matrix_value(bool=false) const
Definition: ov-complex.cc:246
OCTINTERP_API bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
Definition: ov-complex.cc:365
OCTINTERP_API bool save_ascii(std::ostream &os)
Definition: ov-complex.cc:312
OCTINTERP_API octave_value map(unary_mapper_t umap) const
Definition: ov-complex.cc:500
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov-complex.cc:129
OCTINTERP_API FloatNDArray float_array_value(bool=false) const
Definition: ov-complex.cc:220
octave::idx_vector index_vector(bool=false) const
Definition: ov-complex.cc:148
OCTINTERP_API octave_value as_double(void) const
Definition: ov-complex.cc:294
type_conv_info numeric_demotion_function(void) const
Definition: ov-complex.cc:108
OCTINTERP_API octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov-complex.cc:271
OCTINTERP_API FloatMatrix float_matrix_value(bool=false) const
Definition: ov-complex.cc:192
OCTINTERP_API bool load_ascii(std::istream &is)
Definition: ov-complex.cc:324
OCTINTERP_API ComplexNDArray complex_array_value(bool=false) const
Definition: ov-complex.cc:258
OCTINTERP_API FloatComplexNDArray float_complex_array_value(bool=false) const
Definition: ov-complex.cc:264
OCTINTERP_API Matrix matrix_value(bool=false) const
Definition: ov-complex.cc:178
OCTINTERP_API double double_value(bool=false) const
Definition: ov-complex.cc:158
OCTINTERP_API Complex complex_value(bool=false) const
Definition: ov-complex.cc:234
static int static_type_id(void)
octave_value index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov.h:550
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
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:980
void warn_implicit_conversion(const char *id, const char *from, const char *to)
Definition: errwarn.cc:344
QString name
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
void mxArray
Definition: mex.h:58
class OCTAVE_API NDArray
Definition: mx-fwd.h:38
class OCTAVE_API ComplexDiagMatrix
Definition: mx-fwd.h:60
class OCTAVE_API Matrix
Definition: mx-fwd.h:31
class OCTAVE_API ComplexMatrix
Definition: mx-fwd.h:32
class OCTAVE_API FloatComplexMatrix
Definition: mx-fwd.h:34
class OCTAVE_API FloatMatrix
Definition: mx-fwd.h:33
class OCTAVE_API ComplexNDArray
Definition: mx-fwd.h:39
class OCTAVE_API FloatComplexNDArray
Definition: mx-fwd.h:41
class OCTAVE_API FloatNDArray
Definition: mx-fwd.h:40
std::complex< double > erfi(std::complex< double > z, double relerr=0)
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 > erf(std::complex< double > z, double relerr=0)
double fix(double x)
Definition: lo-mappers.h:118
Complex atan(const Complex &x)
Definition: lo-mappers.h:71
double signum(double x)
Definition: lo-mappers.h:229
double asinh(double x)
Definition: lo-specfun.h:58
bool isna(double x)
Definition: lo-mappers.cc:47
double atanh(double x)
Definition: lo-specfun.h:63
bool isfinite(double x)
Definition: lo-mappers.h:192
double roundb(double x)
Definition: lo-mappers.h:147
static const double pi
Definition: lo-specfun.cc:1995
bool isnan(bool)
Definition: lo-mappers.h:178
Complex log1p(const Complex &x)
Definition: lo-specfun.cc:1958
bool isinf(double x)
Definition: lo-mappers.h:203
Complex acos(const Complex &x)
Definition: lo-mappers.cc:85
double round(double x)
Definition: lo-mappers.h:136
Complex asin(const Complex &x)
Definition: lo-mappers.cc:107
double erfcx(double x)
Definition: lo-specfun.cc:1755
Complex erfc(const Complex &x)
Definition: lo-specfun.cc:1652
double acosh(double x)
Definition: lo-specfun.h:40
double erfi(double x)
Definition: lo-specfun.cc:1774
std::complex< T > ceil(const std::complex< T > &x)
Definition: lo-mappers.h:103
std::complex< T > floor(const std::complex< T > &x)
Definition: lo-mappers.h:130
double dawson(double x)
Definition: lo-specfun.cc:1517
Complex log2(const Complex &x)
Definition: lo-mappers.cc:139
Complex erf(const Complex &x)
Definition: lo-specfun.cc:1637
Complex expm1(const Complex &x)
Definition: lo-specfun.cc:1874
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:222
static octave_base_value * default_numeric_demotion_function(const octave_base_value &a)
Definition: ov-complex.cc:100
#define SCALAR_MAPPER(UMAP, FCN)
static T abs(T x)
Definition: pr-output.cc:1678