void inline cuppen_inplace(Matrix& A, Matrix& Q, Vector& lambda) { using std::abs; using mtl::irange; using mtl::imax; using mtl::iall; using vector::iota; typedef typename Collection<Matrix>::value_type value_type; typedef typename Collection<Matrix>::size_type size_type; typedef mtl::vector::dense_vector<size_type, vector::parameters<> > size_vector; // todo: with type trait size_type nrows= num_rows(A); MTL_THROW_IF(nrows != num_cols(A), matrix_not_square()); const value_type zero= 0, one= 1; if (nrows == 1){ lambda[0]= A[0][0]; Q= one; } else { size_type m= size_type(nrows/2); irange till_m(m), from_m(m, imax); size_vector perm(nrows); Matrix T1(A[till_m][till_m]), T2(A[from_m][from_m]), // sub-matrices of A Q0(nrows, nrows), Q1(Q0[till_m][till_m]), Q2(Q0[from_m][from_m]); // Q0 and sub-matrices Vector v(nrows, zero), diag(nrows), lambda1(diag[till_m]), lambda2(diag[from_m]); // sub-vectors of diag //DIVIDE value_type b= A[m-1][m]; T1[m-1][m-1]-= abs(b); T2[0][0]-= abs(b); v[m-1]= b > zero ? one : -one; v[m]= one; cuppen_inplace(T1, Q1, lambda1); cuppen_inplace(T2, Q2, lambda2); Q0[till_m][from_m]= zero; Q0[from_m][till_m]= zero; // zero out non-diagonal blocks T1[m-1][m-1]+= abs(b); T2[0][0]+= abs(b); iota(perm); sort(diag, perm); // CONQUER, start with eq. (3.0.2) using rows (not columns) v[till_m]= b < zero ? Vector(-trans(Q1[m-1][iall])) : trans(Q1[m-1][iall]); v[from_m]= trans(Q2[0][iall]); // permutation on v mtl::matrix::traits::permutation<>::type P= mtl::matrix::permutation(perm); Vector v1(P * v); lambda= secular(v1, diag, abs(b)); // solve secular equation // std::cout << "lambda is " << lambda << "\ndiag is " << diag << '\n'; //Lemma 3.0.2 ... calculate eigenvectors Matrix Q_tilde(nrows, nrows); for (size_type i = 0; i < nrows; i++) { for (size_type j= 0; j < size(diag); ++j) MTL_DEBUG_THROW_IF (diag[j] == lambda[i], logic_error("Can't compute eigenvector, probably due to double eigenvalue.")); Vector li(nrows, lambda[i]), lambda_i(ele_quot(v1, diag - li)); Q_tilde[iall][i]= lambda_i / two_norm(lambda_i); // normalized eigenvector in Matrix Q } Q= Q0 * P * Q_tilde; #if 0 for (size_type i = 0; i < nrows; i++) { // Vector qi(Q[iall][i]); // Todo: find out valgrind complains about the memory of qi for reasons inexplicable Vector qi(nrows); for (size_type j= 0; j < nrows; j++) qi[j]= Q[j][i]; std::cout << "q[" << i << "] = " << qi << ", lambda[i] = " << lambda[i] << ", diff = " << two_norm(Vector(A*qi - lambda[i]*qi)) << ", A*qi = " << Vector(A*qi) << ", li*qi = " << Vector(lambda[i]*qi) << '\n'; itl::basic_iteration<double> iter(1.0, 20, 1e-5, 1e-5); fsm(A, qi, lambda[i], 0.1, iter); std::cout << "q[" << i << "] = " << qi << ", diff = " << two_norm(Vector(A*qi - lambda[i]*qi)) << '\n'; Q[iall][i]= qi; } #endif } }