Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PMR^3: templated eigensolver for Elemental #189

Open
wants to merge 44 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
685bf4a
Create config file for CMake
mcopik Nov 9, 2015
e94630b
Fix the wrong passing of GFORTRAN_LIB to Scalapack
mcopik Nov 18, 2015
dc13004
Merge remote branch 'upstream/master'
Nov 20, 2015
ca7c9e7
Merge branch 'master' of github.com:mcopik/Elemental
mcopik Nov 20, 2015
628436f
Fix passing incorrect include/link strings to ParMETIS
mcopik Nov 20, 2015
724df2d
Merge remote branch 'upstream/master'
mcopik Nov 24, 2015
27da86b
Merge remote branch 'upstream/master'
Nov 26, 2015
3854e23
Merge remote-tracking branch 'upstream/master'
mcopik Dec 11, 2015
bcc2999
New PMRRR
mcopik Feb 10, 2016
08c8a0c
Adding new PMRRR
mcopik Feb 10, 2016
f2f6b08
Update PMRRR
mcopik Feb 10, 2016
fb90124
Update file not compiling with PMRRR
mcopik Feb 10, 2016
c26ff4e
Add example
mcopik Feb 10, 2016
7e216cd
Remove unnecessary config file
mcopik Oct 9, 2016
a52aa80
Merge upstream/master
mcopik Oct 9, 2016
cd42d3b
Fix include for PMR3
mcopik Oct 10, 2016
47dec0c
Update single-precision eigensolver example
mcopik Oct 10, 2016
01d2037
Remove wrong merge
mcopik Oct 10, 2016
7cf5d11
Apply Elemental's changes to PMR3 plarre
mcopik Oct 13, 2016
0480119
Apply Elemental's changes to PMR3 plarrv
mcopik Oct 13, 2016
bdbce36
Apply Elemental's changes to PMR3 process_c_task
mcopik Oct 18, 2016
6d35bb6
Apply Elemental's changes to PMR3 tasks
mcopik Oct 20, 2016
6bb4639
Apply Elemental's changes to PMR3
mcopik Oct 20, 2016
9d125f7
PMR3: fix doubles introduced by a mistake
mcopik Oct 20, 2016
f31bfa7
PMR3: additional API change for tasks.hpp
mcopik Oct 20, 2016
9a3b3a7
PMR3: apply changes for definition headers
mcopik Oct 20, 2016
8268f91
PMR3: remove unnecesary header file
mcopik Oct 20, 2016
98a618b
PMR3: remove unnecesary header file
mcopik Oct 20, 2016
1b7acb9
PMR3: fix converting a string to char*
mcopik Oct 20, 2016
25d68e8
PMR3: change name of odscl
mcopik Oct 20, 2016
fd4c0d3
PMR3: apply final changes
mcopik Oct 20, 2016
f0981a0
Remove dead code
mcopik Oct 21, 2016
cada3ad
PMR3: fix double destructon of lock
mcopik Oct 21, 2016
38157c4
PMR3: create a header file with definitions
mcopik Oct 21, 2016
aeb7cbb
PMR3: remove last dependencies on doubles
mcopik Oct 21, 2016
e98005d
Merge upstream/master
mcopik Oct 21, 2016
2c625f6
PMR3: modify HermitianEig example
mcopik Oct 21, 2016
997a039
PMR3: disable sorting
mcopik Oct 21, 2016
c8b3d4b
PMR3: remove debug output
mcopik Oct 21, 2016
edd0c45
PMR3: remove unused double precision import for PMR3
mcopik Oct 21, 2016
3beb5fc
PMR3: remove debug output
mcopik Oct 21, 2016
66400aa
PMR3: Fix incorrect header guard
mcopik Oct 22, 2016
b66876e
PMR3: remove warnings in lsame
mcopik Oct 22, 2016
39cdaa0
PMR3: remove warnings in lapack code
mcopik Oct 22, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ endif()
# Elemental's mod's of Parallel Multiple Relatively Robust Representations
# ------------------------------------------------------------------------
add_subdirectory(external/pmrrr)
include_directories(external/pmrrr/include)
if(EL_BUILT_SCALAPACK)
add_dependencies(pmrrr project_scalapack)
else()
Expand Down
158 changes: 84 additions & 74 deletions examples/lapack_like/HermitianEig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,88 @@
http://opensource.org/licenses/BSD-2-Clause
*/
#include <El.hpp>

using namespace std;
using namespace El;

// Typedef our real and complex types to 'Real' and 'C' for convenience
typedef double Real;
typedef Complex<Real> C;
template<typename Real>
void run_example(Int n, bool print)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't properly documented, but the examples/ folder is meant to be more for demonstrating functionality, and the tests/ folder is meant for correctness tests.

As an aside, Elemental uses CamelCase for function names rather than snake_case.

It might also be preferred to test both single-precision and double-precision in the same run (with the ideal case being able to individually disable each precision).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the comment, I'm going to fix that.

By being able to disable each precision you mean a compilation flag? Or runtime argument?

{
typedef Complex<Real> C;

// Create a 2d process grid from a communicator. In our case, it is
// mpi::COMM_WORLD. There is another constructor that allows you to
// specify the grid dimensions, Grid g( comm, r ), which creates a
// grid of height r.
Grid g( mpi::COMM_WORLD );

// Create an n x n complex distributed matrix,
// We distribute the matrix using grid 'g'.
//
// There are quite a few available constructors, including ones that
// allow you to pass in your own local buffer and to specify the
// distribution alignments (i.e., which process row and column owns the
// top-left element)
DistMatrix<C> H( n, n, g );

// Fill the matrix since we did not pass in a buffer.
//
// We will fill entry (i,j) with the complex value (i+j,i-j) so that
// the global matrix is Hermitian. However, only one triangle of the
// matrix actually needs to be filled, the symmetry can be implicit.
//
const Int localHeight = H.LocalHeight();
const Int localWidth = H.LocalWidth();
for( Int jLoc=0; jLoc<localWidth; ++jLoc )
{
// Our process owns the rows colShift:colStride:n,
// and the columns rowShift:rowStride:n
const Int j = H.GlobalCol(jLoc);
for( Int iLoc=0; iLoc<localHeight; ++iLoc )
{
const Int i = H.GlobalRow(iLoc);
H.SetLocal( iLoc, jLoc, C(i+j,i-j) );
}
}

// Make a backup of H before we overwrite it within the eigensolver
auto HCopy( H );

// Call the eigensolver. We first create an empty complex eigenvector
// matrix, Q[MC,MR], and an eigenvalue column vector, w[VR,* ]
//
// Optional: set blocksizes and algorithmic choices here. See the
// 'Tuning' section of the README for details.
DistMatrix<Real,VR,STAR> w( g );
DistMatrix<C> Q( g );
HermitianEig( LOWER, H, w, Q );

if( print )
{
Print( HCopy, "H" );
Print( Q, "Q" );
Print( w, "w" );
}

// Check the residual, || H Q - Omega Q ||_F
const Real frobH = HermitianFrobeniusNorm( LOWER, HCopy );
auto E( Q );
DiagonalScale( RIGHT, NORMAL, w, E );
Hemm( LEFT, LOWER, C(-1), HCopy, Q, C(1), E );
const Real frobResid = FrobeniusNorm( E );

// Check the orthogonality of Q
Identity( E, n, n );
Herk( LOWER, ADJOINT, Real(-1), Q, Real(1), E );
const Real frobOrthog = HermitianFrobeniusNorm( LOWER, E );

if( mpi::Rank() == 0 )
Output
("|| H ||_F = ",frobH,"\n",
"|| H Q - Q Omega ||_F / || A ||_F = ",frobResid/frobH,"\n",
"|| Q' Q - I ||_F = ",frobOrthog,"\n");
}


int
main( int argc, char* argv[] )
Expand All @@ -27,80 +103,14 @@ main( int argc, char* argv[] )
{
const Int n = Input("--size","size of matrix",100);
const bool print = Input("--print","print matrices?",false);
const bool single_precision = Input("--single", "single precision?", false);
ProcessInput();
PrintInputReport();

// Create a 2d process grid from a communicator. In our case, it is
// mpi::COMM_WORLD. There is another constructor that allows you to
// specify the grid dimensions, Grid g( comm, r ), which creates a
// grid of height r.
Grid g( mpi::COMM_WORLD );

// Create an n x n complex distributed matrix,
// We distribute the matrix using grid 'g'.
//
// There are quite a few available constructors, including ones that
// allow you to pass in your own local buffer and to specify the
// distribution alignments (i.e., which process row and column owns the
// top-left element)
DistMatrix<C> H( n, n, g );

// Fill the matrix since we did not pass in a buffer.
//
// We will fill entry (i,j) with the complex value (i+j,i-j) so that
// the global matrix is Hermitian. However, only one triangle of the
// matrix actually needs to be filled, the symmetry can be implicit.
//
const Int localHeight = H.LocalHeight();
const Int localWidth = H.LocalWidth();
for( Int jLoc=0; jLoc<localWidth; ++jLoc )
{
// Our process owns the rows colShift:colStride:n,
// and the columns rowShift:rowStride:n
const Int j = H.GlobalCol(jLoc);
for( Int iLoc=0; iLoc<localHeight; ++iLoc )
{
const Int i = H.GlobalRow(iLoc);
H.SetLocal( iLoc, jLoc, C(i+j,i-j) );
}
if(single_precision) {
run_example<float>(n, print);
} else {
run_example<double>(n, print);
}

// Make a backup of H before we overwrite it within the eigensolver
auto HCopy( H );

// Call the eigensolver. We first create an empty complex eigenvector
// matrix, Q[MC,MR], and an eigenvalue column vector, w[VR,* ]
//
// Optional: set blocksizes and algorithmic choices here. See the
// 'Tuning' section of the README for details.
DistMatrix<Real,VR,STAR> w( g );
DistMatrix<C> Q( g );
HermitianEig( LOWER, H, w, Q );

if( print )
{
Print( HCopy, "H" );
Print( Q, "Q" );
Print( w, "w" );
}

// Check the residual, || H Q - Omega Q ||_F
const Real frobH = HermitianFrobeniusNorm( LOWER, HCopy );
auto E( Q );
DiagonalScale( RIGHT, NORMAL, w, E );
Hemm( LEFT, LOWER, C(-1), HCopy, Q, C(1), E );
const Real frobResid = FrobeniusNorm( E );

// Check the orthogonality of Q
Identity( E, n, n );
Herk( LOWER, ADJOINT, Real(-1), Q, Real(1), E );
const Real frobOrthog = HermitianFrobeniusNorm( LOWER, E );

if( mpi::Rank() == 0 )
Output
("|| H ||_F = ",frobH,"\n",
"|| H Q - Q Omega ||_F / || A ||_F = ",frobResid/frobH,"\n",
"|| Q' Q - I ||_F = ",frobOrthog,"\n");
}
catch( exception& e ) { ReportException(e); }

Expand Down
24 changes: 18 additions & 6 deletions external/pmrrr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
# http://opensource.org/licenses/BSD-2-Clause
#

# Create a set of defines for including in templated code
set(pmrrr_defines "\n")

option(HAVE_SPINLOCKS "Enable if pthread lib supports spinlocks" OFF)
MARK_AS_ADVANCED(HAVE_SPINLOCKS)
if(NOT HAVE_SPINLOCKS)
add_definitions(-DNOSPINLOCKS)
set(pmrrr_defines "${pmrrr_defines}#define NOSPINLOCKS\n")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason for this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those defines have been used as a flag to build PMR^3 as a library. Now most of the code (and 100% of code relying on availability of pthreads and spinlocks) have been moved to templated code included by Elemental. To make configuration flags available, I changed one of PMR^3 headers to a CMake configuration file, installed in both build and install directory.

That's why those flags are accumulated and used for configuration of the header, not passed directly to compiler.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the detailed reply; though it seems it would be more usual to use cmakedefine within the configure file rather than explicit string includes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I didn't know about that feature.

endif()

# Include the header directory
Expand All @@ -24,9 +27,6 @@ include_directories(BEFORE "${CMAKE_CURRENT_SOURCE_DIR}/include")

# Define the header files installation rules
# ------------------------------------------
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.h")
if(WIN32 OR APPLE OR NOT EL_HYBRID)
# Disable for Windows because of lack of POSIX support;
# disable for Mac OS X because of deprecation of unnamed semaphores
Expand All @@ -36,9 +36,21 @@ else()
option(DISABLE_PTHREADS "Disable pthreads?" OFF)
endif()
if(DISABLE_PTHREADS)
add_definitions(-DDISABLE_PTHREADS)
set(pmrrr_defines "${pmrrr_defines}#define DISABLE_PTHREADS\n")
endif()

#Build directory
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/global.h.in"
"${PROJECT_BINARY_DIR}/include/pmrrr/definitions/global.h"
@ONLY)
#Install directory
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/global.h.in"
"${CMAKE_INSTALL_INCLUDEDIR}/pmrrr/definitions/lobal.h"
@ONLY)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp")

# Ensure that an MPI C compiler was found
if(NOT MPI_C_FOUND)
message(FATAL_ERROR "No MPI C compiler was found, so PMRRR cannot be built")
Expand Down Expand Up @@ -74,7 +86,7 @@ set(CMAKE_THREAD_LIBS_INIT ${CMAKE_THREAD_LIBS_INIT} PARENT_SCOPE)

# Define the main library and its link libraries
# ----------------------------------------------
file(GLOB_RECURSE PMRRR_SRC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.c" "*.h")
file(GLOB_RECURSE PMRRR_SRC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp" "*.h")
add_library(pmrrr ${LIBRARY_TYPE} ${PMRRR_SRC})
if(DISABLE_PTHREADS)
target_link_libraries(pmrrr ${MPI_C_LIBRARIES} ${MATH_LIBS})
Expand Down
30 changes: 0 additions & 30 deletions external/pmrrr/LICENSE

This file was deleted.

Loading