Search code examples
c++eigeneigen3

Find lowest real value in complex vector


How can I find the smallest positive real number in a complex vector of size N by 1 in Eigen3? For example, in this case I'd like to find the value 3.64038.

#include <Eigen/Dense>
#include <iostream>
using namespace std;
using namespace Eigen;

int main()
{
    MatrixXd m(4, 4);
    m << 1, 0, 1, 1,
        0, 2, 0, 1,
        0, 2, 1, 0,
        2, 1, 2, 1;
    cout << m << endl;
    cout << m.eigenvalues() << endl;
    return 0;
}

Output

1 0 1 1
0 2 0 1
0 2 1 0
2 1 2 1
        (3.64038,0)
      (-0.444745,0)
 (0.902183,1.01932)
(0.902183,-1.01932)

Vector elements that have an imaginary part not equal to 0 should be excluded.

I wrote the following function, but was wondering if there is an approach using Eigen's methods.

double findPositiveRealMin(VectorXcd v)
{
    VectorXd v_imag = v.imag();
    VectorXd v_real = v.real();
    for (int i = 0; i < v.rows(); i++)
    {
        if (v_imag[i] != 0 | v_real[i] <= 0)
            v_real[i] = 1.0e16;
    }
    return v_real.minCoeff();
}

Solution

  • One option is to create a logical array and then call Eigen::select on it. Inspired by https://forum.kde.org/viewtopic.php?f=74&t=91378

    In this case:

    Eigen::VectorXcd v = m.eigenvalues();
    
    // minimum positive real value with zero imaginary part
    Eigen::Array<bool,Eigen::Dynamic,1> cond1 = (v.imag().array() == 0);
    Eigen::Array<bool,Eigen::Dynamic,1> cond2 = (v.real().array() > 0);
    double some_big_value = 1e16;
    
    std::cout << (cond1 && cond2).select(v.real(), some_big_value).minCoeff() << std::endl;
    

    ... or, as a one-liner:

    std::cout << (v.imag().array() == 0 && v.real().array() > 0).select(v.real(), 1e16).minCoeff() << std::endl;