GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
ov-complex.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1996-2025 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-cx-mat.h"
47#include "ov-scalar.h"
48#include "errwarn.h"
49#include "pr-output.h"
50#include "ops.h"
51
52#include "ls-oct-text.h"
53#include "ls-hdf5.h"
54
56 "complex scalar", "double");
57
59
60// Complain if a complex value is used as a subscript.
61
62class complex_index_exception : public index_exception
63{
64public:
65
66 complex_index_exception (const std::string& value)
67 : index_exception (value)
68 {
69 // Virtual, but the one we want to call is defined in this class.
71 }
72
73 OCTAVE_DEFAULT_COPY_MOVE (complex_index_exception)
74
75 ~complex_index_exception () = default;
76
77 void update_message ()
78 {
79 set_message (expression ()
80 + ": subscripts must be real (forgot to initialize i or j?)");
81 }
82
83 // ID of error to throw.
84 const char * err_id () const
85 {
86 return "Octave:invalid-index";
87 }
88
90 {
91 complex_index_exception *retval = new complex_index_exception {*this};
92 retval->set_identifier (retval->err_id ());
93 return retval;
94 }
95};
96
97OCTAVE_END_NAMESPACE(octave)
98
99static octave_base_value *
100default_numeric_demotion_function (const octave_base_value& a)
101{
102 const octave_complex& v = dynamic_cast<const octave_complex&> (a);
103
105}
106
109{
110 return
111 octave_base_value::type_conv_info (default_numeric_demotion_function,
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.
147octave::idx_vector
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
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,
347 octave::mach_info::float_format fmt)
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,
390#else
391 data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, octave_H5P_DEFAULT);
392#endif
393 if (data_hid < 0)
394 {
395 H5Sclose (space_hid);
396 H5Tclose (type_hid);
397 return false;
398 }
399
400 Complex tmp = complex_value ();
401 retval = H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
402 octave_H5P_DEFAULT, &tmp) >= 0;
403
404 H5Dclose (data_hid);
405 H5Tclose (type_hid);
406 H5Sclose (space_hid);
407
408#else
409 octave_unused_parameter (loc_id);
410 octave_unused_parameter (name);
411
412 warn_save ("hdf5");
413#endif
414
415 return retval;
416}
417
418bool
420{
421 bool retval = false;
422
423#if defined (HAVE_HDF5)
424
425#if defined (HAVE_HDF5_18)
426 hid_t data_hid = H5Dopen (loc_id, name, octave_H5P_DEFAULT);
427#else
428 hid_t data_hid = H5Dopen (loc_id, name);
429#endif
430 hid_t type_hid = H5Dget_type (data_hid);
431
432 hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
433
434 if (! hdf5_types_compatible (type_hid, complex_type))
435 {
436 H5Tclose (complex_type);
437 H5Dclose (data_hid);
438 return false;
439 }
440
441 hid_t space_id = H5Dget_space (data_hid);
442 hsize_t rank = H5Sget_simple_extent_ndims (space_id);
443
444 if (rank != 0)
445 {
446 H5Tclose (complex_type);
447 H5Sclose (space_id);
448 H5Dclose (data_hid);
449 return false;
450 }
451
452 // complex scalar:
453 Complex ctmp;
454 if (H5Dread (data_hid, complex_type, octave_H5S_ALL, octave_H5S_ALL,
455 octave_H5P_DEFAULT, &ctmp) >= 0)
456 {
457 retval = true;
458 scalar = ctmp;
459 }
460
461 H5Tclose (complex_type);
462 H5Sclose (space_id);
463 H5Dclose (data_hid);
464
465#else
466 octave_unused_parameter (loc_id);
467 octave_unused_parameter (name);
468
469 warn_load ("hdf5");
470#endif
471
472 return retval;
473}
474
475mxArray *
476octave_complex::as_mxArray (bool interleaved) const
477{
478 mxArray *retval = new mxArray (interleaved, mxDOUBLE_CLASS, 1, 1, mxCOMPLEX);
479
480 if (interleaved)
481 {
482 mxComplexDouble *pd
483 = reinterpret_cast<mxComplexDouble *> (retval->get_complex_doubles ());
484
485 pd[0].real = scalar.real ();
486 pd[0].imag = scalar.imag ();
487 }
488 else
489 {
490 mxDouble *pr = static_cast<mxDouble *> (retval->get_data ());
491 mxDouble *pi = static_cast<mxDouble *> (retval->get_imag_data ());
492
493 pr[0] = scalar.real ();
494 pi[0] = scalar.imag ();
495 }
496
497 return retval;
498}
499
502{
503 switch (umap)
504 {
505#define SCALAR_MAPPER(UMAP, FCN) \
506 case umap_ ## UMAP: \
507 return octave_value (FCN (scalar))
508
509 SCALAR_MAPPER (abs, std::abs);
510 SCALAR_MAPPER (acos, octave::math::acos);
511 SCALAR_MAPPER (acosh, octave::math::acosh);
512 SCALAR_MAPPER (angle, std::arg);
513 SCALAR_MAPPER (arg, std::arg);
514 SCALAR_MAPPER (asin, octave::math::asin);
515 SCALAR_MAPPER (asinh, octave::math::asinh);
516 SCALAR_MAPPER (atan, octave::math::atan);
517 SCALAR_MAPPER (atanh, octave::math::atanh);
518 SCALAR_MAPPER (erf, octave::math::erf);
519 SCALAR_MAPPER (erfc, octave::math::erfc);
520 SCALAR_MAPPER (erfcx, octave::math::erfcx);
521 SCALAR_MAPPER (erfi, octave::math::erfi);
522 SCALAR_MAPPER (dawson, octave::math::dawson);
523 SCALAR_MAPPER (ceil, octave::math::ceil);
524 SCALAR_MAPPER (conj, std::conj);
525 SCALAR_MAPPER (cos, std::cos);
526 SCALAR_MAPPER (cosh, std::cosh);
527 SCALAR_MAPPER (exp, std::exp);
528 SCALAR_MAPPER (expm1, octave::math::expm1);
529 SCALAR_MAPPER (fix, octave::math::fix);
530 SCALAR_MAPPER (floor, octave::math::floor);
531 SCALAR_MAPPER (imag, std::imag);
532 SCALAR_MAPPER (log, std::log);
533 SCALAR_MAPPER (log2, octave::math::log2);
534 SCALAR_MAPPER (log10, std::log10);
535 SCALAR_MAPPER (log1p, octave::math::log1p);
536 SCALAR_MAPPER (real, std::real);
537 SCALAR_MAPPER (round, octave::math::round);
538 SCALAR_MAPPER (roundb, octave::math::roundb);
539 SCALAR_MAPPER (signum, octave::math::signum);
540 SCALAR_MAPPER (sin, std::sin);
541 SCALAR_MAPPER (sinh, std::sinh);
542 SCALAR_MAPPER (sqrt, std::sqrt);
543 SCALAR_MAPPER (tan, std::tan);
544 SCALAR_MAPPER (tanh, std::tanh);
545 SCALAR_MAPPER (isfinite, octave::math::isfinite);
546 SCALAR_MAPPER (isinf, octave::math::isinf);
547 SCALAR_MAPPER (isna, octave::math::isna);
548 SCALAR_MAPPER (isnan, octave::math::isnan);
549
550 // Special cases for Matlab compatibility.
551 case umap_xtolower:
552 case umap_xtoupper:
553 return scalar;
554
555 default:
556 return octave_base_value::map (umap);
557 }
558}
ComplexColumnVector conj(const ComplexColumnVector &a)
N Dimensional Array with copy-on-write semantics.
Definition Array.h:130
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition dim-vector.h:331
std::string expression() const
virtual index_exception * dup()=0
virtual const char * err_id() const =0
virtual void update_message()
mxComplexDouble * get_complex_doubles() const
Definition mxarray.h:514
void * get_data() const
Definition mxarray.h:482
void * get_imag_data() const
Definition mxarray.h:520
virtual octave_value map(unary_mapper_t) const
Definition ov-base.cc:1170
void warn_load(const char *type) const
Definition ov-base.cc:1152
void warn_save(const char *type) const
Definition ov-base.cc:1161
float float_value(bool=false) const
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
bool save_binary(std::ostream &os, bool save_as_floats)
FloatComplex float_complex_value(bool=false) const
NDArray array_value(bool=false) const
FloatComplexMatrix float_complex_matrix_value(bool=false) const
octave_value diag(octave_idx_type m, octave_idx_type n) const
bool load_hdf5(octave_hdf5_id loc_id, const char *name)
mxArray * as_mxArray(bool interleaved) const
ComplexMatrix complex_matrix_value(bool=false) const
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
bool save_ascii(std::ostream &os)
octave_value map(unary_mapper_t umap) const
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
octave_value as_single() const
octave_base_value * try_narrowing_conversion()
FloatNDArray float_array_value(bool=false) const
octave::idx_vector index_vector(bool=false) const
octave_value resize(const dim_vector &dv, bool fill=false) const
FloatMatrix float_matrix_value(bool=false) const
type_conv_info numeric_demotion_function() const
bool load_ascii(std::istream &is)
ComplexNDArray complex_array_value(bool=false) const
FloatComplexNDArray float_complex_array_value(bool=false) const
Matrix matrix_value(bool=false) const
octave_value as_double() const
double double_value(bool=false) const
Complex complex_value(bool=false) const
static int static_type_id()
octave_value index_op(const octave_value_list &idx, bool resize_ok=false)
Definition ov.h:504
octave_value real() const
Definition ov.h:1498
octave_value imag() const
Definition ov.h:1489
const octave_hdf5_id octave_H5P_DEFAULT
const octave_hdf5_id octave_H5S_ALL
ColumnVector real(const ComplexColumnVector &a)
ColumnVector imag(const ComplexColumnVector &a)
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:802
save_type
Definition data-conv.h:85
@ LS_DOUBLE
Definition data-conv.h:93
void error(const char *fmt,...)
Definition error.cc:1003
void warn_implicit_conversion(const char *id, const char *from, const char *to)
Definition errwarn.cc:344
Complex log2(const Complex &x)
Complex asin(const Complex &x)
bool isna(double x)
Definition lo-mappers.cc:47
Complex acos(const Complex &x)
Definition lo-mappers.cc:85
std::complex< T > ceil(const std::complex< T > &x)
Definition lo-mappers.h:103
Complex atan(const Complex &x)
Definition lo-mappers.h:71
double roundb(double x)
Definition lo-mappers.h:147
std::complex< T > floor(const std::complex< T > &x)
Definition lo-mappers.h:130
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
double fix(double x)
Definition lo-mappers.h:118
double erfi(double x)
double dawson(double x)
Complex erf(const Complex &x)
double erfcx(double x)
Complex expm1(const Complex &x)
Complex log1p(const Complex &x)
Complex erfc(const Complex &x)
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:410
bool hdf5_types_compatible(octave_hdf5_id t1, octave_hdf5_id t2)
Definition ls-hdf5.cc:274
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:246
#define SCALAR_MAPPER(UMAP, FCN)
template int8_t abs(int8_t)