Skip to content

Commit

Permalink
test: factor out check_heev; use tests from LAWN 41 and LAPACK testers.
Browse files Browse the repository at this point in the history
  • Loading branch information
mgates3 committed Jun 26, 2024
1 parent f1be573 commit a448f66
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 162 deletions.
97 changes: 97 additions & 0 deletions test/check_heev.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) 2017-2023, University of Tennessee. All rights reserved.
// SPDX-License-Identifier: BSD-3-Clause
// This program is free software: you can redistribute it and/or modify it under
// the terms of the BSD 3-Clause license. See the accompanying LICENSE file.

#include "blas.hh"
#include "lapack.hh"
#include "error.hh"
#include "check_ortho.hh"
#include "scale.hh"

#include <vector>

//------------------------------------------------------------------------------
// Computes error measures:
// If jobz != NoVec:
// result[ 0 ] = || A - Z Lambda Z^H || / (n ||A||) if nfound == n;
// result[ 0 ] = || Z^H A Z - Lambda || / (n ||A||) otherwise.
// result[ 1 ] = || I - Z^H Z || / n, if jobz != NoVec.
// result[ 2 ] = 0 if Lambda is in non-decreasing order, else >= 1.
template< typename scalar_t >
void check_heev(
lapack::Job jobz,
lapack::Uplo uplo, int64_t n,
scalar_t const* A, int64_t lda,
int64_t nfound,
blas::real_type< scalar_t > const* Lambda,
scalar_t const* Z, int64_t ldz,
blas::real_type< scalar_t > result[ 3 ] )
{
using namespace blas;
using namespace lapack;
using real_t = blas::real_type< scalar_t >;

// Constants
const scalar_t one = 1;
const scalar_t zero = 0;

if (jobz == Job::Vec) {
real_t Anorm = lapack::lanhe( Norm::One, uplo, n, A, lda );

// R is nfound-by-nfound, whether n == nfound or not.
int64_t ldr = nfound;
std::vector< scalar_t > R_( ldr*nfound );
scalar_t* R = &R_[ 0 ];

if (n == nfound) {
// || A - Z Lambda Z^H ||
std::vector< scalar_t > ZLambda_( ldz*n );
scalar_t* ZLambda = &ZLambda_[ 0 ];

// ZLambda = Z Lambda is n-by-n.
lapack::lacpy( MatrixType::General, n, n,
Z, ldz,
ZLambda, ldz );
col_scale( n, n, ZLambda, ldz, Lambda );
// R = A - (Z Lambda) Z^H; could use gemmtr instead of gemm.
lapack::lacpy( MatrixType::General, n, n,
A, lda,
R, ldr );
blas::gemm( Layout::ColMajor, Op::NoTrans, Op::ConjTrans, n, n, n,
-one, ZLambda, ldz,
Z, ldz,
one, R, ldr );
}
else {
// || Z^H A Z - Lambda ||
std::vector< scalar_t > AZ_( lda*nfound );
scalar_t* AZ = &AZ_[ 0 ];

// AZ = A Z is n-by-nfound.
blas::hemm( Layout::ColMajor, Side::Left, uplo, n, nfound,
one, A, lda,
Z, ldz,
zero, AZ, lda );
// R = Z^H (A Z); could use gemmtr instead of gemm.
blas::gemm( Layout::ColMajor, Op::ConjTrans, Op::NoTrans,
nfound, nfound, n,
one, Z, ldz,
AZ, lda,
zero, R, ldr );
// R -= Lambda, along diagonal.
blas::axpy( nfound, -one, Lambda, 1, R, ldr + 1 );
}
result[ 0 ] = lapack::lanhe( Norm::One, uplo, nfound, R, ldr )
/ (n * Anorm);

result[ 1 ] = check_orthogonality( RowCol::Col, n, nfound, Z, ldz );
}

// Check that Lambda is non-decreasing.
result[ 2 ] = 0;
for (int64_t i = 0; i < nfound - 1; ++i) {
if (Lambda[ i ] > Lambda[ i+1 ])
result[ 2 ] += 1;
}
}
8 changes: 4 additions & 4 deletions test/test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -319,23 +319,23 @@ std::vector< testsweeper::routines_t > routines = {

// -----
// symmetric/Hermitian eigenvalues
{ "heev", test_heev, Section::heev }, // tested via LAPACKE
{ "heev", test_heev, Section::heev }, // backwards error check
{ "hpev", test_hpev, Section::heev }, // tested via LAPACKE
{ "hbev", test_hbev, Section::heev }, // tested via LAPACKE
{ "sturm", test_sturm, Section::heev },
{ "", nullptr, Section::newline },

{ "heevx", test_heevx, Section::heev }, // tested via LAPACKE
{ "heevx", test_heevx, Section::heev }, // backwards error check
{ "hpevx", test_hpevx, Section::heev }, // tested via LAPACKE
{ "hbevx", test_hbevx, Section::heev }, // tested via LAPACKE
{ "", nullptr, Section::newline },

{ "heevd", test_heevd, Section::heev }, // tested via LAPACKE using gcc/MKL
{ "heevd", test_heevd, Section::heev }, // backwards error check
{ "hpevd", test_hpevd, Section::heev }, // tested via LAPACKE using gcc/MKL
{ "hbevd", test_hbevd, Section::heev }, // tested via LAPACKE using gcc/MKL
{ "", nullptr, Section::newline },

{ "heevr", test_heevr, Section::heev }, // tested via LAPACKE using gcc/MKL
{ "heevr", test_heevr, Section::heev }, // backwards error check
{ "", nullptr, Section::newline },

{ "hetrd", test_hetrd, Section::heev }, // tested via LAPACKE using gcc/MKL
Expand Down
54 changes: 23 additions & 31 deletions test/test_heev.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#include "lapack/flops.hh"
#include "print_matrix.hh"
#include "error.hh"
#include "check_heev.hh"
#include "lapacke_wrappers.hh"
#include "scale.hh"

#include <vector>

Expand All @@ -18,10 +18,10 @@ template< typename scalar_t >
void test_heev_work( Params& params, bool run )
{
using real_t = blas::real_type< scalar_t >;
using lapack::Job;

// Constants
const scalar_t one = 1.0;
const real_t eps = std::numeric_limits< real_t >::epsilon();
const real_t eps = std::numeric_limits< real_t >::epsilon();

// get & mark input values
lapack::Job jobz = params.jobz();
Expand All @@ -36,7 +36,9 @@ void test_heev_work( Params& params, bool run )
params.ref_time();
// params.ref_gflops();
// params.gflops();
params.ortho();
params.error2();
params.error2.name( "Lambda" );

if (! run)
return;
Expand Down Expand Up @@ -82,34 +84,24 @@ void test_heev_work( Params& params, bool run )
printf( "Lambda = " ); print_vector( n, &Lambda_tst[0], 1 );
}

if (params.check() == 'y' && jobz == lapack::Job::Vec) {
// ---------- check error
// Relative backwards error =
// ||A Z - Z Lambda|| / (n * ||A|| * ||Z||)
real_t Anorm = lapack::lanhe( lapack::Norm::One, uplo, n, &A[0], lda );
real_t Znorm = lapack::lange( lapack::Norm::One, n, n, &Z[0], ldz );

std::vector< scalar_t > W( size_Z ); // workspace
int64_t ldw = ldz;
// W = Z
lapack::lacpy( lapack::MatrixType::General, n, n,
&Z[0], ldz,
&W[0], ldw );
// W = Z Lambda
col_scale( n, n, &W[0], ldw, &Lambda_tst[0] );
// W = A Z - (Z Lambda)
blas::hemm( blas::Layout::ColMajor, blas::Side::Left, uplo, n, n,
one, &A[0], lda,
&Z[0], ldz,
-one, &W[0], ldw );
real_t error = lapack::lange( lapack::Norm::One, n, n, &W[0], ldw );
if (verbose >= 2) {
printf( "W = " ); print_matrix( n, n, &W[0], ldw );
}

error /= (n * Anorm * Znorm);
params.error() = error;
params.okay() = (error < tol);
if (params.check() == 'y') {
// ---------- check numerical error
// result[ 0 ] = || A - Z Lambda Z^H || / (n ||A||), if jobz != NoVec.
// result[ 1 ] = || I - Z^H Z || / n, if jobz != NoVec.
// result[ 2 ] = 0 if Lambda is in non-decreasing order, else > 0.
real_t result[ 3 ] = { (real_t) testsweeper::no_data_flag,
(real_t) testsweeper::no_data_flag,
(real_t) testsweeper::no_data_flag };

check_heev( jobz, uplo, n, &A[0], lda,
n, &Lambda_tst[0], &Z[0], ldz, result );

params.error() = result[ 0 ];
params.ortho() = result[ 1 ];
params.error2() = result[ 2 ];
params.okay() = (jobz == Job::NoVec || result[ 0 ] < tol)
&& (jobz == Job::NoVec || result[ 1 ] < tol)
&& result[ 2 ] < tol;
}

if (params.ref() == 'y' || params.check() == 'y') {
Expand Down
53 changes: 23 additions & 30 deletions test/test_heevd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#include "lapack/flops.hh"
#include "print_matrix.hh"
#include "error.hh"
#include "check_heev.hh"
#include "lapacke_wrappers.hh"
#include "scale.hh"

#include <vector>

Expand All @@ -18,9 +18,10 @@ template< typename scalar_t >
void test_heevd_work( Params& params, bool run )
{
using real_t = blas::real_type< scalar_t >;
using lapack::Job;

// Constants
const real_t eps = std::numeric_limits< real_t >::epsilon();
const real_t eps = std::numeric_limits< real_t >::epsilon();

// get & mark input values
lapack::Job jobz = params.jobz();
Expand All @@ -35,7 +36,9 @@ void test_heevd_work( Params& params, bool run )
params.ref_time();
// params.ref_gflops();
// params.gflops();
params.ortho();
params.error2();
params.error2.name( "Lambda" );

if (! run)
return;
Expand Down Expand Up @@ -81,34 +84,24 @@ void test_heevd_work( Params& params, bool run )
printf( "Lambda = " ); print_vector( n, &Lambda_tst[0], 1 );
}

if (params.check() == 'y' && jobz == lapack::Job::Vec) {
// ---------- check error
// Relative backwards error =
// ||A Z - Z Lambda|| / (n * ||A|| * ||Z||)
real_t Anorm = lapack::lanhe( lapack::Norm::One, uplo, n, &A[0], lda );
real_t Znorm = lapack::lange( lapack::Norm::One, n, n, &Z[0], ldz );

std::vector< scalar_t > W( size_A ); // workspace
int64_t ldw = ldz;
// W = Z
lapack::lacpy( lapack::MatrixType::General, n, n,
&Z[0], ldz,
&W[0], ldw );
// W = Z Lambda
col_scale( n, n, &W[0], ldw, &Lambda_tst[0] );
// W = A Z - (Z Lambda)
blas::hemm( blas::Layout::ColMajor, blas::Side::Left, uplo, n, n,
1.0, &A[0], lda,
&Z[0], ldz,
-1.0, &W[0], ldw );
real_t error = lapack::lange( lapack::Norm::One, n, n, &W[0], ldw );
if (verbose >= 2) {
printf( "W = " ); print_matrix( n, n, &W[0], ldw );
}

error /= (n * Anorm * Znorm);
params.error() = error;
params.okay() = (error < tol);
if (params.check() == 'y') {
// ---------- check numerical error
// result[ 0 ] = || A - Z Lambda Z^H || / (n ||A||), if jobz != NoVec.
// result[ 1 ] = || I - Z^H Z || / n, if jobz != NoVec.
// result[ 2 ] = 0 if Lambda is in non-decreasing order, else > 0.
real_t result[ 3 ] = { (real_t) testsweeper::no_data_flag,
(real_t) testsweeper::no_data_flag,
(real_t) testsweeper::no_data_flag };

check_heev( jobz, uplo, n, &A[0], lda,
n, &Lambda_tst[0], &Z[0], ldz, result );

params.error() = result[ 0 ];
params.ortho() = result[ 1 ];
params.error2() = result[ 2 ];
params.okay() = (jobz == Job::NoVec || result[ 0 ] < tol)
&& (jobz == Job::NoVec || result[ 1 ] < tol)
&& result[ 2 ] < tol;
}

if (params.ref() == 'y' || params.check() == 'y') {
Expand Down
54 changes: 23 additions & 31 deletions test/test_heevd_device.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

#include "test.hh"
#include "lapack.hh"
#include "scale.hh"
#include "lapack/device.hh"
#include "lapack/flops.hh"
#include "print_matrix.hh"
#include "error.hh"
#include "check_heev.hh"
#include "lapacke_wrappers.hh"

#include <vector>
Expand All @@ -19,10 +19,10 @@ void test_heevd_device_work( Params& params, bool run )
{
using lapack::device_info_int;
using real_t = blas::real_type< scalar_t >;
using lapack::Job;

// Constants
const scalar_t one = 1.0;
const real_t eps = std::numeric_limits< real_t >::epsilon();
const real_t eps = std::numeric_limits< real_t >::epsilon();

// get & mark input values
lapack::Job jobz = params.jobz();
Expand All @@ -38,7 +38,9 @@ void test_heevd_device_work( Params& params, bool run )
params.ref_time();
// params.ref_gflops();
// params.gflops();
params.ortho();
params.error2();
params.error2.name( "Lambda" );

if (! run)
return;
Expand Down Expand Up @@ -126,34 +128,24 @@ void test_heevd_device_work( Params& params, bool run )
printf( "Lambda = " ); print_vector( n, &Lambda_tst[0], 1 );
}

if (params.check() == 'y' && jobz == lapack::Job::Vec) {
// ---------- check error
// Relative backwards error =
// ||A Z - Z Lambda|| / (n * ||A|| * ||Z||)
real_t Anorm = lapack::lanhe( lapack::Norm::One, uplo, n, &A[0], lda );
real_t Znorm = lapack::lange( lapack::Norm::One, n, n, &Z[0], ldz );

std::vector< scalar_t > W( size_Z ); // workspace
int64_t ldw = ldz;
// W = Z
lapack::lacpy( lapack::MatrixType::General, n, n,
&Z[0], ldz,
&W[0], ldw );
// W = Z Lambda
col_scale( n, n, &W[0], ldw, &Lambda_tst[0] );
// W = A Z - (Z Lambda)
blas::hemm( blas::Layout::ColMajor, blas::Side::Left, uplo, n, n,
one, &A[0], lda,
&Z[0], ldz,
-one, &W[0], ldw );
real_t error = lapack::lange( lapack::Norm::One, n, n, &W[0], ldw );
if (verbose >= 2) {
printf( "W = " ); print_matrix( n, n, &W[0], ldw );
}

error /= (n * Anorm * Znorm);
params.error() = error;
params.okay() = (error < tol);
if (params.check() == 'y') {
// ---------- check numerical error
// result[ 0 ] = || A - Z Lambda Z^H || / (n ||A||), if jobz != NoVec.
// result[ 1 ] = || I - Z^H Z || / n, if jobz != NoVec.
// result[ 2 ] = 0 if Lambda is in non-decreasing order, else > 0.
real_t result[ 3 ] = { (real_t) testsweeper::no_data_flag,
(real_t) testsweeper::no_data_flag,
(real_t) testsweeper::no_data_flag };

check_heev( jobz, uplo, n, &A[0], lda,
n, &Lambda_tst[0], &Z[0], ldz, result );

params.error() = result[ 0 ];
params.ortho() = result[ 1 ];
params.error2() = result[ 2 ];
params.okay() = (jobz == Job::NoVec || result[ 0 ] < tol)
&& (jobz == Job::NoVec || result[ 1 ] < tol)
&& result[ 2 ] < tol;
}

if (params.ref() == 'y' || params.check() == 'y') {
Expand Down
Loading

0 comments on commit a448f66

Please sign in to comment.