Example 11: Hermitian Eigenvalue Problems
This example demonstrates computing eigenvalues and eigenvectors for Hermitian (or symmetric) matrices.
Key Concepts
Eigenvalues Only: Computing just the eigenvalues \(\lambda\) using
eig_vals(heev).Eigenvectors: Computing eigenvalues and eigenvectors \(Z\) such that \(A Z = Z \Lambda\).
Simplified vs Traditional: Using
slate::eigvsslate::heev.
C++ Example
Setup (Lines 28-32)
slate::HermitianMatrix<scalar_type> A( ... );
slate::Matrix<scalar_type> Z( ... );
std::vector<real_t> Lambda( n );
A: Input Hermitian matrix n by n.
Z: Matrix to store eigenvectors. Must be n by n.
Lambda: Vector to store eigenvalues. Must be size n.
Eigenvalues Only (Lines 43-49)
slate::eig_vals( A, Lambda ); // simplified API
// or
slate::eig( A, Lambda ); // simplified API
// or
slate::heev( A, Lambda ); // traditional API
Computes only the eigenvalues. A is overwritten by the tridiagonal factors (if heev logic is followed, though conceptually A is destroyed). Lambda contains the eigenvalues in ascending order.
Note: heev stands for Hermitian EigenValues.
Eigenvalues and Eigenvectors (Lines 63-68)
slate::eig( A, Lambda, Z ); // simplified API
// or
slate::heev( A, Lambda, Z ); // traditional API
Computes both eigenvalues and eigenvectors.
Z is overwritten with the eigenvectors.
The columns of Z correspond to the eigenvalues in Lambda.
1// ex11_hermitian_eig.cc
2// Solve Hermitian eigenvalues A = Z Lambda Z^H
3
4/// !!! Lines between `//---------- begin label` !!!
5/// !!! and `//---------- end label` !!!
6/// !!! are included in the SLATE Users' Guide. !!!
7
8#include <slate/slate.hh>
9
10#include "util.hh"
11
12int mpi_size = 0;
13int mpi_rank = 0;
14int grid_p = 0;
15int grid_q = 0;
16
17//------------------------------------------------------------------------------
18template <typename scalar_type>
19void test_hermitian_eig()
20{
21 using real_t = blas::real_type<scalar_type>;
22
23 print_func( mpi_rank );
24
25 int64_t n=1000, nb=256;
26
27 //---------- begin eig1
28 slate::HermitianMatrix<scalar_type>
29 A( slate::Uplo::Lower, n, nb, grid_p, grid_q, MPI_COMM_WORLD );
30 slate::Matrix<scalar_type>
31 Z( n, n, nb, grid_p, grid_q, MPI_COMM_WORLD );
32 std::vector<real_t> Lambda( n );
33 // ...
34 //---------- end eig1
35
36 A.insertLocalTiles();
37 Z.insertLocalTiles();
38 random_matrix( A );
39
40 //----------------------------------------
41 //---------- begin eig2
42 // A = Z Lambda Z^H, eigenvalues only
43 slate::eig_vals( A, Lambda ); // simplified API, or
44 //---------- end eig2
45
46 random_matrix( A );
47
48 //---------- begin eig3
49 slate::eig( A, Lambda ); // simplified API
50 //---------- end eig3
51
52 random_matrix( A );
53
54 //---------- begin eig4
55 slate::heev( A, Lambda ); // traditional API
56 //---------- end eig4
57
58 random_matrix( A );
59
60 //----------------------------------------
61 //---------- begin eig5
62 // A = Z Lambda Z^H, eigenvalues and eigenvectors
63 slate::eig( A, Lambda, Z ); // simplified API
64 //---------- end eig5
65 random_matrix( A );
66
67 //---------- begin eig6
68 slate::heev( A, Lambda, Z ); // traditional API
69 //---------- end eig6
70}
71
72//------------------------------------------------------------------------------
73int main( int argc, char** argv )
74{
75 try {
76 // Parse command line to set types for s, d, c, z precisions.
77 bool types[ 4 ];
78 parse_args( argc, argv, types );
79
80 int provided = 0;
81 slate_mpi_call(
82 MPI_Init_thread( &argc, &argv, MPI_THREAD_MULTIPLE, &provided ) );
83 assert( provided == MPI_THREAD_MULTIPLE );
84
85 slate_mpi_call(
86 MPI_Comm_size( MPI_COMM_WORLD, &mpi_size ) );
87
88 slate_mpi_call(
89 MPI_Comm_rank( MPI_COMM_WORLD, &mpi_rank ) );
90
91 // Determine p-by-q grid for this MPI size.
92 // Hermitian eig requires square MPI grid.
93 grid_size_square( mpi_size, &grid_p, &grid_q );
94 if (mpi_rank == 0) {
95 printf( "mpi_size %d, grid_p %d, grid_q %d\n",
96 mpi_size, grid_p, grid_q );
97 }
98
99 // so random_matrix is different on different ranks.
100 srand( 100 * mpi_rank );
101
102 if (types[ 0 ]) {
103 test_hermitian_eig< float >();
104 }
105
106 if (types[ 1 ]) {
107 test_hermitian_eig< double >();
108 }
109
110 if (types[ 2 ]) {
111 test_hermitian_eig< std::complex<float> >();
112 }
113
114 if (types[ 3 ]) {
115 test_hermitian_eig< std::complex<double> >();
116 }
117
118 slate_mpi_call(
119 MPI_Finalize() );
120 }
121 catch (std::exception const& ex) {
122 fprintf( stderr, "%s", ex.what() );
123 return 1;
124 }
125 return 0;
126}