Search code examples
c++vectorcomplex-numbers

Flatten and restore a complex vector into a double vector and back


I have a vector containing complex values (either defined as std::vector<std::complex<double>> or arma::cx_vec) and would like to convert them into vectors containing double-values of twice the size. Afterwards I would like to convert them back again. Currently I use two loops (here from going from double-vectors to complex vectors and back):

//get x and dx as vectors containing real values, with a size of 2 * dim
arma::cx_colvec local_x(dim), local_dx(dim);
for(size_t i = 0; i < x.size(); i += 2) {
    local_x(i / 2) = std::complex<double>(x(i), x(i + 1));
}
//Do something with local_x and local_dx
for(size_t i = 0; i < 2 * dim; i += 2) {
    dx(i) = local_dx(i / 2).real();
    dx(i + 1) = local_dx(i / 2).imag();
}
//Send dx back

I can imagine that that might be rather slow. Therefore, are there other possibilities of reshaping those vectors from complex to double and back? Ideally involving iterators (such that I can use methods such as transform()) instead of a loop over a size.

Background to this question is: I have complex input data which has to be put into a function A which I can not modify, but which calls a user-supplied function again (called U). This function does not support complex data types, only real types. Therefore, my intention was to flatten the vector before putting it into A, unflatten it in U, do the calculations on it, reflatten it and send it back again.


Solution

  • std::complex<double> is explicitly called out as something that can be treated as a double[2]

    Array-oriented access

    For any object z of type complex<T>, reinterpret_cast<T(&)[2]>(z)[0] is the real part of z and reinterpret_cast<T(&)[2]>(z)[1] is the imaginary part of z.

    For any pointer to an element of an array of complex<T> named p and any valid array index i, reinterpret_cast<T*>(p)[2*i] is the real part of the complex number p[i], and reinterpret_cast<T*>(p)[2*i + 1] is the imaginary part of the complex number p[i]

    The intent of this requirement is to preserve binary compatibility between the C++ library complex number types and the C language complex number types (and arrays thereof), which have an identical object representation requirement.

    So you can use std::vector::data() to obtain a complex<double> *, and reinterpret it as a double * with twice as many elements.