0

How can I print out the highest element of Valarray of complex numbers in C++ ?

I have tried with this code but it is returning error messages

#include <iostream>     // std::cout
#include <valarray> 
#include <complex>// std::valarray


typedef std::complex<double> Complex;
typedef std::valarray <Complex > CArray;


int main ()
{
  CArray y[5]={{1, 2},{3, 4},{2,0},{7,0},{9,0}};

  std::cout << "The max is " << y.max() << '\n';

  return 0;
}

Output:

main.cpp: In function 'int main()':
main.cpp:15:35: error: request for member 'max' in 'y', which is of non-class type 'CArray [5] {aka std::valarray<std::complex<double> > [5]}'
   std::cout << "The max is " << y.max() << '\n';
                                   ^

What I am doing wrong ?

Second version of code I have modified a bit the code, Now I would like to get all index corresponding to the highest element of my Valarray in my case all index corresponding to element {9,0}

Note :by "Highest element" I mean element having the highest real part

new code:

#include <iostream>
#include <valarray> 
#include <complex>
#include <algorithm>
#include <numeric>
typedef std::complex<double> Complex;
typedef std::valarray <Complex > CArray;

int main ()
{
    CArray y={{1, 2},{3, 4},{2,0},{9,0},{7,0},{9,0}};
    auto max_val = std::accumulate (std::begin(y), std::end(y), *std::begin(y),
        [](const Complex& a ,const Complex& b)
        {
            auto abs_a = abs(a);
            auto abs_b = abs(b);
            //if(abs_a == abs_b)
               // return std::max(arg(a), arg(b));
            return std::max(abs_a, abs_b);
        }
    );
  for (std::size_t i =std::begin(y) ; i != std::end(y) ;  i++) {
      std::cout << "The max is found on index ["<< i <<"]" << max_val<< '\n';

  }


  return 0;
}

I am getting following errors : Output:

main.cpp: In function 'int main()':
main.cpp:22:35: error: invalid conversion from 'std::complex<double>*' to 'std::size_t {aka long unsigned int}' [-fpermissive]
   for (std::size_t i =std::begin(y) ; i != std::end(y) ;  i++) {
                                   ^
main.cpp:22:54: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]
   for (std::size_t i =std::begin(y) ; i != std::end(y) ;  i++) {
                                                      ^
Serge
  • 3
  • 5

3 Answers3

3
  1. y is an array of valarrays, so you need to call max on each element in that array, not on the array itself (which of course has no member functions).
  2. std::complex is not a comparable type, so what does it mean to have a "highest" element?

Update: Regarding your edit, I think I understand what you're after...

For the highest index of the max (by real()) element:

std::size_t max_index(CArray const& y) {
    struct acc_t {
        double max_value;
        std::size_t max_idx, current_idx;

        constexpr acc_t next() const { return {max_value, max_idx, current_idx + 1}; }
        constexpr acc_t next_with(Complex const c) const {
            return {c.real(), current_idx, current_idx + 1};
        }
    };

    return std::accumulate(
        std::begin(y), std::end(y), acc_t{},
        [](acc_t const acc, Complex const c) {
            return c.real() < acc.max_value
              ? acc.next()
              : acc.next_with(c);
        }
    ).max_idx;
}

Online Demo

Or for all indices of the max element:

std::vector<std::size_t> max_indices(CArray const& y) {
    struct acc_t {
        std::vector<std::size_t> max_idcs;
        double max_value;
        std::size_t current_idx;

        constexpr acc_t&& next() {
            ++current_idx;
            return std::move(*this);
        }
        acc_t&& next_with_current() {
            max_idcs.push_back(current_idx++);
            return std::move(*this);
        }
        acc_t&& next_with(Complex const c) {
            max_value = c.real();
            max_idcs.clear();
            return next_with_current();
        }
    };

    return std::accumulate(
        std::begin(y), std::end(y), acc_t{},
        [](acc_t& acc, Complex const c) {
            return c.real() < acc.max_value ? acc.next()
                 : c.real() > acc.max_value ? acc.next_with(c)
                 :                            acc.next_with_current();
        }
    ).max_idcs;
}

Online Demo

N.b. your code has abs involved but I'm not sure why since you said you just wanted comparison based on std::complex<>::real(), so I've omitted that...

ildjarn
  • 62,044
  • 9
  • 127
  • 211
0

using std::accumulate can get max of complex numbers simillar to Matlab max function:

#include <iostream>
#include <valarray> 
#include <complex>
#include <algorithm>
#include <numeric>
typedef std::complex<double> Complex;
typedef std::valarray <Complex > CArray;

int main ()
{
    CArray y={{1, 2},{3, 4},{2,0},{7,0},{9,0}};
    auto max_val = std::accumulate (std::begin(y), std::end(y), *std::begin(y),
        [](const Complex& a ,const Complex& b)
        {
            auto abs_a = abs(a);
            auto abs_b = abs(b);
            if(abs_a == abs_b)
                return std::max(arg(a), arg(b));
            return std::max(abs_a, abs_b);
        }
    );

  std::cout << "The max is " << max_val<< '\n';

  return 0;
}

Edit: question edited and OP wants to get index of maximum of real part of complex numbers so your answer:

#include <iostream>
#include <valarray> 
#include <complex>
#include <algorithm>
#include <numeric>

typedef std::complex<double> Complex;
typedef std::valarray <Complex > CArray;

int main ()
{
    CArray y={{1, 2},{3, 4},{2,0},{7,0},{9,0}};
    std::vector<int> index(y.size());
    std::iota( index.begin(), index.end(), 0 );

    auto max_index = std::accumulate (std::begin(index), std::end(index), *std::begin(index),
        [&](int a ,int b)
        {
            return y[a].real() > y[b].real() ? a: b;
        }
    );

  std::cout << "index of  max is " << max_index<< '\n';
  return 0;
}

Edit 2: as @ildjarn mentioned modified question wants to get all indices corresponding to the highest element so modified answer:

#include <iostream>
#include <valarray> 
#include <complex>
#include <algorithm>
#include <numeric>

typedef std::complex<double> Complex;
typedef std::valarray <Complex > CArray;

int main ()
{
    CArray y={{1, 2},{3, 4},{2,0},{7,0},{9,0}};
    std::vector<int> index(y.size());
    std::iota( index.begin(), index.end(), 0 );

    auto max_index = std::accumulate (std::begin(index), std::end(index), *std::begin(index),
        [&](int a ,int b)
        {
            return y[a].real() > y[b].real() ? a: b;
        }
    );
    std::vector<int> indices;
    std::copy_if(std::begin(index), std::end(index),  std::back_inserter(indices),
        [&](int a)
        {
            return y[a] == y[max_index];
        }
    );
    for (auto i: indices)
        std::cout << "index of  max is " << i << '\n';
    return 0;
}

Edit 3: using std::max_element the simplest solution we have:

#include <iostream>
#include <valarray> 
#include <complex>
#include <algorithm>
#include <numeric>
#include <vector>

typedef std::complex<double> Complex;
typedef std::valarray <Complex > CArray;

int main ()
{
    CArray y={{1, 2},{3, 4},{2,0},{9,0},{7,0},{9,0}};

    auto max_index = std::max_element (std::begin(y), std::end(y), 
        [](const Complex& a ,const Complex& b)
        {
            return a.real() < b.real() ;
        }
    );
    std::cout << "index of  first max element is " << max_index-std::begin(y) << '\n';
    std::cout << "indices of all matches of max element is: " << "[";

    for (auto it= std::begin(y), end = std::end(y); it != end; ++it){
        if(it->real() == max_index->real()) {
            std::cout << it - std::begin(y) << ' ' ;
        }
    }
    std::cout << "]";
    return 0;
}
rahnema1
  • 15,264
  • 3
  • 15
  • 27
  • 1
    Thank you, that work. I have modified a bit the code, Now I would like to get all index corresponding to the highest element of my Valarray in my case all index corresponding to the element {9,0} Note :by "Highest element" I mean element having the highest real part – Serge Jul 17 '16 at 11:39
0

The bigger problem of your original code was (as pointed by Ildjarn) that Complex lack of operator<.

I suppose that your Complex should be a little more complex (if you allow me the play on words).

I propose the following solution were Complex derive from std::complex<double> and declare a friend operator< (). One of many operator< () possible.

#include <iostream>
#include <valarray> 
#include <complex>

struct Complex: public std::complex<double>
 {
   template <typename ... Args>
      Complex (const Args & ... args) : std::complex<double>{args...}
    { }

   friend bool operator< (const Complex & c1, const Complex & c2)
    {
      return (c1.real() < c2.real())
         || ((c1.real() == c2.real()) && (c1.imag() < c2.imag()));
    }
 };

typedef std::valarray <Complex > CArray;

int main ()
 {
   CArray y { {1.0,2.0}, {3.0,4.0}, {2.0,0.0}, {7.0,0.0}, {9.0,0.0} };

   std::cout << "The max is " << y.max() << '\n';

   return 0;
 }

If you accept that Complex can be a templated class (using Class<double> instead of Complex, you can write a more general solution in this way (that can be used also with complex based on float and long double)

#include <iostream>
#include <valarray> 
#include <complex>

template <typename T>
struct Complex: public std::complex<T>
 {
   template <typename ... Args>
      Complex (const Args & ... args) : std::complex<T>{args...}
    { }

   friend bool operator< (const Complex & c1, const Complex & c2)
    {
      return (c1.real() < c2.real())
         || ((c1.real() == c2.real()) && (c1.imag() < c2.imag()));
    }
 };

typedef std::valarray <Complex<double>> CArray;

int main ()
 {
   CArray y { {1.0,2.0}, {3.0,4.0}, {2.0,0.0}, {7.0,0.0}, {9.0,0.0} };

   std::cout << "The max is " << y.max() << '\n';

   return 0;
 }

p.s.: should work with C++11 too.

p.s.2: sorry for my bad English.

--- Edited to get the index of the max element ---

#include <iostream>
#include <valarray> 
#include <complex>

template <typename T>
struct Complex: public std::complex<T>
 {
   template <typename ... Args>
      Complex (const Args & ... args) : std::complex<T>{args...}
    { }

   friend bool operator< (const Complex & c1, const Complex & c2)
    {
      return (c1.real() < c2.real())
         || ((c1.real() == c2.real()) && (c1.imag() < c2.imag()));
    }
 };

typedef std::valarray <Complex<double>> CArray;

int main ()
 {
   CArray y { {1.0,2.0}, {3.0,4.0}, {2.0,0.0}, {7.0,0.0}, {9.0,0.0} };

   auto m = 0U;

   for ( auto i = 1U ; i < y.size() ; ++i)
      if ( y[m] < y[i] )
         m = i;

   std::cout << "The max is found on index ["<< m <<"] and is " << y[m]
      << std::endl;

   return 0;
 }
max66
  • 65,235
  • 10
  • 71
  • 111
  • 1
    That work too, thanks, You English is good for me. I have modified a bit the code, Now I would like to get all index corresponding to the highest element of my Valarray in my case all index corresponding to the element {9,0}. please see code I pasted above. – Serge Jul 17 '16 at 12:00
  • @Serge - I've rejected your edit because was clearly wrong; I've added a possible solution to get max value and corresponding index – max66 Jul 17 '16 at 12:28