├── sanitizers └── lsan.blacklist ├── figures └── anr_nonlocaldd.png ├── .github └── codecov.yml ├── include └── htool │ ├── matrix │ ├── utils.hpp │ ├── linalg.hpp │ ├── linalg │ │ ├── scale.hpp │ │ └── transpose.hpp │ ├── utils │ │ ├── math.hpp │ │ ├── modifiers.hpp │ │ ├── SVD_truncation.hpp │ │ └── output.hpp │ └── matrix_view.hpp │ ├── hmatrix │ ├── linalg.hpp │ ├── lrmat │ │ ├── linalg.hpp │ │ ├── linalg │ │ │ ├── scale.hpp │ │ │ ├── add_lrmat_vector_product.hpp │ │ │ └── add_lrmat_matrix_product_row_major.hpp │ │ └── recompressed_low_rank_generator.hpp │ ├── interfaces │ │ ├── virtual_dense_blocks_generator.hpp │ │ ├── virtual_admissibility_condition.hpp │ │ ├── virtual_generator.hpp │ │ └── virtual_lrmat_generator.hpp │ ├── linalg │ │ ├── triangular_hmatrix_lrmat_solve.hpp │ │ └── scale.hpp │ ├── hmatrix_tree_data.hpp │ ├── utils │ │ └── recompression.hpp │ └── execution_policies.hpp │ ├── distributed_operator │ ├── linalg.hpp │ ├── linalg │ │ ├── add_distributed_operator_vector_sub_product_global_to_local.hpp │ │ └── utility.hpp │ ├── interfaces │ │ ├── virtual_partition.hpp │ │ ├── virtual_local_to_local_operator.hpp │ │ └── virtual_global_to_local_operator.hpp │ ├── implementations │ │ ├── partition_from_cluster.hpp │ │ └── global_to_local_operators │ │ │ ├── hmatrix.hpp │ │ │ └── dense_matrix.hpp │ └── local_renumbering.hpp │ ├── misc │ ├── define.hpp │ ├── petsc.hpp │ ├── user.hpp │ ├── misc.hpp │ └── logger.hpp │ ├── solvers │ ├── interfaces │ │ ├── virtual_coarse_space_builder.hpp │ │ ├── virtual_coarse_operator_builder.hpp │ │ └── virtual_local_solver.hpp │ └── local_solvers │ │ └── local_dense_solvers.hpp │ ├── clustering │ ├── interfaces │ │ └── virtual_partitioning.hpp │ └── cluster_tree_data.hpp │ ├── htool_version.hpp │ ├── testing │ ├── dense_blocks_generator_test.hpp │ ├── gmsh.hpp │ └── geometry.hpp │ ├── htool.hpp │ └── wrappers │ └── wrapper_mpi.hpp ├── cmake ├── HtoolConfig.cmake.in └── version.cmake ├── .clang-format ├── tests ├── CMakeLists.txt └── functional_tests │ ├── hmatrix │ ├── task_based │ │ ├── CMakeLists.txt │ │ └── test_task_based_hmatrix_dependencies.cpp │ ├── lrmat │ │ ├── lrmat_addition │ │ │ ├── CMakeLists.txt │ │ │ ├── test_lrmat_addition_double.cpp │ │ │ └── test_lrmat_addition_complex_double.cpp │ │ ├── lrmat_product │ │ │ ├── CMakeLists.txt │ │ │ ├── test_lrmat_product_double.cpp │ │ │ └── test_lrmat_product_complex_double.cpp │ │ ├── CMakeLists.txt │ │ ├── lrmat_build │ │ │ ├── CMakeLists.txt │ │ │ └── test_lrmat_build_partialACA.cpp │ │ ├── test_matrix_matrix_product.hpp │ │ ├── test_matrix_lrmat_product.hpp │ │ └── test_lrmat_lrmat_product.hpp │ ├── hmatrix_addition │ │ ├── CMakeLists.txt │ │ ├── test_hmatrix_addition_double.cpp │ │ └── test_hmatrix_addition_complex_double.cpp │ ├── hmatrix_factorization │ │ ├── test_hmatrix_factorization_double.cpp │ │ ├── test_hmatrix_factorization_complex_double.cpp │ │ ├── CMakeLists.txt │ │ ├── test_task_based_hmatrix_factorization_double.cpp │ │ └── test_task_based_hmatrix_factorization_complex_double.cpp │ ├── hmatrix_triangular_solve │ │ ├── test_hmatrix_triangular_solve_double.cpp │ │ ├── test_hmatrix_triangular_solve_complex_double.cpp │ │ ├── CMakeLists.txt │ │ ├── test_task_based_hmatrix_triangular_solve_double.cpp │ │ └── test_task_based_hmatrix_triangular_solve_complex_double.cpp │ ├── CMakeLists.txt │ ├── hmatrix_builder │ │ ├── test_hmatrix_builder_double.cpp │ │ ├── CMakeLists.txt │ │ └── test_hmatrix_builder_complex_double.cpp │ ├── hmatrix_product │ │ ├── test_hmatrix_product_double.cpp │ │ ├── CMakeLists.txt │ │ └── test_hmatrix_product_complex_double.cpp │ ├── hmatrix_build │ │ ├── test_task_based_hmatrix_build_double.cpp │ │ ├── test_task_based_hmatrix_build_complex_double.cpp │ │ ├── CMakeLists.txt │ │ └── test_hmatrix_build_double.cpp │ └── test_lrmat_hmatrix_addition.hpp │ ├── misc │ ├── CMakeLists.txt │ └── test_logger.cpp │ ├── geometry │ ├── CMakeLists.txt │ └── test_geometry_file.cpp │ ├── local_operators │ ├── local_dense_operator_product │ │ ├── CMakeLists.txt │ │ └── test_local_operator_dense_matrix_product.cpp │ ├── CMakeLists.txt │ └── test_local_operator_dense_matrix.cpp │ ├── matrix │ ├── matrix_product │ │ ├── CMakeLists.txt │ │ ├── test_matrix_product_double.cpp │ │ └── test_matrix_product_complex_double.cpp │ ├── matrix_factorization │ │ ├── CMakeLists.txt │ │ ├── test_matrix_factorization_double.cpp │ │ └── test_matrix_factorization_complex_double.cpp │ ├── matrix_triangular_solve │ │ ├── CMakeLists.txt │ │ ├── test_matrix_triangular_solve_double.cpp │ │ └── test_matrix_triangular_solve_complex_double.cpp │ ├── CMakeLists.txt │ ├── test_matrix_file.cpp │ └── test_matrix_factorization.hpp │ ├── basic_types │ ├── CMakeLists.txt │ └── test_basic_types_vector_file.cpp │ ├── CMakeLists.txt │ ├── distributed_operator │ ├── CMakeLists.txt │ └── test_distributed_operator_product_double.cpp │ ├── clustering │ └── CMakeLists.txt │ └── solvers │ ├── CMakeLists.txt │ └── test_solver_complex_double.cpp ├── examples ├── use_ddm_solver.sh ├── use_hmatrix.sh ├── use_clustering.sh ├── use_distributed_operator.sh ├── compression_comparison.sh ├── CMakeLists.txt └── use_clustering.cpp ├── cmake_modules └── FindHPDDM.cmake ├── .gitignore ├── doc └── CMakeLists.txt ├── tools ├── plot_comparison_compression.py ├── plot_cluster.py └── plot_hmatrix.py ├── README.md ├── LICENSE └── CONTRIBUTING.md /sanitizers/lsan.blacklist: -------------------------------------------------------------------------------- 1 | leak:mpich -------------------------------------------------------------------------------- /figures/anr_nonlocaldd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/htool-ddm/htool/HEAD/figures/anr_nonlocaldd.png -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | fixes: 2 | # - "before/::after/" # move path e.g., "before/path" => "after/path" 3 | # - "::after/" # move root e.g., "path/" => "after/path/" 4 | - "htool/::" # reduce root e.g., "before/path/" => "path/" 5 | -------------------------------------------------------------------------------- /include/htool/matrix/utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_MATRIX_UTILS_HPP 2 | #define HTOOL_MATRIX_UTILS_HPP 3 | 4 | #include "utils/SVD_truncation.hpp" 5 | #include "utils/math.hpp" 6 | #include "utils/modifiers.hpp" 7 | #include "utils/output.hpp" 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/htool/hmatrix/linalg.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_HMATRIX_LINALG_HPP 2 | #define HTOOL_HMATRIX_LINALG_HPP 3 | 4 | #include "linalg/add_hmatrix_matrix_product.hpp" 5 | #include "linalg/add_hmatrix_vector_product.hpp" 6 | #include "linalg/factorization.hpp" 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /cmake/HtoolConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include(CMakeFindDependencyMacro) 4 | find_package(BLAS REQUIRED) 5 | find_package(LAPACK) 6 | find_package(OpenMP) 7 | find_package(MPI) 8 | 9 | include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") 10 | check_required_components("@PROJECT_NAME@") 11 | -------------------------------------------------------------------------------- /include/htool/distributed_operator/linalg.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_DISTRIBUTED_OPERATOR_LINALG_HPP 2 | #define HTOOL_DISTRIBUTED_OPERATOR_LINALG_HPP 3 | 4 | #include "linalg/add_distributed_operator_matrix_product_global_to_global.hpp" 5 | #include "linalg/add_distributed_operator_vector_product_global_to_global.hpp" 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | Language: Cpp 3 | Standard: Cpp11 4 | IndentWidth: 4 5 | BinPackParameters: false 6 | BinPackArguments: false 7 | IndentPPDirectives: AfterHash 8 | AlwaysBreakTemplateDeclarations: true 9 | BreakBeforeBinaryOperators: NonAssignment 10 | AlignConsecutiveAssignments: Consecutive 11 | ColumnLimit: 0 12 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(functional_tests) 2 | 3 | # add_executable(Test_warnings test_warnings.cpp) 4 | # target_link_libraries(Test_warnings htool) 5 | # target_compile_options(Test_warnings PRIVATE -Werror -Wall -Wextra -Wno-sign-compare) 6 | # add_test(Test_warnings Test_warnings) 7 | # add_dependencies(build-tests Test_warnings) 8 | -------------------------------------------------------------------------------- /examples/use_ddm_solver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Initialization 4 | MY_PATH="`dirname \"$0\"`" 5 | MY_PATH="`( cd \"$MY_PATH\" && pwd )`" 6 | cd ${MY_PATH} 7 | cd ../ 8 | mkdir -p build & cd build 9 | cmake ../ 10 | make Use_ddm_solver 11 | mkdir -p ../output/examples/use_ddm_solver 12 | 13 | # Run 14 | mpirun -np 4 ./examples/Use_ddm_solver 15 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/task_based/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(Test_task_based_hmatrix_dependencies test_task_based_hmatrix_dependencies.cpp) 2 | target_link_libraries(Test_task_based_hmatrix_dependencies htool) 3 | add_dependencies(build-tests-hmatrix Test_task_based_hmatrix_dependencies) 4 | add_test(Test_task_based_hmatrix_dependencies Test_task_based_hmatrix_dependencies) 5 | -------------------------------------------------------------------------------- /include/htool/matrix/linalg.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_MATRIX_LINALG_HPP 2 | #define HTOOL_MATRIX_LINALG_HPP 3 | 4 | #include "linalg/add_matrix_matrix_product.hpp" 5 | #include "linalg/add_matrix_matrix_product_row_major.hpp" 6 | #include "linalg/add_matrix_vector_product.hpp" 7 | #include "linalg/factorization.hpp" 8 | #include "linalg/scale.hpp" 9 | #include "linalg/transpose.hpp" 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /tests/functional_tests/misc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | add_executable(Test_logger test_logger.cpp) 6 | target_link_libraries(Test_logger htool) 7 | add_dependencies(build-tests-misc Test_logger) 8 | add_test(Test_logger Test_logger) 9 | -------------------------------------------------------------------------------- /include/htool/hmatrix/lrmat/linalg.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_HMATRIX_LRMAT_LINALG_HPP 2 | #define HTOOL_HMATRIX_LRMAT_LINALG_HPP 3 | 4 | #include "linalg/add_lrmat_lrmat_product.hpp" 5 | #include "linalg/add_lrmat_matrix_product.hpp" 6 | #include "linalg/add_lrmat_matrix_product_row_major.hpp" 7 | #include "linalg/add_lrmat_vector_product.hpp" 8 | #include "linalg/add_matrix_lrmat_product.hpp" 9 | #include "linalg/add_matrix_matrix_product.hpp" 10 | #include "linalg/scale.hpp" 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /include/htool/matrix/linalg/scale.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_MATRIX_LINALG_SCALE_HPP 2 | #define HTOOL_MATRIX_LINALG_SCALE_HPP 3 | 4 | #include "../../matrix/matrix.hpp" // for Matrix 5 | #include "../../wrappers/wrapper_blas.hpp" // for Blas 6 | 7 | namespace htool { 8 | 9 | template 10 | void scale(T da, Matrix &A) { 11 | int size = A.nb_cols() * A.nb_rows(); 12 | int incx = 1; 13 | Blas::scal(&size, &da, A.data(), &incx); 14 | } 15 | 16 | } // namespace htool 17 | #endif 18 | -------------------------------------------------------------------------------- /include/htool/misc/define.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_DEFINE_HPP 2 | #define HTOOL_DEFINE_HPP 3 | 4 | /* Constants: C-style preprocessor variables 5 | * 6 | * HTOOL_MKL - If not set to zero, Intel MKL is chosen as the linear algebra backend. */ 7 | 8 | #if defined(PETSC_HAVE_MKL_LIBS) && !defined(HTOOL_MKL) 9 | # define HTOOL_MKL 1 10 | #endif 11 | #ifndef HTOOL_MKL 12 | # ifdef INTEL_MKL_VERSION 13 | # define HTOOL_MKL 1 14 | # else 15 | # define HTOOL_MKL 0 16 | # endif 17 | #endif 18 | #endif 19 | -------------------------------------------------------------------------------- /include/htool/solvers/interfaces/virtual_coarse_space_builder.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_VIRTUAL_COARSE_SPACE_BUILDER_HPP 2 | #define HTOOL_VIRTUAL_COARSE_SPACE_BUILDER_HPP 3 | 4 | #include "htool/matrix/matrix.hpp" // for Matrix 5 | 6 | namespace htool { 7 | 8 | template 9 | class VirtualCoarseSpaceBuilder { 10 | public: 11 | virtual Matrix build_coarse_space() = 0; 12 | virtual ~VirtualCoarseSpaceBuilder() {} 13 | }; 14 | 15 | } // namespace htool 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /examples/use_hmatrix.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Initialization 4 | MY_PATH="`dirname \"$0\"`" 5 | MY_PATH="`( cd \"$MY_PATH\" && pwd )`" 6 | cd ${MY_PATH} 7 | cd ../ 8 | mkdir -p build & cd build 9 | cmake ../ 10 | make Use_hmatrix 11 | mkdir -p ../output/examples/use_hmatrix 12 | 13 | # Arguments 14 | outputfolder=../output/examples/use_hmatrix/ 15 | 16 | # Run 17 | ./examples/Use_hmatrix ${outputfolder} 18 | 19 | # Display output 20 | python3 ../tools/plot_hmatrix.py --inputfile ../output/examples/use_hmatrix/hmatrix.csv 21 | -------------------------------------------------------------------------------- /tests/functional_tests/geometry/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | add_executable(Test_geometry_file test_geometry_file.cpp) 6 | target_link_libraries(Test_geometry_file htool) 7 | add_dependencies(build-tests Test_geometry_file) 8 | add_test(NAME Test_geometry_file COMMAND Test_geometry_file ${CMAKE_SOURCE_DIR}/data/data_test/gmsh_test.msh) 9 | -------------------------------------------------------------------------------- /examples/use_clustering.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Initialization 4 | MY_PATH="`dirname \"$0\"`" 5 | MY_PATH="`( cd \"$MY_PATH\" && pwd )`" 6 | cd ${MY_PATH} 7 | cd ../ 8 | mkdir -p build & cd build 9 | cmake ../ 10 | make Use_clustering 11 | mkdir -p ../output/examples/use_clustering 12 | 13 | # Arguments 14 | outputfolder=../output/examples/use_clustering/ 15 | 16 | # Run 17 | ./examples/Use_clustering ${outputfolder} 18 | 19 | # Display output 20 | python3 ../tools/plot_cluster.py --inputfile ../output/examples/use_clustering/clustering_output.csv --depth 2 21 | -------------------------------------------------------------------------------- /include/htool/solvers/interfaces/virtual_coarse_operator_builder.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_VIRTUAL_OPERATOR_SPACE_BUILDER_HPP 2 | #define HTOOL_VIRTUAL_OPERATOR_SPACE_BUILDER_HPP 3 | 4 | #include "../../matrix/matrix.hpp" 5 | 6 | namespace htool { 7 | 8 | template 9 | class VirtualCoarseOperatorBuilder { 10 | public: 11 | virtual Matrix build_coarse_operator(int nb_rows, int nb_cols, CoefficientPrecision **Z) = 0; 12 | virtual ~VirtualCoarseOperatorBuilder() {} 13 | }; 14 | 15 | } // namespace htool 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /include/htool/hmatrix/lrmat/linalg/scale.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_LRMAT_LINALG_SCALE_HPP 2 | #define HTOOL_LRMAT_LINALG_SCALE_HPP 3 | 4 | #include "../../../matrix/linalg/scale.hpp" 5 | #include "../lrmat.hpp" 6 | namespace htool { 7 | 8 | template 9 | void scale(CoefficientPrecision da, LowRankMatrix &lrmat) { 10 | if (lrmat.get_U().nb_rows() <= lrmat.get_V().nb_cols()) { 11 | scale(da, lrmat.get_U()); 12 | } else { 13 | scale(da, lrmat.get_V()); 14 | } 15 | } 16 | 17 | } // namespace htool 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /include/htool/matrix/linalg/transpose.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_MATRIX_LINALG_TRANSPOSE_HPP 2 | #define HTOOL_MATRIX_LINALG_TRANSPOSE_HPP 3 | 4 | namespace htool { 5 | 6 | template ::value>> 10 | void transpose(const MatA &A, MatB &B) { 11 | for (int i = 0; i < A.nb_rows(); i++) { 12 | for (int j = 0; j < A.nb_cols(); j++) { 13 | B(j, i) = A(i, j); 14 | } 15 | } 16 | } 17 | 18 | } // namespace htool 19 | #endif 20 | -------------------------------------------------------------------------------- /examples/use_distributed_operator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Initialization 4 | MY_PATH="`dirname \"$0\"`" 5 | MY_PATH="`( cd \"$MY_PATH\" && pwd )`" 6 | cd ${MY_PATH} 7 | cd ../ 8 | mkdir -p build & cd build 9 | cmake ../ 10 | make Use_distributed_operator 11 | mkdir -p ../output/examples/use_distributed_operator 12 | 13 | # Arguments 14 | outputfolder=../output/examples/use_distributed_operator/ 15 | 16 | # Run 17 | mpirun -np 4 ./examples/Use_distributed_operator ${outputfolder} 18 | 19 | # Display output 20 | python3 ../tools/plot_hmatrix.py --inputfile ../output/examples/use_distributed_operator/local_hmatrix_0.csv 21 | -------------------------------------------------------------------------------- /include/htool/hmatrix/interfaces/virtual_dense_blocks_generator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_HMATRIX_VIRTUAL_DENSE_GENERATOR_HPP 2 | #define HTOOL_HMATRIX_VIRTUAL_DENSE_GENERATOR_HPP 3 | 4 | #include // for vector 5 | 6 | namespace htool { 7 | 8 | template 9 | class VirtualDenseBlocksGenerator { 10 | public: 11 | // C style 12 | virtual void copy_dense_blocks(const std::vector &M, const std::vector &N, const std::vector &rows, const std::vector &cols, std::vector &ptr) const = 0; 13 | 14 | virtual ~VirtualDenseBlocksGenerator() {} 15 | }; 16 | 17 | } // namespace htool 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /tests/functional_tests/local_operators/local_dense_operator_product/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | add_executable(Test_local_operator_dense_matrix_product test_local_operator_dense_matrix_product.cpp) 6 | target_link_libraries(Test_local_operator_dense_matrix_product htool) 7 | add_dependencies(build-tests-local-operators-dense-product Test_local_operator_dense_matrix_product) 8 | add_test(Test_local_operator_dense_matrix_product Test_local_operator_dense_matrix_product) 9 | -------------------------------------------------------------------------------- /tests/functional_tests/local_operators/local_dense_operator_product/test_local_operator_dense_matrix_product.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_local_operator_dense_matrix.hpp" 2 | 3 | using namespace std; 4 | using namespace htool; 5 | 6 | int main(int argc, char *argv[]) { 7 | MPI_Init(&argc, &argv); 8 | 9 | bool is_error = false; 10 | const int number_of_rows = 200; 11 | const int number_of_rows_increased = 400; 12 | const int number_of_columns = 200; 13 | const int number_of_columns_increased = 400; 14 | const int number_of_right_hand_side = 5; 15 | 16 | if (is_error) { 17 | return 1; 18 | } 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/lrmat/lrmat_addition/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | set(types "double") 5 | list(APPEND types "complex_double") 6 | 7 | foreach(type ${types}) 8 | add_executable(Test_lrmat_addition_${type} test_lrmat_addition_${type}.cpp) 9 | target_link_libraries(Test_lrmat_addition_${type} htool) 10 | add_dependencies(build-tests-lrmat Test_lrmat_addition_${type}) 11 | add_test(Test_lrmat_addition_${type} Test_lrmat_addition_${type}) 12 | endforeach() 13 | -------------------------------------------------------------------------------- /tests/functional_tests/matrix/matrix_product/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | set(types "double") 6 | list(APPEND types "complex_double") 7 | 8 | foreach(type ${types}) 9 | add_executable(Test_matrix_product_${type} test_matrix_product_${type}.cpp) 10 | target_link_libraries(Test_matrix_product_${type} htool) 11 | add_dependencies(build-tests-matrix-product Test_matrix_product_${type}) 12 | add_test(Test_matrix_product_${type} Test_matrix_product_${type}) 13 | endforeach() 14 | -------------------------------------------------------------------------------- /cmake_modules/FindHPDDM.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Try to find HPDDM library and include path. 3 | # Once done this will define 4 | # 5 | # HPDDM_FOUND 6 | # HPDDM_INCLUDE_DIR 7 | # 8 | 9 | FIND_PATH( 10 | HPDDM_INCLUDE_DIR 11 | NAMES HPDDM.hpp 12 | PATHS 13 | ${CMAKE_CURRENT_SOURCE_DIR}/../hpddm/include 14 | ) 15 | 16 | # Handle the QUIETLY and REQUIRED arguments and set the HPDDM_FOUND to TRUE 17 | # if all listed variables are TRUE 18 | include(FindPackageHandleStandardArgs) 19 | find_package_handle_standard_args(HPDDM DEFAULT_MSG 20 | HPDDM_INCLUDE_DIR) 21 | 22 | mark_as_advanced(HPDDM_INCLUDE_DIR) 23 | 24 | if (HPDDM_FOUND) 25 | set(HPDDM_INCLUDE_DIRS ${HPDDM_INCLUDE_DIR} ) 26 | endif() 27 | -------------------------------------------------------------------------------- /include/htool/clustering/interfaces/virtual_partitioning.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_CLUSTERING_VIRTUAL_PARTITIONING_HPP 2 | #define HTOOL_CLUSTERING_VIRTUAL_PARTITIONING_HPP 3 | 4 | #include "../cluster_node.hpp" // for Cluster 5 | 6 | namespace htool { 7 | 8 | template 9 | class VirtualPartitioning { 10 | public: 11 | virtual std::vector> compute_partitioning(Cluster ¤t_cluster, int spatial_dimension, const CoordinatePrecision *coordinates, const CoordinatePrecision *const radii, const CoordinatePrecision *const weights, int number_of_partitions) = 0; 12 | 13 | virtual ~VirtualPartitioning() {} 14 | }; 15 | 16 | } // namespace htool 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /tests/functional_tests/local_operators/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | add_executable(Test_local_operator_dense_matrix test_local_operator_dense_matrix.cpp) 6 | target_link_libraries(Test_local_operator_dense_matrix htool) 7 | add_dependencies(build-tests-local-operators Test_local_operator_dense_matrix) 8 | add_test(Test_local_operator_dense_matrix Test_local_operator_dense_matrix) 9 | 10 | add_custom_target(build-tests-local-operators-dense-product) 11 | add_subdirectory(local_dense_operator_product) 12 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_addition/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | set(types "double") 6 | list(APPEND types "complex_double") 7 | 8 | foreach(type ${types}) 9 | add_executable(Test_hmatrix_addition_${type} test_hmatrix_addition_${type}.cpp) 10 | target_link_libraries(Test_hmatrix_addition_${type} htool) 11 | add_dependencies(build-tests-hmatrix-addition Test_hmatrix_addition_${type}) 12 | add_test(Test_hmatrix_addition_${type}_1 Test_hmatrix_addition_${type}) 13 | endforeach() 14 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/lrmat/lrmat_product/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | #=== lrmat_SVD 6 | set(types "double") 7 | list(APPEND types "complex_double") 8 | 9 | foreach(type ${types}) 10 | add_executable(Test_lrmat_product_${type} test_lrmat_product_${type}.cpp) 11 | target_link_libraries(Test_lrmat_product_${type} htool) 12 | add_dependencies(build-tests-lrmat-product Test_lrmat_product_${type}) 13 | add_test(Test_lrmat_product_${type} Test_lrmat_product_${type}) 14 | endforeach() 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dotfiles 2 | .* 3 | !.gitignore 4 | !.clang-format 5 | !.clang-tidy 6 | !.devcontainer 7 | !.github 8 | 9 | # Compiled Object files 10 | *.slo 11 | *.lo 12 | *.o 13 | *.obj 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Compiled Dynamic libraries 20 | *.so 21 | *.dylib 22 | *.dll 23 | 24 | # Fortran module files 25 | *.mod 26 | *.smod 27 | 28 | # Compiled Static libraries 29 | *.lai 30 | *.la 31 | *.a 32 | *.lib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | 39 | # Builds 40 | build*/ 41 | bin*/ 42 | 43 | # Temporary files 44 | *~ 45 | *.DS_Store 46 | 47 | # VScode 48 | .vscode 49 | 50 | # Output 51 | output/* 52 | 53 | # mesh 54 | *.msh 55 | 56 | # Python 57 | __pycache__ 58 | *.egg-info 59 | -------------------------------------------------------------------------------- /examples/compression_comparison.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Initialization 4 | MY_PATH="`dirname \"$0\"`" 5 | MY_PATH="`( cd \"$MY_PATH\" && pwd )`" 6 | cd ${MY_PATH} 7 | cd ../ 8 | mkdir -p build & cd build 9 | cmake ../ 10 | make Compression_comparison 11 | mkdir -p ../output/examples/compression_comparison 12 | 13 | # Arguments 14 | outputfolder=../output/examples/compression_comparison/ 15 | distances=(1 2 3) 16 | 17 | # Run 18 | for distance in "${distances[@]}" 19 | do 20 | ./examples/compression_comparison ${distance} compression_comparison_${distance}.csv ${outputfolder} 21 | done 22 | 23 | 24 | # python3 ../tools/plot_comparison_compression.py --inputfile ../output/examples/compression_comparison/compression_comparison_1.csv 25 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/lrmat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | add_custom_target(build-tests-lrmat-build) 6 | add_dependencies(build-tests-lrmat build-tests-lrmat-build) 7 | add_subdirectory(lrmat_build) 8 | 9 | add_custom_target(build-tests-lrmat-product) 10 | add_dependencies(build-tests-lrmat build-tests-lrmat-product) 11 | add_subdirectory(lrmat_product) 12 | 13 | add_custom_target(build-tests-lrmat-addition) 14 | add_dependencies(build-tests-lrmat build-tests-lrmat-addition) 15 | add_subdirectory(lrmat_addition) 16 | -------------------------------------------------------------------------------- /tests/functional_tests/matrix/matrix_factorization/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | set(types "double") 6 | list(APPEND types "complex_double") 7 | 8 | foreach(type ${types}) 9 | add_executable(Test_matrix_factorization_${type} test_matrix_factorization_${type}.cpp) 10 | target_link_libraries(Test_matrix_factorization_${type} htool) 11 | add_dependencies(build-tests-matrix-factorization Test_matrix_factorization_${type}) 12 | add_test(Test_matrix_factorization_${type} Test_matrix_factorization_${type}) 13 | endforeach() 14 | -------------------------------------------------------------------------------- /tests/functional_tests/matrix/matrix_triangular_solve/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | set(types "double") 6 | list(APPEND types "complex_double") 7 | 8 | foreach(type ${types}) 9 | add_executable(Test_matrix_triangular_solve_${type} test_matrix_triangular_solve_${type}.cpp) 10 | target_link_libraries(Test_matrix_triangular_solve_${type} htool) 11 | add_dependencies(build-tests-matrix-triangular-solve Test_matrix_triangular_solve_${type}) 12 | add_test(Test_matrix_triangular_solve_${type} Test_matrix_triangular_solve_${type}) 13 | endforeach() 14 | -------------------------------------------------------------------------------- /tests/functional_tests/basic_types/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | add_executable(Test_basic_types_vector test_basic_types_vector.cpp) 6 | target_link_libraries(Test_basic_types_vector htool) 7 | add_dependencies(build-tests-basic-types Test_basic_types_vector) 8 | add_test(Test_basic_types_vector Test_basic_types_vector) 9 | 10 | add_executable(Test_basic_types_vector_file test_basic_types_vector_file.cpp) 11 | target_link_libraries(Test_basic_types_vector_file htool) 12 | add_dependencies(build-tests-basic-types Test_basic_types_vector_file) 13 | add_test(Test_basic_types_vector_file Test_basic_types_vector_file) 14 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/lrmat/lrmat_build/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | #=== lrmat_SVD 6 | set(compressions "fullACA") 7 | list(APPEND compressions "partialACA") 8 | list(APPEND compressions "recompressed_partialACA") 9 | list(APPEND compressions "sympartialACA") 10 | list(APPEND compressions "SVD") 11 | foreach(compression ${compressions}) 12 | add_executable(Test_lrmat_build_${compression} test_lrmat_build_${compression}.cpp) 13 | target_link_libraries(Test_lrmat_build_${compression} htool) 14 | add_dependencies(build-tests-lrmat-build Test_lrmat_build_${compression}) 15 | add_test(Test_lrmat_build_${compression} Test_lrmat_build_${compression}) 16 | endforeach() 17 | -------------------------------------------------------------------------------- /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Doxygen) 2 | if(NOT DOXYGEN_FOUND) 3 | message("Doxygen not found, I will not generate/install the documentation") 4 | else() 5 | # set input and output files 6 | set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) 7 | set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) 8 | 9 | # request to configure the file 10 | configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY) 11 | message("Doxygen build started") 12 | 13 | # note the option ALL which allows to build the docs together with the application 14 | add_custom_target( 15 | doc ALL 16 | COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} 17 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 18 | COMMENT "Generating API documentation with Doxygen" 19 | VERBATIM) 20 | 21 | #install(DIRECTORY ${CMAKE_BINARY_DIR}/doc/html 22 | # DESTINATION share/doc/${CMAKE_PROJECT_NAME}) 23 | 24 | endif() 25 | -------------------------------------------------------------------------------- /include/htool/matrix/utils/math.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_MATRIX_UTILS_MATH_HPP 2 | #define HTOOL_MATRIX_UTILS_MATH_HPP 3 | #include "../../misc/misc.hpp" 4 | namespace htool { 5 | 6 | template 7 | auto normFrob(const Mat &A) { 8 | using T = typename Mat::value_type; 9 | htool::underlying_type norm = 0; 10 | for (int j = 0; j < A.nb_rows(); j++) { 11 | for (int k = 0; k < A.nb_cols(); k++) { 12 | norm = norm + std::pow(std::abs(A(j, k)), 2); 13 | } 14 | } 15 | return sqrt(norm); 16 | } 17 | 18 | template 19 | std::pair argmax(const Mat &M) { 20 | using T = typename Mat::value_type; 21 | int p = std::max_element(M.data(), M.data() + M.nb_cols() * M.nb_rows(), [](T a, T b) { return std::abs(a) < std::abs(b); }) - M.data(); 22 | return std::pair(p % M.nb_rows(), p / M.nb_rows()); 23 | } 24 | 25 | } // namespace htool 26 | #endif 27 | -------------------------------------------------------------------------------- /tests/functional_tests/matrix/matrix_triangular_solve/test_matrix_triangular_solve_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_matrix_triangular_solve.hpp" 2 | 3 | using namespace std; 4 | using namespace htool; 5 | 6 | int main(int, char *[]) { 7 | 8 | bool is_error = false; 9 | const int number_of_rows = 200; 10 | 11 | for (auto number_of_rhs : {1, 100}) { 12 | for (auto side : {'L', 'R'}) { 13 | for (auto operation : {'N', 'T'}) { 14 | for (auto diag : {'N', 'U'}) { 15 | std::cout << number_of_rhs << " " << side << " " << operation << " " << diag << "\n"; 16 | // Square matrix 17 | is_error = is_error || test_matrix_triangular_solve(number_of_rows, number_of_rhs, side, operation, diag); 18 | } 19 | } 20 | } 21 | } 22 | 23 | if (is_error) { 24 | return 1; 25 | } 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /tests/functional_tests/matrix/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_custom_target(build-tests-matrix-product) 2 | add_dependencies(build-tests-matrix build-tests-matrix-product) 3 | add_subdirectory(matrix_product) 4 | 5 | add_custom_target(build-tests-matrix-triangular-solve) 6 | add_dependencies(build-tests-matrix build-tests-matrix-triangular-solve) 7 | add_subdirectory(matrix_triangular_solve) 8 | 9 | add_custom_target(build-tests-matrix-factorization) 10 | add_dependencies(build-tests-matrix build-tests-matrix-factorization) 11 | add_subdirectory(matrix_factorization) 12 | 13 | add_executable(Test_matrix test_matrix.cpp) 14 | target_link_libraries(Test_matrix htool) 15 | add_dependencies(build-tests-matrix Test_matrix) 16 | add_test(Test_matrix Test_matrix) 17 | 18 | add_executable(Test_matrix_file test_matrix_file.cpp) 19 | target_link_libraries(Test_matrix_file htool) 20 | add_dependencies(build-tests-matrix Test_matrix_file) 21 | add_test(Test_matrix_file Test_matrix_file) 22 | -------------------------------------------------------------------------------- /tests/functional_tests/matrix/matrix_factorization/test_matrix_factorization_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_matrix_factorization.hpp" // for test_matrix_cholesky 2 | #include // for initializer_list 3 | 4 | using namespace std; 5 | using namespace htool; 6 | 7 | int main(int, char *[]) { 8 | 9 | bool is_error = false; 10 | const int number_of_rows = 200; 11 | 12 | for (auto number_of_rhs : {1, 100}) { 13 | for (auto operation : {'N', 'T'}) { 14 | // Square matrix 15 | is_error = is_error || test_matrix_lu(operation, number_of_rows, number_of_rhs); 16 | } 17 | is_error = is_error || test_matrix_cholesky('N', number_of_rows, number_of_rhs, 'S', 'U'); 18 | is_error = is_error || test_matrix_cholesky('N', number_of_rows, number_of_rhs, 'S', 'L'); 19 | } 20 | 21 | if (is_error) { 22 | return 1; 23 | } 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /tests/functional_tests/geometry/test_geometry_file.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | using namespace htool; 7 | 8 | int main(int argc, char const *argv[]) { 9 | 10 | // Input file 11 | if (argc != 2) { // argc should be 2 for correct execution 12 | // We print argv[0] assuming it is the program name 13 | cout << "usage: " << argv[0] << " \n"; 14 | return 1; 15 | } 16 | 17 | bool test = 0; 18 | std::vector points; 19 | std::vector r; 20 | 21 | test = test || (Load_GMSH_nodes(points, argv[1])); 22 | test = test || !(norm2(points[0] - R3{1, 0, 0}) < 1e-16); 23 | test = test || !(norm2(points[1] - R3{0, 1, 0}) < 1e-16); 24 | test = test || !(norm2(points[2] - R3{-1, 0, 0}) < 1e-16); 25 | test = test || !(norm2(points[3] - R3{0, -1, 0}) < 1e-16); 26 | 27 | cout << test << endl; 28 | return test; 29 | } 30 | -------------------------------------------------------------------------------- /include/htool/misc/petsc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_PETSC_HPP 2 | #define HTOOL_PETSC_HPP 3 | 4 | #if defined(__clang__) 5 | # pragma clang diagnostic push 6 | # pragma clang diagnostic ignored "-Wsign-compare" 7 | #elif defined(__GNUC__) || defined(__GNUG__) 8 | # pragma GCC diagnostic push 9 | # pragma GCC diagnostic ignored "-Wsign-compare" 10 | #endif 11 | 12 | #include "define.hpp" 13 | #include "misc.hpp" 14 | 15 | #include "../clustering/clustering.hpp" 16 | #include "../distributed_operator/distributed_operator.hpp" 17 | #include "../distributed_operator/implementations/partition_from_cluster.hpp" 18 | #include "../hmatrix/hmatrix.hpp" 19 | #include "../hmatrix/lrmat/SVD.hpp" 20 | #include "../hmatrix/lrmat/fullACA.hpp" 21 | #include "../hmatrix/lrmat/lrmat.hpp" 22 | #include "../hmatrix/lrmat/sympartialACA.hpp" 23 | 24 | #if defined(__clang__) 25 | # pragma clang diagnostic pop 26 | #elif defined(__GNUC__) || defined(__GNUG__) 27 | # pragma GCC diagnostic pop 28 | #endif 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /tools/plot_comparison_compression.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from mpl_toolkits.mplot3d import Axes3D 3 | import matplotlib.pyplot as plt 4 | import matplotlib.colors as colors 5 | import pandas as pd 6 | import argparse 7 | 8 | # Input 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument("--inputfile",type=str) 11 | parser.add_argument("--show",type=int,choices=[0,1],default=1) 12 | parser.add_argument("--save",type=str,default="") 13 | 14 | args = parser.parse_args() 15 | inputfile = args.inputfile 16 | 17 | 18 | # Data 19 | data = pd.read_csv(inputfile) 20 | compressions = data.columns[1:] 21 | 22 | # Plot 23 | fig, ax = plt.subplots(1,1) 24 | ax.set_xlabel("Rank") 25 | ax.set_ylabel("Relative error in Frobenius norm") 26 | for compression in compressions: 27 | ax.semilogy(data["Rank"],data[compression],"x") 28 | ax.legend(compressions) 29 | 30 | 31 | 32 | # Output 33 | if args.show: 34 | plt.show() 35 | 36 | 37 | if args.save!="": 38 | fig.savefig(args.save,bbox_inches = 'tight', 39 | pad_inches = 0) -------------------------------------------------------------------------------- /include/htool/htool_version.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_VERSION_HPP 2 | #define HTOOL_VERSION_HPP 3 | 4 | #define HTOOL_VERSION_MAJOR 1 5 | #define HTOOL_VERSION_MINOR 0 6 | #define HTOOL_VERSION_SUBMINOR 0 7 | 8 | #define HTOOL_VERSION_EQ(MAJOR, MINOR, SUBMINOR) \ 9 | ((HTOOL_VERSION_MAJOR == (MAJOR)) && (HTOOL_VERSION_MINOR == (MINOR)) && (HTOOL_VERSION_SUBMINOR == (SUBMINOR))) 10 | 11 | #define HTOOL_VERSION_ HTOOL_VERSION_EQ 12 | 13 | #define HTOOL_VERSION_LT(MAJOR, MINOR, SUBMINOR) \ 14 | (HTOOL_VERSION_MAJOR < (MAJOR) || (HTOOL_VERSION_MAJOR == (MAJOR) && (HTOOL_VERSION_MINOR < (MINOR) || (HTOOL_VERSION_MINOR == (MINOR) && (HTOOL_VERSION_SUBMINOR < (SUBMINOR)))))) 15 | 16 | #define HTOOL_VERSION_LE(MAJOR, MINOR, SUBMINOR) \ 17 | (HTOOL_VERSION_LT(MAJOR, MINOR, SUBMINOR) || HTOOL_VERSION_EQ(MAJOR, MINOR, SUBMINOR)) 18 | 19 | #define HTOOL_VERSION_GT(MAJOR, MINOR, SUBMINOR) \ 20 | (0 == HTOOL_VERSION_LE(MAJOR, MINOR, SUBMINOR)) 21 | 22 | #define HTOOL_VERSION_GE(MAJOR, MINOR, SUBMINOR) \ 23 | (0 == HTOOL_VERSION_LT(MAJOR, MINOR, SUBMINOR)) 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_factorization/test_hmatrix_factorization_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_hmatrix_factorization.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | using namespace htool; 9 | 10 | int main(int, char *[]) { 11 | 12 | bool is_error = false; 13 | const int n1 = 1000; 14 | const double margin = 1; 15 | const int n2 = 100; 16 | 17 | for (auto epsilon : {1e-3, 1e-6}) { 18 | for (auto trans : {'N', 'T'}) { 19 | is_error = is_error || test_hmatrix_lu(trans, n1, n2, epsilon, margin); 20 | } 21 | for (auto UPLO : {'L', 'U'}) { 22 | is_error = is_error || test_hmatrix_cholesky(UPLO, n1, n2, epsilon, margin); 23 | } 24 | } 25 | 26 | if (is_error) { 27 | return 1; 28 | } 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /tests/functional_tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_custom_target(build-tests-basic-types) 2 | add_dependencies(build-tests build-tests-basic-types) 3 | add_subdirectory(basic_types) 4 | 5 | add_custom_target(build-tests-misc) 6 | add_dependencies(build-tests build-tests-misc) 7 | add_subdirectory(misc) 8 | 9 | add_custom_target(build-tests-clustering) 10 | add_dependencies(build-tests build-tests-clustering) 11 | add_subdirectory(clustering) 12 | 13 | add_custom_target(build-tests-matrix) 14 | add_dependencies(build-tests build-tests-matrix) 15 | add_subdirectory(matrix) 16 | 17 | add_custom_target(build-tests-hmatrix) 18 | add_dependencies(build-tests build-tests-hmatrix) 19 | add_subdirectory(hmatrix) 20 | 21 | if(MPI_FOUND) 22 | add_custom_target(build-tests-distributed-operator) 23 | add_dependencies(build-tests build-tests-distributed-operator) 24 | add_subdirectory(distributed_operator) 25 | endif() 26 | 27 | if(MPI_FOUND AND HPDDM_FOUND) 28 | add_custom_target(build-tests-solvers) 29 | add_dependencies(build-tests build-tests-solvers) 30 | add_subdirectory(solvers) 31 | endif() 32 | -------------------------------------------------------------------------------- /tests/functional_tests/matrix/matrix_factorization/test_matrix_factorization_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_matrix_factorization.hpp" // for test_matrix_cholesky 2 | #include // for complex, abs 3 | #include // for initializer_list 4 | 5 | using namespace std; 6 | using namespace htool; 7 | 8 | int main(int, char *[]) { 9 | 10 | bool is_error = false; 11 | const int number_of_rows = 200; 12 | 13 | for (auto number_of_rhs : {1, 100}) { 14 | for (auto operation : {'N', 'T', 'C'}) { 15 | // Square matrix 16 | is_error = is_error || test_matrix_lu>(operation, number_of_rows, number_of_rhs); 17 | } 18 | 19 | is_error = is_error || test_matrix_cholesky>('N', number_of_rows, number_of_rhs, 'H', 'U'); 20 | is_error = is_error || test_matrix_cholesky>('N', number_of_rows, number_of_rhs, 'H', 'L'); 21 | } 22 | 23 | if (is_error) { 24 | return 1; 25 | } 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Htool-DDM [![CI](https://github.com/htool-ddm/htool/actions/workflows/CI.yml/badge.svg)](https://github.com/htool-ddm/htool/actions/workflows/CI.yml) [![codecov](https://codecov.io/gh/htool-ddm/htool/branch/main/graph/badge.svg?token=1JJ40GPFA5)](https://codecov.io/gh/htool-ddm/htool) [![Documentation](https://img.shields.io/badge/docs-online-blue.svg)](http://htool-ddm.pages.math.cnrs.fr/) 2 | 3 | **Htool-DDM** is a lightweight header-only C++14 library that provides an easy-to-use interface for parallel iterative solvers and a default matrix compression via in-house hierarchical matrix implementation. Its goal is to provide modern iterative solvers for dense/compressed linear systems. 4 | 5 | It is also an extensible framework which contains several customization points. For example, one can provide its own compression algorithm, or customize the default hierarchical compression. Via its interface with [HPDDM](https://github.com/hpddm/hpddm), it is also a flexible tool to test various iterative solvers and preconditioners. 6 | 7 | See [documentation](http://htool-ddm.pages.math.cnrs.fr/) for more information. 8 | -------------------------------------------------------------------------------- /include/htool/distributed_operator/linalg/add_distributed_operator_vector_sub_product_global_to_local.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_DISTRIBUTED_OPERATOR_LINALG_ADD_DISTRIBUTED_OPERATOR_VECTOR_SUB_PRODUCT_GLOBAL_TO_LOCAL_HPP 2 | #define HTOOL_DISTRIBUTED_OPERATOR_LINALG_ADD_DISTRIBUTED_OPERATOR_VECTOR_SUB_PRODUCT_GLOBAL_TO_LOCAL_HPP 3 | 4 | #include "../distributed_operator.hpp" 5 | #include "utility.hpp" 6 | 7 | namespace htool { 8 | 9 | template 10 | void internal_add_distributed_operator_vector_sub_product_global_to_local(const DistributedOperator &A, const CoefficientPrecision *const in, CoefficientPrecision *const out, int mu, int offset, int size) { 11 | 12 | // Product 13 | for (auto &local_operator : A.get_global_to_local_operators()) { 14 | local_operator->add_sub_matrix_product_to_local(in, out, mu, offset, size); 15 | } 16 | for (auto &local_operator : A.get_local_to_local_operators()) { 17 | local_operator->add_sub_matrix_product_to_local(in, out, mu, offset, size); 18 | } 19 | } 20 | 21 | } // namespace htool 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/lrmat/lrmat_addition/test_lrmat_addition_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_lrmat_lrmat_addition.hpp" // for test_lrmat_lrmat_addition 2 | #include // for SVD 3 | #include // for GeneratorTestDouble 4 | #include // for initializer_list 5 | #include // for basic_ostream, char_traits 6 | 7 | int main(int, char const *[]) { 8 | bool is_error = false; 9 | // const int greater_size = 400; 10 | // const int lower_size = 200; 11 | const double margin = 10; 12 | 13 | for (auto &epsilon : {1e-6, 1e-10}) { 14 | for (auto &n1 : {200, 400}) { 15 | for (auto &n2 : {200, 400}) { 16 | std::cout << epsilon << " " << n1 << " " << n2 << "\n"; 17 | is_error = is_error || test_lrmat_lrmat_addition>(n1, n2, epsilon, margin); 18 | } 19 | } 20 | } 21 | 22 | if (is_error) { 23 | return 1; 24 | } 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /include/htool/testing/dense_blocks_generator_test.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_TESTING_DENSE_BLOCKS_GENERATOR_TEST_HPP 2 | #define HTOOL_TESTING_DENSE_BLOCKS_GENERATOR_TEST_HPP 3 | 4 | #include "../hmatrix/interfaces/virtual_dense_blocks_generator.hpp" 5 | #include "../hmatrix/interfaces/virtual_generator.hpp" 6 | #include 7 | 8 | namespace htool { 9 | template 10 | class DenseBlocksGeneratorTest : public VirtualDenseBlocksGenerator { 11 | private: 12 | const VirtualInternalGenerator &m_generator; 13 | 14 | public: 15 | DenseBlocksGeneratorTest(const VirtualInternalGenerator &generator) : m_generator(generator) {} 16 | void copy_dense_blocks(const std::vector &M, const std::vector &N, const std::vector &rows, const std::vector &cols, std::vector &ptr) const override { 17 | for (int i = 0; i < M.size(); i++) { 18 | m_generator.copy_submatrix(M[i], N[i], rows[i], cols[i], ptr[i]); 19 | } 20 | } 21 | }; 22 | } // namespace htool 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_triangular_solve/test_hmatrix_triangular_solve_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_hmatrix_triangular_solve.hpp" 2 | #include 3 | 4 | using namespace std; 5 | using namespace htool; 6 | 7 | int main(int, char *[]) { 8 | 9 | bool is_error = false; 10 | const int n1 = 400; 11 | const double margin = 1; 12 | 13 | for (auto number_of_rhs : {100}) { 14 | for (auto epsilon : {1e-6, 1e-10}) { 15 | for (auto side : {'L', 'R'}) { 16 | for (auto operation : {'N', 'T'}) { 17 | for (auto diag : {'N', 'U'}) { 18 | std::cout << epsilon << " " << number_of_rhs << " " << side << " " << operation << " " << diag << "\n"; 19 | is_error = is_error || test_hmatrix_triangular_solve(side, operation, diag, n1, number_of_rhs, epsilon, margin); 20 | } 21 | } 22 | } 23 | } 24 | } 25 | if (is_error) { 26 | return 1; 27 | } 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Pierre Marchand 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/lrmat/lrmat_addition/test_lrmat_addition_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_lrmat_lrmat_addition.hpp" // for test_lrmat_lrmat_addition 2 | #include // for complex, operator* 3 | #include // for SVD 4 | #include // for GeneratorTestComplex 5 | #include // for initializer_list 6 | #include // for basic_ostream, char_traits 7 | 8 | int main(int, char const *[]) { 9 | bool is_error = false; 10 | const double margin = 10; 11 | 12 | for (auto &epsilon : {1e-6, 1e-10}) { 13 | for (auto &n1 : {200, 400}) { 14 | for (auto &n2 : {200, 400}) { 15 | std::cout << epsilon << " " << n1 << " " << n2 << "\n"; 16 | is_error = is_error || test_lrmat_lrmat_addition, GeneratorTestComplex, SVD>>(n1, n2, epsilon, margin); 17 | } 18 | } 19 | } 20 | 21 | if (is_error) { 22 | return 1; 23 | } 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_addition/test_hmatrix_addition_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_lrmat_hmatrix_addition.hpp" // for test_lrmat_hmatrix_add... 2 | #include // for copy 3 | #include // for SVD 4 | #include // for GeneratorTestDouble 5 | #include // for initializer_list 6 | #include // for basic_ostream, char_tr... 7 | 8 | using namespace std; 9 | using namespace htool; 10 | 11 | int main(int, char *[]) { 12 | 13 | bool is_error = false; 14 | const double margin = 10; 15 | 16 | for (auto &epsilon : {1e-6, 1e-10}) { 17 | for (auto &n1 : {200, 400}) { 18 | for (auto &n2 : {200, 400}) { 19 | std::cout << epsilon << " " << n1 << " " << n2 << "\n"; 20 | is_error = is_error || test_lrmat_hmatrix_addition>(n1, n2, epsilon, margin); 21 | } 22 | } 23 | } 24 | if (is_error) { 25 | return 1; 26 | } 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /include/htool/clustering/cluster_tree_data.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_CLUSTERING_CLUSTER_TREE_DATA_HPP 2 | #define HTOOL_CLUSTERING_CLUSTER_TREE_DATA_HPP 3 | 4 | #include // for numeric_limits 5 | #include // for shared_ptr 6 | #include // for vector 7 | 8 | namespace htool { 9 | 10 | template 11 | class Cluster; 12 | 13 | template 14 | struct ClusterTreeData { 15 | // Parameters 16 | unsigned int m_maximal_leaf_size{10}; // minimal number of geometric point in a cluster 17 | 18 | // Information 19 | unsigned int m_max_depth{std::numeric_limits::min()}; // maximum depth of the tree 20 | unsigned int m_min_depth{std::numeric_limits::max()}; // minimum depth of the tree 21 | std::shared_ptr> m_permutation{nullptr}; // permutation from htool numbering to user numbering 22 | bool m_is_permutation_local{false}; 23 | 24 | // Nodes 25 | const Cluster *m_root_cluster{nullptr}; 26 | std::vector *> m_clusters_on_partition{}; 27 | }; 28 | 29 | } // namespace htool 30 | #endif 31 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_factorization/test_hmatrix_factorization_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_hmatrix_factorization.hpp" // for test_hmatrix_cholesky 2 | #include // for complex, operator== 3 | #include // for GeneratorTestComplex... 4 | #include // for initializer_list 5 | 6 | using namespace std; 7 | using namespace htool; 8 | 9 | int main(int, char *[]) { 10 | 11 | bool is_error = false; 12 | const int n1 = 500; 13 | const double margin = 1; 14 | const int n2 = 100; 15 | 16 | for (auto epsilon : {1e-3, 1e-6, 1e-10}) { 17 | for (auto trans : {'N', 'T'}) { 18 | is_error = is_error || test_hmatrix_lu, GeneratorTestComplexHermitian>(trans, n1, n2, epsilon, margin); 19 | } 20 | for (auto UPLO : {'L', 'U'}) { 21 | is_error = is_error || test_hmatrix_cholesky, GeneratorTestComplexHermitian>(UPLO, n1, n2, epsilon, margin); 22 | } 23 | } 24 | 25 | if (is_error) { 26 | return 1; 27 | } 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | add_executable(Use_clustering use_clustering.cpp) 6 | target_link_libraries(Use_clustering htool) 7 | add_dependencies(build-examples Use_clustering) 8 | 9 | add_executable(Use_hmatrix use_hmatrix.cpp) 10 | target_link_libraries(Use_hmatrix htool) 11 | add_dependencies(build-examples Use_hmatrix) 12 | 13 | if(MPI_FOUND) 14 | add_executable(Use_distributed_operator use_distributed_operator.cpp) 15 | target_link_libraries(Use_distributed_operator htool) 16 | add_dependencies(build-examples Use_distributed_operator) 17 | endif() 18 | 19 | if(MPI_FOUND AND HPDDM_FOUND) 20 | add_executable(Use_ddm_solver use_ddm_solver.cpp) 21 | target_link_libraries(Use_ddm_solver htool) 22 | add_dependencies(build-examples Use_ddm_solver) 23 | endif() 24 | 25 | add_executable(Compression_comparison compression_comparison.cpp) 26 | target_link_libraries(Compression_comparison htool) 27 | add_dependencies(build-examples Compression_comparison) 28 | -------------------------------------------------------------------------------- /tests/functional_tests/matrix/matrix_triangular_solve/test_matrix_triangular_solve_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_matrix_triangular_solve.hpp" // for test_matrix_triangula... 2 | #include // for complex, operator/, abs 3 | #include // for initializer_list 4 | #include // for basic_ostream, operat... 5 | 6 | using namespace std; 7 | using namespace htool; 8 | 9 | int main(int, char *[]) { 10 | 11 | bool is_error = false; 12 | const int number_of_rows = 200; 13 | 14 | for (auto number_of_rhs : {1, 100}) { 15 | for (auto side : {'L', 'R'}) { 16 | for (auto operation : {'N', 'T', 'C'}) { 17 | for (auto diag : {'N', 'U'}) { 18 | std::cout << number_of_rhs << " " << side << " " << operation << " " << diag << "\n"; 19 | // Square matrix 20 | is_error = is_error || test_matrix_triangular_solve>(number_of_rows, number_of_rhs, side, operation, diag); 21 | } 22 | } 23 | } 24 | } 25 | 26 | if (is_error) { 27 | return 1; 28 | } 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /include/htool/distributed_operator/linalg/utility.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_DISTRIBUTED_OPERATOR_LINALG_UTILITY_HPP 2 | #define HTOOL_DISTRIBUTED_OPERATOR_LINALG_UTILITY_HPP 3 | 4 | #include "../../misc/misc.hpp" 5 | #include "../../wrappers/wrapper_mpi.hpp" 6 | #include "../interfaces/virtual_partition.hpp" 7 | 8 | namespace htool { 9 | 10 | template 11 | void local_to_global(const VirtualPartition &partition, const CoefficientPrecision *in, CoefficientPrecision *out, int mu, MPI_Comm comm) { 12 | 13 | // Allgather 14 | int sizeWorld, rankWorld; 15 | MPI_Comm_rank(comm, &rankWorld); 16 | MPI_Comm_size(comm, &sizeWorld); 17 | std::vector recvcounts(sizeWorld); 18 | std::vector displs(sizeWorld); 19 | 20 | displs[0] = 0; 21 | 22 | for (int i = 0; i < sizeWorld; i++) { 23 | recvcounts[i] = (partition.get_size_of_partition(i)) * mu; 24 | if (i > 0) 25 | displs[i] = displs[i - 1] + recvcounts[i - 1]; 26 | } 27 | MPI_Allgatherv(in, recvcounts[rankWorld], wrapper_mpi::mpi_type(), out, &(recvcounts[0]), &(displs[0]), wrapper_mpi::mpi_type(), comm); 28 | } 29 | } // namespace htool 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_addition/test_hmatrix_addition_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_lrmat_hmatrix_addition.hpp" // for test_lrmat_hmatrix_add... 2 | #include // for copy 3 | #include // for complex, operator* 4 | #include // for SVD 5 | #include // for GeneratorTestComplex 6 | #include // for initializer_list 7 | #include // for basic_ostream, char_tr... 8 | 9 | using namespace std; 10 | using namespace htool; 11 | 12 | int main(int, char *[]) { 13 | 14 | bool is_error = false; 15 | const double margin = 10; 16 | 17 | for (auto &epsilon : {1e-6, 1e-10}) { 18 | for (auto &n1 : {200, 400}) { 19 | for (auto &n2 : {200, 400}) { 20 | std::cout << epsilon << " " << n1 << " " << n2 << "\n"; 21 | is_error = is_error || test_lrmat_hmatrix_addition, GeneratorTestComplex, SVD>>(n1, n2, epsilon, margin); 22 | } 23 | } 24 | } 25 | if (is_error) { 26 | return 1; 27 | } 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /include/htool/hmatrix/linalg/triangular_hmatrix_lrmat_solve.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_HMATRIX_LINALG_TRIANGULAR_HMATRIX_LRMAT_SOLVE_HPP 2 | #define HTOOL_HMATRIX_LINALG_TRIANGULAR_HMATRIX_LRMAT_SOLVE_HPP 3 | 4 | #include "../../misc/misc.hpp" // for underlying_type 5 | #include "../hmatrix.hpp" // for HMatrix 6 | #include "../lrmat/lrmat.hpp" // for LowRankMatrix 7 | #include "triangular_hmatrix_matrix_solve.hpp" // for triangular_hmatrix_... 8 | 9 | namespace htool { 10 | template > 11 | void internal_triangular_hmatrix_lrmat_solve(char side, char UPLO, char transa, char diag, CoefficientPrecision alpha, const HMatrix &A, LowRankMatrix &B) { 12 | if (alpha != CoefficientPrecision(1)) { 13 | scale(alpha, B); 14 | } 15 | if (side == 'L' or side == 'l') { 16 | internal_triangular_hmatrix_matrix_solve('L', UPLO, transa, diag, CoefficientPrecision(1), A, B.get_U()); 17 | } else { 18 | internal_triangular_hmatrix_matrix_solve('R', UPLO, transa, diag, CoefficientPrecision(1), A, B.get_V()); 19 | } 20 | } 21 | 22 | } // namespace htool 23 | #endif 24 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_custom_target(build-tests-lrmat) 2 | add_dependencies(build-tests build-tests-lrmat) 3 | add_subdirectory(lrmat) 4 | 5 | add_custom_target(build-tests-hmatrix-task-based) 6 | add_dependencies(build-tests-hmatrix build-tests-hmatrix-task-based) 7 | add_subdirectory(task_based) 8 | 9 | add_custom_target(build-tests-hmatrix-build) 10 | add_dependencies(build-tests-hmatrix build-tests-hmatrix-build) 11 | add_subdirectory(hmatrix_build) 12 | 13 | add_custom_target(build-tests-hmatrix-builder) 14 | add_dependencies(build-tests-hmatrix build-tests-hmatrix-builder) 15 | add_subdirectory(hmatrix_builder) 16 | 17 | add_custom_target(build-tests-hmatrix-product) 18 | add_dependencies(build-tests-hmatrix build-tests-hmatrix-product) 19 | add_subdirectory(hmatrix_product) 20 | 21 | add_custom_target(build-tests-hmatrix-addition) 22 | add_dependencies(build-tests-hmatrix build-tests-hmatrix-addition) 23 | add_subdirectory(hmatrix_addition) 24 | 25 | add_custom_target(build-tests-hmatrix-triangular-solve) 26 | add_dependencies(build-tests-hmatrix build-tests-hmatrix-triangular-solve) 27 | add_subdirectory(hmatrix_triangular_solve) 28 | 29 | add_custom_target(build-tests-hmatrix-factorization) 30 | add_dependencies(build-tests-hmatrix build-tests-hmatrix-factorization) 31 | add_subdirectory(hmatrix_factorization) 32 | -------------------------------------------------------------------------------- /include/htool/hmatrix/interfaces/virtual_admissibility_condition.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_HMATRIX_VIRTUAL_BLOCKS_ADMISSIBILITY_CONDITIONS_HPP 2 | #define HTOOL_HMATRIX_VIRTUAL_BLOCKS_ADMISSIBILITY_CONDITIONS_HPP 3 | 4 | #include "../../basic_types/vector.hpp" // for norm2 5 | #include "../../clustering/cluster_node.hpp" // for Cluster 6 | 7 | namespace htool { 8 | 9 | template 10 | class VirtualAdmissibilityCondition { 11 | public: 12 | virtual bool ComputeAdmissibility(const Cluster &target, const Cluster &source, double eta) const = 0; 13 | virtual ~VirtualAdmissibilityCondition() {} 14 | }; 15 | 16 | // Rjasanow - Steinbach (3.15) p111 Chap Approximation of Boundary Element Matrices 17 | template 18 | class RjasanowSteinbach final : public VirtualAdmissibilityCondition { 19 | public: 20 | bool ComputeAdmissibility(const Cluster &target, const Cluster &source, double eta) const override { 21 | bool admissible = 2 * std::min(target.get_radius(), source.get_radius()) < eta * std::max((norm2(target.get_center() - source.get_center()) - target.get_radius() - source.get_radius()), CoordinatePrecision(0)); 22 | return admissible; 23 | } 24 | }; 25 | 26 | } // namespace htool 27 | #endif 28 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_triangular_solve/test_hmatrix_triangular_solve_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_hmatrix_triangular_solve.hpp" // for test_hm... 2 | #include // for complex 3 | #include // for Generat... 4 | #include // for initial... 5 | #include // for basic_o... 6 | 7 | using namespace std; 8 | using namespace htool; 9 | 10 | int main(int, char *[]) { 11 | 12 | bool is_error = false; 13 | const int n1 = 400; 14 | const double margin = 1; 15 | 16 | for (auto number_of_rhs : {100}) { 17 | for (auto epsilon : {1e-6, 1e-10}) { 18 | for (auto side : {'L', 'R'}) { 19 | for (auto operation : {'N', 'T', 'C'}) { 20 | for (auto diag : {'N', 'U'}) { 21 | std::cout << epsilon << " " << number_of_rhs << " " << side << " " << operation << " " << diag << "\n"; 22 | is_error = is_error || test_hmatrix_triangular_solve, GeneratorTestComplexHermitian>(side, operation, diag, n1, number_of_rhs, epsilon, margin); 23 | } 24 | } 25 | } 26 | } 27 | } 28 | if (is_error) { 29 | return 1; 30 | } 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/lrmat/lrmat_product/test_lrmat_product_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_lrmat_product.hpp" 2 | #include 3 | #include // for SVD 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | using namespace htool; 10 | 11 | int main(int, char *[]) { 12 | 13 | bool is_error = false; 14 | const double additional_compression_tolerance = 0; 15 | const std::array additional_lrmat_sum_tolerances{1., 1., 1., 1.}; 16 | 17 | for (auto epsilon : {1e-6, 1e-10}) { 18 | for (auto n1 : {200, 400}) { 19 | for (auto n3 : {100}) { 20 | for (auto n2 : {200, 400}) { 21 | for (auto transa : {'N', 'T'}) { 22 | for (auto transb : {'N', 'T'}) { 23 | std::cout << epsilon << " " << n1 << " " << n2 << " " << n3 << " " << transa << " " << transb << "\n"; 24 | is_error = is_error || test_lrmat_product>(transa, transb, n1, n2, n3, epsilon, additional_compression_tolerance, additional_lrmat_sum_tolerances); 25 | } 26 | } 27 | } 28 | } 29 | } 30 | } 31 | 32 | if (is_error) { 33 | return 1; 34 | } 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /include/htool/solvers/local_solvers/local_dense_solvers.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_SOLVERS_LOCAL_SOLVER_DENSE_HPP 2 | #define HTOOL_SOLVERS_LOCAL_SOLVER_DENSE_HPP 3 | 4 | #include "../../matrix/linalg/factorization.hpp" 5 | #include "../interfaces/virtual_local_solver.hpp" 6 | 7 | namespace htool { 8 | 9 | template 10 | class LocalDenseSolver : public VirtualLocalSolver { 11 | private: 12 | Matrix &m_local_matrix; 13 | 14 | public: 15 | LocalDenseSolver(Matrix &local_matrix) : m_local_matrix(local_matrix) {} 16 | void numfact(HPDDM::MatrixCSR *const &, bool = false, CoefficientPrecision *const & = nullptr) { 17 | lu_factorization(m_local_matrix); 18 | } 19 | void solve(CoefficientPrecision *const b, const unsigned short &mu = 1) const { 20 | Matrix b_view; 21 | b_view.assign(m_local_matrix.nb_cols(), mu, b, false); 22 | lu_solve('N', m_local_matrix, b_view); 23 | } 24 | void solve(const CoefficientPrecision *const b, CoefficientPrecision *const x, const unsigned short &mu = 1) const { 25 | std::copy_n(b, m_local_matrix.nb_cols() * mu, x); 26 | Matrix b_view; 27 | b_view.assign(m_local_matrix.nb_cols(), mu, x, false); 28 | lu_solve('N', m_local_matrix, b_view); 29 | } 30 | }; 31 | } // namespace htool 32 | #endif 33 | -------------------------------------------------------------------------------- /include/htool/hmatrix/lrmat/linalg/add_lrmat_vector_product.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_LRMAT_LINALG_ADD_LRMAT_VECTOR_PRODUCT_HPP 2 | #define HTOOL_LRMAT_LINALG_ADD_LRMAT_VECTOR_PRODUCT_HPP 3 | #include "../../../matrix/linalg/add_matrix_vector_product.hpp" // for add_... 4 | #include "../lrmat.hpp" // for LowR... 5 | #include // for vector 6 | namespace htool { 7 | 8 | template 9 | void add_lrmat_vector_product(char trans, CoefficientPrecision alpha, const LowRankMatrix &A, const CoefficientPrecision *in, CoefficientPrecision beta, CoefficientPrecision *out) { 10 | auto rank = A.rank_of(); 11 | if (rank != 0) { 12 | auto &U = A.get_U(); 13 | auto &V = A.get_V(); 14 | if (trans == 'N') { 15 | std::vector a(rank); 16 | add_matrix_vector_product(trans, CoefficientPrecision(1.), V, in, CoefficientPrecision(0), a.data()); 17 | add_matrix_vector_product(trans, alpha, U, a.data(), beta, out); 18 | } else { 19 | std::vector a(rank); 20 | add_matrix_vector_product(trans, CoefficientPrecision(1.), U, in, CoefficientPrecision(0), a.data()); 21 | add_matrix_vector_product(trans, alpha, V, a.data(), beta, out); 22 | } 23 | } 24 | } 25 | 26 | } // namespace htool 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /tests/functional_tests/basic_types/test_basic_types_vector_file.cpp: -------------------------------------------------------------------------------- 1 | #include // for copy 2 | #include // for complex 3 | #include // for norm2, operator-, bytes_to_v... 4 | #include // for basic_ostream, operator<<, cout 5 | #include // for char_traits, basic_string 6 | #include // for vector 7 | 8 | using namespace std; 9 | using namespace htool; 10 | int main(int, char const *[]) { 11 | bool test = 0; 12 | 13 | //// Vector - double 14 | vector Vd(10); 15 | vector Pd(10); 16 | for (int i = 0; i < 10; i++) { 17 | Vd[i] = i; 18 | } 19 | test = test || (vector_to_bytes(Vd, "Vd")); 20 | test = test || (bytes_to_vector(Pd, "Vd")); 21 | test = test || !(norm2(Vd - Pd) < 1e-16); 22 | cout << "diff : " << norm2(Vd - Pd) << endl; 23 | 24 | //// Vector - complex double 25 | vector> Vcd(10); 26 | vector> Pcd(10); 27 | 28 | for (int i = 0; i < 10; i++) { 29 | Vcd[i] = complex(i, 1); 30 | } 31 | test = test || (vector_to_bytes(Vcd, "Vcd")); 32 | test = test || (bytes_to_vector(Pcd, "Vcd")); 33 | test = test || !(norm2(Vcd - Pcd) < 1e-16); 34 | cout << "diff : " << norm2(Vcd - Pcd) << endl; 35 | 36 | cout << test << endl; 37 | return test; 38 | } 39 | -------------------------------------------------------------------------------- /include/htool/htool.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_HTOOL_HPP 2 | #define HTOOL_HTOOL_HPP 3 | 4 | #include "htool_version.hpp" 5 | #include "misc/define.hpp" 6 | 7 | #include "basic_types/vector.hpp" 8 | #include "clustering/cluster_output.hpp" 9 | #include "clustering/tree_builder/tree_builder.hpp" 10 | #include "distributed_operator/distributed_operator.hpp" 11 | #include "distributed_operator/linalg.hpp" 12 | #include "distributed_operator/utility.hpp" 13 | #include "hmatrix/hmatrix.hpp" 14 | #include "hmatrix/hmatrix_distributed_output.hpp" 15 | #include "hmatrix/interfaces/virtual_generator.hpp" 16 | #include "hmatrix/linalg.hpp" 17 | #include "hmatrix/lrmat/SVD.hpp" 18 | #include "hmatrix/lrmat/fullACA.hpp" 19 | #include "hmatrix/lrmat/linalg.hpp" 20 | #include "hmatrix/lrmat/lrmat.hpp" 21 | #include "hmatrix/lrmat/partialACA.hpp" 22 | #include "hmatrix/lrmat/recompressed_low_rank_generator.hpp" 23 | #include "hmatrix/lrmat/sympartialACA.hpp" 24 | #include "matrix/linalg.hpp" 25 | #include "matrix/matrix.hpp" 26 | #include "matrix/matrix_view.hpp" 27 | #include "misc/misc.hpp" 28 | #include "misc/user.hpp" 29 | 30 | #ifdef HTOOL_WITH_HPDDM 31 | # include "solvers/ddm.hpp" 32 | # include "solvers/geneo/coarse_operator_builder.hpp" 33 | # include "solvers/geneo/coarse_space_builder.hpp" 34 | # include "solvers/utility.hpp" 35 | # include "wrappers/wrapper_hpddm.hpp" 36 | #endif 37 | #include "wrappers/wrapper_blas.hpp" 38 | #include "wrappers/wrapper_mpi.hpp" 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /tests/functional_tests/matrix/matrix_product/test_matrix_product_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_matrix_product.hpp" // for test_matrix_product, test_matr... 2 | #include // for initializer_list 3 | #include // for basic_ostream, operator<<, cha... 4 | 5 | using namespace std; 6 | using namespace htool; 7 | 8 | int main(int, char *[]) { 9 | 10 | bool is_error = false; 11 | for (auto n1 : {200, 400}) { 12 | for (auto n3 : {1, 5}) { 13 | for (auto n2 : {200, 400}) { 14 | for (auto transa : {'N', 'T'}) { 15 | for (auto transb : {'N', 'T'}) { 16 | std::cout << "matrix product: " << n1 << " " << n2 << " " << n3 << " " << transa << " " << transb << "\n"; 17 | // Square matrix 18 | is_error = is_error || test_matrix_product(n1, n2, n3, transa, transb); 19 | } 20 | } 21 | } 22 | for (auto side : {'L', 'R'}) { 23 | for (auto UPLO : {'U', 'L'}) { 24 | std::cout << "symmetric matrix product: " << n1 << " " << n3 << " " << side << " " << UPLO << "\n"; 25 | is_error = is_error || test_matrix_symmetric_product(n1, n3, side, UPLO); 26 | } 27 | } 28 | } 29 | } 30 | 31 | if (is_error) { 32 | return 1; 33 | } 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /include/htool/hmatrix/lrmat/linalg/add_lrmat_matrix_product_row_major.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_LRMAT_LINALG_ADD_LRMAT_MATRIX_PRODUCT_ROW_MAJOR_HPP 2 | #define HTOOL_LRMAT_LINALG_ADD_LRMAT_MATRIX_PRODUCT_ROW_MAJOR_HPP 3 | 4 | #include "../../../matrix/linalg/add_matrix_matrix_product_row_major.hpp" 5 | #include "../lrmat.hpp" 6 | #include 7 | 8 | namespace htool { 9 | 10 | template 11 | void add_lrmat_matrix_product_row_major(char transa, char transb, CoefficientPrecision alpha, const LowRankMatrix &A, const CoefficientPrecision *in, CoefficientPrecision beta, CoefficientPrecision *out, int mu) { 12 | auto rank = A.rank_of(); 13 | 14 | if (rank != 0) { 15 | auto &U = A.get_U(); 16 | auto &V = A.get_V(); 17 | if (transa == 'N') { 18 | std::vector a(rank * mu); 19 | add_matrix_matrix_product_row_major(transa, transb, CoefficientPrecision(1), V, in, CoefficientPrecision(0), a.data(), mu); 20 | add_matrix_matrix_product_row_major(transa, 'N', alpha, U, a.data(), beta, out, mu); 21 | } else { 22 | std::vector a(rank * mu); 23 | add_matrix_matrix_product_row_major(transa, transb, CoefficientPrecision(1), U, in, CoefficientPrecision(0), a.data(), mu); 24 | add_matrix_matrix_product_row_major(transa, 'N', alpha, V, a.data(), beta, out, mu); 25 | } 26 | } 27 | } 28 | 29 | } // namespace htool 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_builder/test_hmatrix_builder_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_hmatrix_builder.hpp" // for test_hmatrix_build 2 | #include // for max 3 | #include // for GeneratorTestComplexSymm... 4 | #include // for initializer_list 5 | #include // for basic_ostream, char_traits 6 | #include // for MPI_Finalize, MPI_Init 7 | 8 | using namespace std; 9 | using namespace htool; 10 | 11 | int main(int argc, char *argv[]) { 12 | MPI_Init(&argc, &argv); 13 | 14 | bool is_error = false; 15 | 16 | for (auto nr : {200, 400}) { 17 | for (auto nc : {200, 400}) { 18 | for (auto epsilon : {1e-14, 1e-6}) { 19 | std::cout << nr << " " << nc << " " << epsilon << "\n"; 20 | 21 | is_error = is_error || test_hmatrix_builder(nr, nc, 'N', 'N', epsilon); 22 | 23 | if (nr == nc) { 24 | for (auto UPLO : {'U', 'L'}) { 25 | std::cout << UPLO << "\n"; 26 | is_error = is_error || test_hmatrix_builder(nr, nc, 'S', UPLO, epsilon); 27 | } 28 | } 29 | } 30 | } 31 | } 32 | 33 | MPI_Finalize(); 34 | 35 | if (is_error) { 36 | return 1; 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /tools/plot_cluster.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from mpl_toolkits.mplot3d import Axes3D 3 | import matplotlib.pyplot as plt 4 | import matplotlib.colors as colors 5 | import pandas as pd 6 | import argparse 7 | 8 | parser = argparse.ArgumentParser() 9 | parser.add_argument("--inputfile", type=str) 10 | parser.add_argument("--show", type=int, choices=[0, 1], default=1) 11 | parser.add_argument("--depth", type=int, default=1) 12 | parser.add_argument("--save", type=str, default="") 13 | 14 | args = parser.parse_args() 15 | inputfile = args.inputfile 16 | depth = args.depth 17 | 18 | # First Data 19 | data = (pd.read_csv(inputfile, header=None)).T 20 | header = data.iloc[0] 21 | print(header) 22 | data = data[1:] 23 | data.columns = header 24 | 25 | 26 | # Create Color Map 27 | colormap = plt.get_cmap("tab10") 28 | norm = colors.Normalize(vmin=min(data[str(depth)]), vmax=max(data[str(depth)])) 29 | 30 | # Figure 31 | fig = plt.figure() 32 | 33 | 34 | if "x_2" in data.columns: 35 | ax = fig.add_subplot(111, projection='3d') 36 | ax.scatter(data["x_0"].tolist(), data["x_1"].tolist(), data["x_2"].tolist( 37 | ), c=colormap(norm(data[str(depth)].tolist())), marker='o') 38 | else: 39 | ax = fig.add_subplot(111) 40 | ax.scatter(data["x_0"].tolist(), data["x_1"].tolist(), 41 | c=colormap(norm(data[str(depth)].tolist())), marker='o') 42 | 43 | # Output 44 | if args.show: 45 | plt.show() 46 | 47 | 48 | if args.save != "": 49 | fig.savefig(args.save, bbox_inches='tight', 50 | pad_inches=0) 51 | -------------------------------------------------------------------------------- /include/htool/misc/user.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_USER_HPP 2 | #define HTOOL_USER_HPP 3 | 4 | #include // for size_t 5 | #include // for accumulate 6 | #include // for basic_ostringstream, basic_istringstream, istri... 7 | #include // for basic_string, allocator, string, char_traits 8 | #include // for vector 9 | 10 | namespace htool { 11 | 12 | // Conversions 13 | template 14 | std::string NbrToStr(T Number) { 15 | std::ostringstream ss; 16 | ss << Number; 17 | return ss.str(); 18 | } 19 | 20 | template 21 | T StrToNbr(const std::string &Text) { 22 | std::istringstream ss(Text); 23 | T result; 24 | return (ss >> result) ? result : 0; 25 | } 26 | 27 | // String operations 28 | 29 | inline std::vector split(const std::string &s, const std::string &delim) { 30 | std::vector elems; 31 | std::string line = s; 32 | std::size_t pos = 0; 33 | std::string token; 34 | while ((pos = line.find(delim)) != std::string::npos) { 35 | token = line.substr(0, pos); 36 | elems.push_back(token); 37 | line.erase(0, pos + delim.length()); 38 | } 39 | elems.push_back(line); 40 | return elems; 41 | } 42 | 43 | inline std::string join(std::string delimiter, std::vector x) { 44 | return std::accumulate(x.begin(), x.end(), std::string(), [&](std::string ss, const std::string &s) { return ss.empty() ? s : ss + delimiter + s; }); 45 | } 46 | } // namespace htool 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for considering contributing to **Htool-DDM**! We welcome bug reports, feature suggestions, and pull requests. 4 | 5 | ## Opening issues 6 | 7 | If you encounter a bug or have a question, please [open an issue](https://github.com/htool-ddm/htool/issues). 8 | When reporting a bug, include: 9 | 10 | - a clear description of the problem, 11 | - the expected behavior, 12 | - a minimal, reproducible example (if possible), 13 | - your environment (compiler, OS, library versions). 14 | 15 | ## Submitting changes (Pull Requests) 16 | 17 | To learn how to submit a pull request, please refer to GitHub’s 18 | [pull request documentation](https://docs.github.com/fr/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests). 19 | 20 | Before your pull request can be merged into `main`: 21 | 22 | 1. **Tests must run successfully.** 23 | 2. **Code style and formatting must follow project standards.** 24 | 25 | Instructions for running tests locally and applying formatting can be found in the 26 | [Htool developer guide](https://htool-ddm.pages.math.cnrs.fr/cpp_api/developer_guide.html#developer-guide). 27 | 28 | ## Code Style and Guidelines 29 | 30 | - Follow the project’s formatting rules (see [developer guide](https://htool-ddm.pages.math.cnrs.fr/cpp_api/developer_guide.html#formatting)). 31 | - Write clear commit messages. 32 | - Keep pull requests focused and reasonably small. 33 | 34 | --- 35 | 36 | Thank you again for helping improve Htool-DDM! 37 | -------------------------------------------------------------------------------- /include/htool/testing/gmsh.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_GEOMETRY_HPP 2 | #define HTOOL_GEOMETRY_HPP 3 | 4 | #include "point.hpp" // for operator>>, R3 5 | #include // for copy, max 6 | #include // for array 7 | #include // for basic_ifstream, basic_istream::operator>>, basi... 8 | #include // for cout 9 | #include // for basic_istringstream 10 | #include // for getline, basic_string, operator!=, char_traits 11 | #include // for vector 12 | 13 | namespace htool { 14 | 15 | int Load_GMSH_nodes(std::vector &x, const std::string &filename) { 16 | 17 | int size = 0; 18 | 19 | std::istringstream iss; 20 | std::ifstream file; 21 | std::string line; 22 | 23 | // Open file 24 | file.open(filename); 25 | if (!file.good()) { 26 | std::cout << "Cannot open mesh file\n"; // LCOV_EXCL_LINE 27 | return 1; // LCOV_EXCL_LINE 28 | } 29 | 30 | // Number of elements 31 | while (line != "$Nodes") { 32 | getline(file, line); 33 | } 34 | file >> size; 35 | getline(file, line); 36 | x.resize(size); 37 | 38 | // Read point 39 | R3 coord; 40 | int dummy; 41 | getline(file, line); 42 | for (int p = 0; p < size; p++) { 43 | iss.str(line); 44 | iss >> dummy; 45 | iss >> coord; 46 | x[p] = coord; 47 | iss.clear(); 48 | getline(file, line); 49 | } 50 | 51 | // Fermeture fichier 52 | file.close(); 53 | 54 | return 0; 55 | } 56 | 57 | } // namespace htool 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /include/htool/misc/misc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_INFOS_HPP 2 | #define HTOOL_INFOS_HPP 3 | 4 | #include // for transform 5 | #include // for complex 6 | #include // for enable_if, false_type, true_type 7 | 8 | namespace htool { 9 | template 10 | struct underlying_type_spec { 11 | typedef T type; 12 | }; 13 | template 14 | struct underlying_type_spec> { 15 | typedef T type; 16 | }; 17 | template 18 | using underlying_type = typename underlying_type_spec::type; 19 | 20 | // Check if complex type 21 | // https://stackoverflow.com/a/41438903/5913047 22 | template 23 | struct is_complex_t : public std::false_type {}; 24 | template 25 | struct is_complex_t> : public std::true_type {}; 26 | 27 | template 28 | constexpr bool is_complex() { return is_complex_t::value; } 29 | 30 | // https://stackoverflow.com/a/63316255/5913047 31 | template ::value, int>::type = 0> 32 | void conj_if_complex(T *, int) {} 33 | 34 | template ::value, int>::type = 0> 35 | void conj_if_complex(T *in, int size) { 36 | std::transform(in, in + size, in, [](const T &c) { return std::conj(c); }); 37 | } 38 | 39 | template ::value, int>::type = 0> 40 | T conj_if_complex(T in) { return in; } 41 | 42 | template ::value, int>::type = 0> 43 | T conj_if_complex(T in) { 44 | return std::conj(in); 45 | } 46 | } // namespace htool 47 | #endif 48 | -------------------------------------------------------------------------------- /include/htool/matrix/utils/modifiers.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_MATRIX_UTILS_MODIFIERS_HPP 2 | #define HTOOL_MATRIX_UTILS_MODIFIERS_HPP 3 | 4 | #include 5 | 6 | namespace htool { 7 | 8 | template 9 | auto get_stridedslice(const Mat &mat, int start, int length, int stride) { 10 | using T = typename Mat::value_type; 11 | std::vector result; 12 | result.reserve(length); 13 | const T *pos = &mat.data()[start]; 14 | for (int i = 0; i < length; i++) { 15 | result.push_back(*pos); 16 | pos += stride; 17 | } 18 | return result; 19 | } 20 | 21 | template 22 | void set_stridedslice(Mat &mat, int start, int length, int stride, const std::vector &a) { 23 | using T = typename Mat::value_type; 24 | T *pos = &mat.data()[start]; 25 | for (int i = 0; i < length; i++) { 26 | *pos = a[i]; 27 | pos += stride; 28 | } 29 | } 30 | template 31 | auto get_row(const Mat &mat, int row) { 32 | return get_stridedslice(mat, row, mat.nb_cols(), mat.nb_rows()); 33 | } 34 | 35 | template 36 | auto get_col(const Mat &mat, int col) { 37 | return get_stridedslice(mat, col * mat.nb_rows(), mat.nb_rows(), 1); 38 | } 39 | 40 | template 41 | void set_row(Mat &mat, int row, const std::vector &a) { 42 | set_stridedslice(mat, row, mat.nb_cols(), mat.nb_rows(), a); 43 | } 44 | template 45 | void set_col(Mat &mat, int col, const std::vector &a) { 46 | set_stridedslice(mat, col * mat.nb_rows(), mat.nb_rows(), 1, a); 47 | } 48 | 49 | } // namespace htool 50 | #endif 51 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_builder/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | set(types "double") 6 | list(APPEND types "complex_double") 7 | 8 | foreach(type ${types}) 9 | add_executable(Test_hmatrix_builder_${type} test_hmatrix_builder_${type}.cpp) 10 | target_link_libraries(Test_hmatrix_builder_${type} htool) 11 | add_dependencies(build-tests-hmatrix-builder Test_hmatrix_builder_${type}) 12 | add_test(NAME Test_hmatrix_builder_${type}_1 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 1 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_hmatrix_builder_${type}) 13 | set_tests_properties(Test_hmatrix_builder_${type}_1 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=4) 14 | set_tests_properties(Test_hmatrix_builder_${type}_1 PROPERTIES LABELS "mpi") 15 | add_test(NAME Test_hmatrix_builder_${type}_2 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_hmatrix_builder_${type}) 16 | set_tests_properties(Test_hmatrix_builder_${type}_2 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=2) 17 | set_tests_properties(Test_hmatrix_builder_${type}_2 PROPERTIES LABELS "mpi") 18 | add_test(NAME Test_hmatrix_builder_${type}_4 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_hmatrix_builder_${type}) 19 | set_tests_properties(Test_hmatrix_builder_${type}_4 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=1) 20 | set_tests_properties(Test_hmatrix_builder_${type}_4 PROPERTIES LABELS "mpi") 21 | endforeach() 22 | -------------------------------------------------------------------------------- /include/htool/distributed_operator/interfaces/virtual_partition.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_DISTIRBUTED_OPERATOR_VIRTUAL_PARTITION_HPP 2 | #define HTOOL_DISTIRBUTED_OPERATOR_VIRTUAL_PARTITION_HPP 3 | 4 | namespace htool { 5 | 6 | template 7 | class VirtualPartition { 8 | public: 9 | virtual int get_size_of_partition(int subdomain_number) const = 0; 10 | virtual int get_offset_of_partition(int subdomain_number) const = 0; 11 | 12 | virtual int get_global_size() const = 0; 13 | 14 | virtual void global_to_partition_numbering(const CoefficientPrecision *const in, CoefficientPrecision *const out) const = 0; 15 | virtual void partition_to_global_numbering(const CoefficientPrecision *const in, CoefficientPrecision *const out) const = 0; 16 | 17 | virtual void local_to_local_partition_numbering(int subdomain_number, const CoefficientPrecision *const in, CoefficientPrecision *const out) const = 0; 18 | virtual void local_partition_to_local_numbering(int subdomain_number, const CoefficientPrecision *const in, CoefficientPrecision *const out) const = 0; 19 | 20 | virtual bool is_renumbering_local() const = 0; 21 | virtual ~VirtualPartition() = default; 22 | 23 | protected: 24 | // no copy 25 | VirtualPartition() = default; 26 | VirtualPartition(const VirtualPartition &) = default; 27 | VirtualPartition &operator=(const VirtualPartition &) = default; 28 | VirtualPartition(VirtualPartition &&IPartition) noexcept = default; 29 | VirtualPartition &operator=(VirtualPartition &&IPartition) noexcept = default; 30 | }; 31 | 32 | } // namespace htool 33 | #endif 34 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_builder/test_hmatrix_builder_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_hmatrix_builder.hpp" // for test_hmatrix_build 2 | #include // for max 3 | #include // for complex, abs, operator- 4 | #include // for GeneratorTestComplexSymm... 5 | #include // for initializer_list 6 | #include // for basic_ostream, char_traits 7 | #include // for MPI_Finalize, MPI_Init 8 | 9 | using namespace std; 10 | using namespace htool; 11 | 12 | int main(int argc, char *argv[]) { 13 | MPI_Init(&argc, &argv); 14 | 15 | bool is_error = false; 16 | 17 | for (auto nr : {200, 400}) { 18 | for (auto nc : {200, 400}) { 19 | for (auto epsilon : {1e-14, 1e-6}) { 20 | std::cout << nr << " " << nc << " " << epsilon << "\n"; 21 | 22 | is_error = is_error || test_hmatrix_builder, GeneratorTestComplexSymmetric>(nr, nc, 'N', 'N', epsilon); 23 | if (nr == nc) { 24 | for (auto UPLO : {'U', 'L'}) { 25 | is_error = is_error || test_hmatrix_builder, GeneratorTestComplexSymmetric>(nr, nr, 'S', UPLO, epsilon); 26 | 27 | is_error = is_error || test_hmatrix_builder, GeneratorTestComplexHermitian>(nr, nr, 'H', UPLO, epsilon); 28 | } 29 | } 30 | } 31 | } 32 | } 33 | 34 | MPI_Finalize(); 35 | 36 | if (is_error) { 37 | return 1; 38 | } 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /include/htool/hmatrix/hmatrix_tree_data.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_HMATRIX_TREE_DATA_HPP 2 | #define HTOOL_HMATRIX_TREE_DATA_HPP 3 | 4 | #include "../clustering/cluster_node.hpp" // for Cluster 5 | #include "../misc/misc.hpp" // for underlying_type 6 | #include "interfaces/virtual_admissibility_condition.hpp" // for VirtualAdmissibility .. 7 | #include "interfaces/virtual_lrmat_generator.hpp" // for VirtualLowRankGene... 8 | #include // for duration 9 | #include // for map 10 | #include // for shared_ptr 11 | #include // for string 12 | 13 | namespace htool { 14 | 15 | template > 16 | struct HMatrixTreeData { 17 | // Parameters 18 | underlying_type m_epsilon{1e-6}; 19 | CoordinatePrecision m_eta{10}; 20 | unsigned int m_minimal_source_depth{0}; 21 | unsigned int m_minimal_target_depth{0}; 22 | bool m_delay_dense_computation{false}; 23 | int m_reqrank{-1}; 24 | bool m_is_block_tree_consistent{true}; 25 | 26 | // Information 27 | mutable std::map m_information; 28 | mutable std::map> m_timings; 29 | 30 | // Strategies 31 | std::shared_ptr> 32 | m_low_rank_generator; 33 | std::shared_ptr> m_admissibility_condition; 34 | }; 35 | 36 | } // namespace htool 37 | #endif 38 | -------------------------------------------------------------------------------- /include/htool/hmatrix/utils/recompression.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_HMATRIX_UTILS_RECOMPRESSION_HPP 2 | #define HTOOL_HMATRIX_UTILS_RECOMPRESSION_HPP 3 | #include "../hmatrix.hpp" 4 | #include "../lrmat/utils/SVD_recompression.hpp" 5 | namespace htool { 6 | 7 | template , class Recompression = decltype(SVD_recompression(std::declval &>()))(LowRankMatrix &)> 8 | void recompression(HMatrix &hmatrix, Recompression recompression = &SVD_recompression) { 9 | auto leaves = get_low_rank_leaves_from(hmatrix); // C++17 structured binding 10 | for (auto &leaf : leaves) { 11 | recompression(*leaf->get_low_rank_data()); 12 | } 13 | } 14 | 15 | template , class Recompression = decltype(SVD_recompression(std::declval &>()))(LowRankMatrix &)> 16 | void openmp_recompression(HMatrix &hmatrix, Recompression recompression = &SVD_recompression) { 17 | auto leaves = get_low_rank_leaves_from(hmatrix); // C++17 structured binding 18 | 19 | #if defined(_OPENMP) 20 | # pragma omp parallel 21 | #endif 22 | { 23 | #if defined(_OPENMP) 24 | # pragma omp for schedule(guided) nowait 25 | #endif 26 | for (int i = 0; i < leaves.size(); i++) { 27 | recompression(*leaves[i]->get_low_rank_data()); 28 | } 29 | } 30 | } 31 | } // namespace htool 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /tests/functional_tests/matrix/test_matrix_file.cpp: -------------------------------------------------------------------------------- 1 | #include // for complex 2 | #include // for Matrix 3 | #include // for MatrixView 4 | #include // for normFrob 5 | #include // for basic_ostream, operator<<, cout 6 | #include // for basic_string, char_traits 7 | 8 | using namespace std; 9 | using namespace htool; 10 | int main(int, char const *[]) { 11 | bool test = 0; 12 | 13 | //// Matrix - double 14 | Matrix Md(10, 5); 15 | Matrix Pd(10, 5); 16 | for (int i = 0; i < 10; i++) { 17 | for (int j = 0; j < 5; j++) { 18 | Md(i, j) = i + j; 19 | } 20 | } 21 | matrix_to_bytes(Md, "Md"); 22 | bytes_to_matrix("Md", Pd); 23 | test = test || !(normFrob(Md - Pd) < 1e-16); 24 | cout << "diff : " << normFrob(Md - Pd) << endl; 25 | 26 | //// Matrix view - double 27 | MatrixView Md_view(Md); 28 | matrix_to_bytes(Md_view, "Md_view"); 29 | bytes_to_matrix("Md_view", Pd); 30 | test = test || !(normFrob(Md - Pd) < 1e-16); 31 | cout << "diff : " << normFrob(Md - Pd) << endl; 32 | 33 | //// Matrix - complex double 34 | Matrix> Mcd(10, 5); 35 | Matrix> Pcd(10, 5); 36 | 37 | for (int i = 0; i < 10; i++) { 38 | for (int j = 0; j < 5; j++) { 39 | Mcd(i, j) = complex(i + j, 1); 40 | } 41 | } 42 | matrix_to_bytes(Mcd, "Mcd"); 43 | bytes_to_matrix("Mcd", Pcd); 44 | test = test || !(normFrob(Mcd - Pcd) < 1e-16); 45 | cout << "diff : " << normFrob(Mcd - Pcd) << endl; 46 | 47 | return test; 48 | } 49 | -------------------------------------------------------------------------------- /include/htool/wrappers/wrapper_mpi.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_WRAPPER_MPI_HPP 2 | #define HTOOL_WRAPPER_MPI_HPP 3 | 4 | #include "htool/misc/misc.hpp" // for underlying_type 5 | #include // for UCHAR_MAX, UINT_MAX, ULONG_MAX, USHRT... 6 | #include // for complex 7 | #include // for SIZE_MAX 8 | #include // for MPI_Datatype, MPI_C_COMPLEX, MPI_C_DO... 9 | 10 | namespace htool { 11 | template 12 | struct wrapper_mpi { 13 | static MPI_Datatype mpi_type(); 14 | static MPI_Datatype mpi_underlying_type() { 15 | return wrapper_mpi>::mpi_type(); 16 | } 17 | }; 18 | 19 | template <> 20 | inline MPI_Datatype wrapper_mpi::mpi_type() { return MPI_INT; } 21 | template <> 22 | inline MPI_Datatype wrapper_mpi::mpi_type() { return MPI_FLOAT; } 23 | template <> 24 | inline MPI_Datatype wrapper_mpi::mpi_type() { return MPI_DOUBLE; } 25 | template <> 26 | inline MPI_Datatype wrapper_mpi>::mpi_type() { return MPI_C_COMPLEX; } 27 | template <> 28 | inline MPI_Datatype wrapper_mpi>::mpi_type() { return MPI_C_DOUBLE_COMPLEX; } 29 | 30 | // https: //stackoverflow.com/questions/40807833/sending-size-t-type-data-with-mpi 31 | #if SIZE_MAX == UCHAR_MAX 32 | # define my_MPI_SIZE_T MPI_UNSIGNED_CHAR 33 | #elif SIZE_MAX == USHRT_MAX 34 | # define my_MPI_SIZE_T MPI_UNSIGNED_SHORT 35 | #elif SIZE_MAX == UINT_MAX 36 | # define my_MPI_SIZE_T MPI_UNSIGNED 37 | #elif SIZE_MAX == ULONG_MAX 38 | # define my_MPI_SIZE_T MPI_UNSIGNED_LONG 39 | #elif SIZE_MAX == ULLONG_MAX 40 | # define my_MPI_SIZE_T MPI_UNSIGNED_LONG_LONG 41 | #else 42 | # error "what is happening here?" 43 | #endif 44 | 45 | } // namespace htool 46 | #endif 47 | -------------------------------------------------------------------------------- /tests/functional_tests/matrix/matrix_product/test_matrix_product_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_matrix_product.hpp" // for test_matrix_hermitian_product 2 | #include // for complex 3 | #include // for initializer_list 4 | #include // for basic_ostream, operator<<, cha... 5 | 6 | using namespace std; 7 | using namespace htool; 8 | 9 | int main(int, char *[]) { 10 | 11 | bool is_error = false; 12 | 13 | for (auto n1 : {200, 400}) { 14 | for (auto n3 : {1, 5}) { 15 | for (auto n2 : {200, 400}) { 16 | for (auto transa : {'N', 'T', 'C'}) { 17 | for (auto transb : {'N', 'T', 'C'}) { 18 | std::cout << "matrix product: " << n1 << " " << n2 << " " << n3 << " " << transa << " " << transb << "\n"; 19 | // Square matrix 20 | is_error = is_error || test_matrix_product>(n1, n2, n3, transa, transb); 21 | } 22 | } 23 | } 24 | for (auto side : {'L', 'R'}) { 25 | for (auto UPLO : {'U', 'L'}) { 26 | std::cout << "symmetric matrix product: " << n1 << " " << n3 << " " << side << " " << UPLO << "\n"; 27 | is_error = is_error || test_matrix_symmetric_product>(n1, n3, side, UPLO); 28 | 29 | std::cout << "hermitian matrix product: " << n1 << " " << n3 << " " << side << " " << UPLO << "\n"; 30 | is_error = is_error || test_matrix_hermitian_product(n1, n3, side, UPLO); 31 | } 32 | } 33 | } 34 | } 35 | if (is_error) { 36 | return 1; 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /include/htool/hmatrix/lrmat/recompressed_low_rank_generator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_HMATRIX_LRMAT_RECOMPRESSED_LOW_RANK_GENERATOR_HPP 2 | #define HTOOL_HMATRIX_LRMAT_RECOMPRESSED_LOW_RANK_GENERATOR_HPP 3 | 4 | #include "../../hmatrix/interfaces/virtual_lrmat_generator.hpp" // for Virt... 5 | #include "../../misc/misc.hpp" // for unde... 6 | #include "../lrmat/utils/SVD_recompression.hpp" 7 | #include 8 | 9 | namespace htool { 10 | 11 | template 12 | class RecompressedLowRankGenerator final : public VirtualInternalLowRankGenerator { 13 | const VirtualInternalLowRankGenerator &m_low_rank_generator; 14 | std::function &)> m_recompression; 15 | 16 | public: 17 | RecompressedLowRankGenerator(const VirtualInternalLowRankGenerator &low_rank_generator, std::function &)> recompression) : m_low_rank_generator(low_rank_generator), m_recompression(recompression) {} 18 | 19 | virtual bool copy_low_rank_approximation(int M, int N, int row_offset, int col_offset, LowRankMatrix &lrmat) const { 20 | bool info = m_low_rank_generator.copy_low_rank_approximation(M, N, row_offset, col_offset, lrmat); 21 | if (info) { 22 | m_recompression(lrmat); 23 | } 24 | return info; 25 | } 26 | 27 | virtual bool copy_low_rank_approximation(int M, int N, int row_offset, int col_offset, int reqrank, LowRankMatrix &lrmat) const { 28 | bool info = m_low_rank_generator.copy_low_rank_approximation(M, N, row_offset, col_offset, reqrank, lrmat); 29 | return info; 30 | } 31 | }; 32 | 33 | } // namespace htool 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_factorization/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | set(types "double") 6 | list(APPEND types "complex_double") 7 | 8 | foreach(type ${types}) 9 | add_executable(Test_hmatrix_factorization_${type} test_hmatrix_factorization_${type}.cpp) 10 | target_link_libraries(Test_hmatrix_factorization_${type} htool) 11 | add_dependencies(build-tests-hmatrix-factorization Test_hmatrix_factorization_${type}) 12 | add_test(Test_hmatrix_factorization_${type} Test_hmatrix_factorization_${type}) 13 | endforeach() 14 | 15 | foreach(type ${types}) 16 | add_executable(Test_task_based_hmatrix_factorization_${type} test_task_based_hmatrix_factorization_${type}.cpp) 17 | target_link_libraries(Test_task_based_hmatrix_factorization_${type} htool) 18 | add_dependencies(build-tests-hmatrix-factorization Test_task_based_hmatrix_factorization_${type}) 19 | 20 | add_test(Test_task_based_hmatrix_factorization_${type}_1 Test_task_based_hmatrix_factorization_${type}) 21 | set_tests_properties(Test_task_based_hmatrix_factorization_${type}_1 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=1) 22 | 23 | add_test(Test_task_based_hmatrix_factorization_${type}_2 Test_task_based_hmatrix_factorization_${type}) 24 | set_tests_properties(Test_task_based_hmatrix_factorization_${type}_2 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=2) 25 | 26 | add_test(Test_task_based_hmatrix_factorization_${type}_4 Test_task_based_hmatrix_factorization_${type}) 27 | set_tests_properties(Test_task_based_hmatrix_factorization_${type}_4 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=4) 28 | endforeach() 29 | -------------------------------------------------------------------------------- /examples/use_clustering.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | using namespace htool; 8 | 9 | int main(int argc, char *argv[]) { 10 | 11 | // Check the number of parameters 12 | if (argc > 2) { 13 | // Tell the user how to run the program 14 | cerr << "Usage: " << argv[0] << " output_folder" << endl; 15 | /* "Usage messages" are a conventional way of telling the user 16 | * how to run a program if they enter the command incorrectly. 17 | */ 18 | return 1; 19 | } 20 | std::string output_folder = argc == 2 ? argv[1] : "./"; 21 | 22 | // Geometry 23 | const int number_points = 10000; 24 | const int spatial_dimension = 3; 25 | const int number_of_partitions = 8; 26 | const int number_of_children = 8; 27 | vector coordinates(spatial_dimension * number_points); 28 | create_sphere(number_points, coordinates.data()); 29 | 30 | // Cluster tree builder with customization 31 | ClusterTreeBuilder recursive_build_strategy; 32 | recursive_build_strategy.set_maximal_leaf_size(10); 33 | recursive_build_strategy.set_partitioning_strategy(std::make_shared, RegularSplitting>>()); 34 | 35 | // Clustering 36 | Cluster cluster = recursive_build_strategy.create_cluster_tree(number_points, spatial_dimension, coordinates.data(), number_of_children, number_of_partitions); 37 | 38 | // Output 39 | save_clustered_geometry(cluster, spatial_dimension, coordinates.data(), output_folder + "/clustering_output", {1, 2, 3}); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/lrmat/lrmat_product/test_lrmat_product_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_lrmat_product.hpp" // for test_lrmat_product 2 | #include // for copy 3 | #include // for array 4 | #include // for complex, operator*, oper... 5 | #include // for SVD 6 | #include // for GeneratorTestComplex 7 | #include // for initializer_list 8 | #include // for basic_ostream, char_traits 9 | 10 | using namespace std; 11 | using namespace htool; 12 | 13 | int main(int, char *[]) { 14 | 15 | bool is_error = false; 16 | const double additional_compression_tolerance = 0; 17 | const std::array additional_lrmat_sum_tolerances{10., 10., 10., 10.}; 18 | 19 | for (auto epsilon : {1e-6, 1e-10}) { 20 | for (auto n1 : {200, 400}) { 21 | for (auto n3 : {100}) { 22 | for (auto n2 : {200, 400}) { 23 | for (auto transa : {'N', 'T', 'C'}) { 24 | for (auto transb : {'N', 'T', 'C'}) { 25 | std::cout << epsilon << " " << n1 << " " << n2 << " " << n3 << " " << transa << " " << transb << "\n"; 26 | is_error = is_error || test_lrmat_product, GeneratorTestComplex, SVD>>(transa, transb, n1, n2, n3, epsilon, additional_compression_tolerance, additional_lrmat_sum_tolerances); 27 | } 28 | } 29 | } 30 | } 31 | } 32 | } 33 | 34 | if (is_error) { 35 | return 1; 36 | } 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_triangular_solve/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | set(types "double") 6 | list(APPEND types "complex_double") 7 | 8 | foreach(type ${types}) 9 | add_executable(Test_hmatrix_triangular_solve_${type} test_hmatrix_triangular_solve_${type}.cpp) 10 | target_link_libraries(Test_hmatrix_triangular_solve_${type} htool) 11 | add_dependencies(build-tests-hmatrix-triangular-solve Test_hmatrix_triangular_solve_${type}) 12 | add_test(Test_hmatrix_triangular_solve_${type} Test_hmatrix_triangular_solve_${type}) 13 | endforeach() 14 | 15 | foreach(type ${types}) 16 | add_executable(Test_task_based_hmatrix_triangular_solve_${type} test_task_based_hmatrix_triangular_solve_${type}.cpp) 17 | target_link_libraries(Test_task_based_hmatrix_triangular_solve_${type} htool) 18 | add_dependencies(build-tests-hmatrix-triangular-solve Test_task_based_hmatrix_triangular_solve_${type}) 19 | 20 | add_test(Test_task_based_hmatrix_triangular_solve_${type}_1 Test_task_based_hmatrix_triangular_solve_${type}) 21 | set_tests_properties(Test_task_based_hmatrix_triangular_solve_${type}_1 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=1) 22 | 23 | add_test(Test_task_based_hmatrix_triangular_solve_${type}_2 Test_task_based_hmatrix_triangular_solve_${type}) 24 | set_tests_properties(Test_task_based_hmatrix_triangular_solve_${type}_2 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=2) 25 | 26 | add_test(Test_task_based_hmatrix_triangular_solve_${type}_4 Test_task_based_hmatrix_triangular_solve_${type}) 27 | set_tests_properties(Test_task_based_hmatrix_triangular_solve_${type}_4 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=4) 28 | endforeach() 29 | -------------------------------------------------------------------------------- /include/htool/distributed_operator/interfaces/virtual_local_to_local_operator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_DISTRIBUTED_OPERATOR_VIRTUAL_LOCAL_TO_LOCAL_OPERATOR_HPP 2 | #define HTOOL_DISTRIBUTED_OPERATOR_VIRTUAL_LOCAL_TO_LOCAL_OPERATOR_HPP 3 | 4 | namespace htool { 5 | /// @brief Interface representing 6 | /// @tparam T 7 | template 8 | class VirtualLocalToLocalOperator { 9 | public: 10 | /// @brief 11 | /// @param trans 12 | /// @param alpha 13 | /// @param in Local input vector. 14 | /// @param beta 15 | /// @param out Local output vector. 16 | virtual void add_vector_product(char trans, T alpha, const T *const in, T beta, T *const out) const = 0; 17 | 18 | /// @brief 19 | /// @param trans 20 | /// @param alpha 21 | /// @param in Local input row-major matrix. 22 | /// @param beta 23 | /// @param out Local output row-major matrix. 24 | /// @param mu Number of columns for in and out. 25 | virtual void add_matrix_product_row_major(char trans, T alpha, const T *const in, T beta, T *const out, int mu) const = 0; 26 | 27 | /// @brief 28 | /// @param in 29 | /// @param out 30 | /// @param mu 31 | /// @param offset 32 | /// @param size 33 | virtual void add_sub_matrix_product_to_local(const T *const in, T *const out, int mu, int offset, int size) const = 0; 34 | 35 | virtual ~VirtualLocalToLocalOperator() {} 36 | 37 | protected: 38 | VirtualLocalToLocalOperator() = default; 39 | VirtualLocalToLocalOperator(const VirtualLocalToLocalOperator &) = default; 40 | VirtualLocalToLocalOperator(VirtualLocalToLocalOperator &&) noexcept = default; 41 | VirtualLocalToLocalOperator &operator=(const VirtualLocalToLocalOperator &) = default; 42 | VirtualLocalToLocalOperator &operator=(VirtualLocalToLocalOperator &&) noexcept = default; 43 | }; 44 | } // namespace htool 45 | #endif 46 | -------------------------------------------------------------------------------- /include/htool/solvers/interfaces/virtual_local_solver.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_WRAPPERS_INTERFACE_HPP 2 | #define HTOOL_WRAPPERS_INTERFACE_HPP 3 | #define HPDDM_NUMBERING 'F' 4 | #define HPDDM_DENSE 1 5 | #define HPDDM_FETI 0 6 | #define HPDDM_BDD 0 7 | #define LAPACKSUB 8 | #define DLAPACK 9 | #define EIGENSOLVER 1 10 | #if defined(__clang__) 11 | # pragma clang diagnostic push 12 | # pragma clang diagnostic ignored "-Wsign-compare" 13 | # pragma clang diagnostic ignored "-Wshadow" 14 | # pragma clang diagnostic ignored "-Wdouble-promotion" 15 | # pragma clang diagnostic ignored "-Wunused-parameter" 16 | # pragma clang diagnostic ignored "-Wnon-virtual-dtor" 17 | #elif defined(__GNUC__) || defined(__GNUG__) 18 | # pragma GCC diagnostic push 19 | # pragma GCC diagnostic ignored "-Wsign-compare" 20 | # pragma GCC diagnostic ignored "-Wshadow" 21 | # pragma GCC diagnostic ignored "-Wdouble-promotion" 22 | # pragma GCC diagnostic ignored "-Wunused-parameter" 23 | # pragma GCC diagnostic ignored "-Wnon-virtual-dtor" 24 | # pragma GCC diagnostic ignored "-Wuseless-cast" 25 | # pragma GCC diagnostic ignored "-Wunused-local-typedefs" 26 | #endif 27 | 28 | #include 29 | 30 | #if defined(__clang__) 31 | # pragma clang diagnostic pop 32 | #elif defined(__GNUC__) || defined(__GNUG__) 33 | # pragma GCC diagnostic pop 34 | #endif 35 | 36 | namespace htool { 37 | 38 | template 39 | class VirtualLocalSolver { 40 | public: 41 | virtual void numfact(HPDDM::MatrixCSR *const &, bool = false, CoefficientPrecision *const & = nullptr) = 0; 42 | 43 | virtual void solve(CoefficientPrecision *const, const unsigned short & = 1) const = 0; 44 | virtual void solve(const CoefficientPrecision *const, CoefficientPrecision *const, const unsigned short & = 1) const = 0; 45 | 46 | virtual ~VirtualLocalSolver() {} 47 | }; 48 | 49 | } // namespace htool 50 | #endif 51 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_triangular_solve/test_task_based_hmatrix_triangular_solve_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_task_based_hmatrix_triangular_solve.hpp" 2 | #include // for max 3 | #include // for GeneratorTestComplexSymm... 4 | #include // for initializer_list 5 | #include // for basic_ostream, char_traits 6 | 7 | using namespace std; 8 | using namespace htool; 9 | 10 | int main(int, char *[]) { 11 | 12 | bool is_error = false; 13 | 14 | const int n1 = 400; 15 | const int number_of_rhs = 100; 16 | 17 | for (auto epsilon : {1e-6}) { 18 | for (auto side : {'L', 'R'}) { 19 | for (auto operation : {'N', 'T'}) { 20 | for (auto diag : {'N', 'U'}) { 21 | 22 | std::cout << "task based hmatrix triangular solve test case: " << "number_of_rhs = " << number_of_rhs << ", epsilon = " << epsilon << ", n1 = " << n1 << ", side = " << side << ", operation = " << operation << ", diag = " << diag << "\n"; 23 | 24 | TestCaseSolve test_case(side, operation, n1, number_of_rhs, 1, -1); 25 | 26 | is_error = is_error || test_task_based_hmatrix_triangular_solve>(test_case, side, operation, diag, epsilon); 27 | } 28 | } 29 | } 30 | } 31 | 32 | std::cout << "+++++++++++++++++++++++++++++++++++++++++++" << std::endl; 33 | if (is_error) { 34 | htool::Logger::get_instance().log(LogLevel::ERROR, "At least one test_task_based_hmatrix_triangular_solve case failed."); // LCOV_EXCL_LINE 35 | return 1; 36 | 37 | } else { 38 | std::cout << "SUCCESS: All test_task_based_hmatrix_triangular_solve cases passed." << std::endl; 39 | } 40 | std::cout << "+++++++++++++++++++++++++++++++++++++++++++" << std::endl; 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_factorization/test_task_based_hmatrix_factorization_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_task_based_hmatrix_factorization.hpp" // for test_task_based_lu_factorization, test_task_based_cholesky_factorization 2 | #include // for max 3 | #include // for GeneratorTestComplexSymm... 4 | #include // for initializer_list 5 | #include // for basic_ostream, char_traits 6 | 7 | using namespace std; 8 | using namespace htool; 9 | 10 | int main(int, char *[]) { 11 | 12 | bool is_error = false; 13 | 14 | const int n1 = 1100; 15 | const int n2 = 1000; 16 | 17 | for (auto epsilon : {1e-4, 1e-8}) { 18 | for (auto trans : {'N', 'T'}) { 19 | 20 | std::cout << "task based LU factorization test case: " << "epsilon = " << epsilon << ", n1 = " << n1 << ", n2 = " << n2 << ", trans = " << trans << "\n"; 21 | 22 | is_error = is_error || test_task_based_lu_factorization(trans, n1, n2, epsilon); 23 | } 24 | 25 | for (auto UPLO : {'L', 'U'}) { 26 | std::cout << "task based Cholesky factorization test case: " << "epsilon = " << epsilon << ", n1 = " << n1 << ", n2 = " << n2 << ", UPLO = " << UPLO << "\n"; 27 | 28 | is_error = is_error || test_task_based_cholesky_factorization(UPLO, n1, n2, epsilon); 29 | } 30 | } 31 | 32 | std::cout << "+++++++++++++++++++++++++++++++++++++++++++" << std::endl; 33 | if (is_error) { 34 | htool::Logger::get_instance().log(LogLevel::ERROR, "At least one test_task_based_factorization case failed."); // LCOV_EXCL_LINE 35 | return 1; 36 | 37 | } else { 38 | std::cout << "SUCCESS: All test_task_based_factorization cases passed." << std::endl; 39 | } 40 | std::cout << "+++++++++++++++++++++++++++++++++++++++++++" << std::endl; 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /include/htool/hmatrix/execution_policies.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_HMATRIX_EXECUTION_POLICIES_HPP 2 | #define HTOOL_HMATRIX_EXECUTION_POLICIES_HPP 3 | 4 | #include "hmatrix.hpp" 5 | #include 6 | 7 | #if defined(__cpp_lib_execution) && __cplusplus >= 201703L 8 | # include 9 | namespace exec_compat { 10 | using parallel_policy = std::execution::parallel_policy; 11 | inline constexpr auto par = std::execution::par; 12 | using sequenced_policy = std::execution::sequenced_policy; 13 | inline constexpr auto seq = std::execution::seq; 14 | } // namespace exec_compat 15 | #else 16 | namespace exec_compat { 17 | struct sequenced_policy {}; 18 | static constexpr sequenced_policy seq{}; 19 | } // namespace exec_compat 20 | 21 | namespace exec_compat { 22 | struct parallel_policy {}; 23 | static constexpr parallel_policy par{}; 24 | 25 | } // namespace exec_compat 26 | #endif 27 | 28 | namespace htool { 29 | 30 | // Base template: false by default 31 | template 32 | struct is_execution_policy : std::false_type {}; 33 | 34 | // Specializations for fallback exec_compat policies 35 | template <> 36 | struct is_execution_policy : std::true_type {}; 37 | 38 | template <> 39 | struct is_execution_policy : std::true_type {}; 40 | 41 | template > 42 | struct omp_task_policy { 43 | // Shared state between tasks 44 | std::vector *> L0; 45 | int max_nb_nodes = 64; 46 | }; 47 | 48 | template 49 | struct is_execution_policy> : std::true_type {}; 50 | 51 | template 52 | constexpr bool is_execution_policy_v = is_execution_policy::value; 53 | 54 | inline bool need_to_create_parallel_region() { 55 | #if defined(_OPENMP) 56 | return omp_in_parallel() == 1 ? false : true; 57 | #else 58 | return false; 59 | #endif 60 | } 61 | 62 | } // namespace htool 63 | #endif 64 | -------------------------------------------------------------------------------- /include/htool/distributed_operator/interfaces/virtual_global_to_local_operator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_DISTRIBUTED_OPERATOR_VIRTUAL_GLOBAL_TO_LOCAL_OPERATOR_HPP 2 | #define HTOOL_DISTRIBUTED_OPERATOR_VIRTUAL_GLOBAL_TO_LOCAL_OPERATOR_HPP 3 | 4 | namespace htool { 5 | /// @brief Interface representing 6 | /// @tparam T 7 | template 8 | class VirtualGlobalToLocalOperator { 9 | public: 10 | /// @brief 11 | /// @param trans 12 | /// @param alpha 13 | /// @param in Global input vector when trans=='N'. Local input vector when trans!=N. 14 | /// @param beta 15 | /// @param out Local output vector when trans=='N'. Global output vector when trans=='N'. 16 | virtual void add_vector_product(char trans, T alpha, const T *const in, T beta, T *const out) const = 0; 17 | 18 | /// @brief 19 | /// @param trans 20 | /// @param alpha 21 | /// @param in Global input row-major matrix when trans=='N'. Local input row-major matrix when trans!=N. 22 | /// @param beta 23 | /// @param out Local input row-major matrix when trans=='N'. Global input row-major matrix when trans!=N. 24 | /// @param mu Number of columns for in and out. 25 | virtual void add_matrix_product_row_major(char trans, T alpha, const T *const in, T beta, T *const out, int mu) const = 0; 26 | 27 | /// @brief 28 | /// @param in 29 | /// @param out 30 | /// @param mu 31 | /// @param offset 32 | /// @param size 33 | virtual void add_sub_matrix_product_to_local(const T *const in, T *const out, int mu, int offset, int size) const = 0; 34 | 35 | virtual ~VirtualGlobalToLocalOperator() {} 36 | 37 | protected: 38 | VirtualGlobalToLocalOperator() = default; 39 | VirtualGlobalToLocalOperator(const VirtualGlobalToLocalOperator &) = default; 40 | VirtualGlobalToLocalOperator(VirtualGlobalToLocalOperator &&) noexcept = default; 41 | VirtualGlobalToLocalOperator &operator=(const VirtualGlobalToLocalOperator &) = default; 42 | VirtualGlobalToLocalOperator &operator=(VirtualGlobalToLocalOperator &&) noexcept = default; 43 | }; 44 | } // namespace htool 45 | #endif 46 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_factorization/test_task_based_hmatrix_factorization_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_task_based_hmatrix_factorization.hpp" // for test_task_based_lu_factorization, test_task_based_cholesky_factorization 2 | #include // for max 3 | #include // for complex, abs, operator- 4 | #include // for GeneratorTestComplexSymm... 5 | #include // for initializer_list 6 | #include // for basic_ostream, char_traits 7 | 8 | using namespace std; 9 | using namespace htool; 10 | 11 | int main(int, char *[]) { 12 | 13 | bool is_error = false; 14 | 15 | const int n1 = 1100; 16 | const int n2 = 1000; 17 | 18 | for (auto epsilon : {1e-3, 1e-8}) { 19 | for (auto trans : {'N', 'T'}) { 20 | 21 | std::cout << "task based LU factorization test case: " << "epsilon = " << epsilon << ", n1 = " << n1 << ", n2 = " << n2 << ", trans = " << trans << "\n"; 22 | 23 | is_error = is_error || test_task_based_lu_factorization, GeneratorTestComplexHermitian>(trans, n1, n2, epsilon); 24 | } 25 | 26 | for (auto UPLO : {'L', 'U'}) { 27 | std::cout << "task based Cholesky factorization test case: " << "epsilon = " << epsilon << ", n1 = " << n1 << ", n2 = " << n2 << ", UPLO = " << UPLO << "\n"; 28 | 29 | is_error = is_error || test_task_based_cholesky_factorization, GeneratorTestComplexHermitian>(UPLO, n1, n2, epsilon); 30 | } 31 | } 32 | 33 | std::cout << "+++++++++++++++++++++++++++++++++++++++++++" << std::endl; 34 | if (is_error) { 35 | htool::Logger::get_instance().log(LogLevel::ERROR, "At least one test_task_based_factorization case failed."); // LCOV_EXCL_LINE 36 | return 1; 37 | 38 | } else { 39 | std::cout << "SUCCESS: All test_task_based_factorization cases passed." << std::endl; 40 | } 41 | std::cout << "+++++++++++++++++++++++++++++++++++++++++++" << std::endl; 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_triangular_solve/test_task_based_hmatrix_triangular_solve_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_task_based_hmatrix_triangular_solve.hpp" 2 | #include // for max 3 | #include // for complex, abs, operator- 4 | #include // for GeneratorTestComplexSymm... 5 | #include // for initializer_list 6 | #include // for basic_ostream, char_traits 7 | 8 | using namespace std; 9 | using namespace htool; 10 | 11 | int main(int, char *[]) { 12 | 13 | bool is_error = false; 14 | 15 | const int n1 = 400; 16 | const int number_of_rhs = 100; 17 | 18 | for (auto epsilon : {1e-6}) { 19 | for (auto side : {'L', 'R'}) { 20 | for (auto operation : {'N', 'T', 'C'}) { 21 | for (auto diag : {'N', 'U'}) { 22 | 23 | std::cout << "task based hmatrix triangular solve test case: " << "number_of_rhs = " << number_of_rhs << ", epsilon = " << epsilon << ", n1 = " << n1 << ", side = " << side << ", operation = " << operation << ", diag = " << diag << "\n"; 24 | 25 | TestCaseSolve, GeneratorTestComplexHermitian> test_case(side, operation, n1, number_of_rhs, 1, -1); 26 | 27 | is_error = is_error || test_task_based_hmatrix_triangular_solve, GeneratorTestComplexHermitian, TestCaseSolve, GeneratorTestComplexHermitian>>(test_case, side, operation, diag, epsilon); 28 | } 29 | } 30 | } 31 | } 32 | 33 | std::cout << "+++++++++++++++++++++++++++++++++++++++++++" << std::endl; 34 | if (is_error) { 35 | htool::Logger::get_instance().log(LogLevel::ERROR, "At least one test_task_based_hmatrix_triangular_solve case failed."); // LCOV_EXCL_LINE 36 | return 1; 37 | 38 | } else { 39 | std::cout << "SUCCESS: All test_task_based_hmatrix_triangular_solve cases passed." << std::endl; 40 | } 41 | std::cout << "+++++++++++++++++++++++++++++++++++++++++++" << std::endl; 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_product/test_hmatrix_product_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_hmatrix_product.hpp" // for test_hm... 2 | #include // for max, copy 3 | #include // for array 4 | #include // for Generat... 5 | #include // for initial... 6 | #include // for basic_o... 7 | #include // for MPI_Fin... 8 | 9 | using namespace std; 10 | using namespace htool; 11 | 12 | int main(int argc, char *argv[]) { 13 | 14 | MPI_Init(&argc, &argv); 15 | bool is_error = false; 16 | const std::array additional_lrmat_sum_tolerances{10., 10., 10., 10., 10.}; 17 | 18 | for (auto epsilon : {1e-6, 1e-10}) { 19 | for (auto n1 : {200, 400}) { 20 | for (auto n3 : {100}) { 21 | for (auto use_local_cluster : {true, false}) { 22 | for (auto n2 : {200, 400}) { 23 | for (auto transa : {'N', 'T'}) { 24 | for (auto transb : {'N', 'T'}) { 25 | std::cout << "hmatrix product: " << use_local_cluster << " " << epsilon << " " << n1 << " " << n2 << " " << n3 << " " << transa << " " << transb << "\n"; 26 | 27 | is_error = is_error || test_hmatrix_product(transa, transb, n1, n2, n3, use_local_cluster, epsilon, additional_lrmat_sum_tolerances); 28 | } 29 | } 30 | } 31 | } 32 | for (auto side : {'L', 'R'}) { 33 | for (auto UPLO : {'U', 'L'}) { 34 | const double margin = 0; 35 | std::cout << "symmetric matrix product: " << n1 << " " << n3 << " " << side << " " << UPLO << " " << epsilon << "\n"; 36 | is_error = is_error || test_symmetric_hmatrix_product(n1, n3, side, UPLO, epsilon, margin); 37 | } 38 | } 39 | } 40 | } 41 | } 42 | MPI_Finalize(); 43 | if (is_error) { 44 | return 1; 45 | } 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /include/htool/testing/geometry.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef HTOOL_TESTING_GEOMETRY_HPP 3 | #define HTOOL_TESTING_GEOMETRY_HPP 4 | 5 | #include // for array 6 | #include // for M_PI, cbrt 7 | #include // for mt19937, uniform_real_distribution 8 | namespace htool { 9 | 10 | template 11 | void create_rotated_ellipse(int space_dim, T a, T b, T alpha, T z, int nr, T *const xt) { 12 | std::mt19937 mersenne_engine(0); 13 | std::uniform_real_distribution dist(0, 1); 14 | auto gen = [&dist, &mersenne_engine]() { 15 | return dist(mersenne_engine); 16 | }; 17 | 18 | T cos_alpha = std::cos(alpha); 19 | T sin_alpha = std::sin(alpha); 20 | 21 | for (int j = 0; j < nr; j++) { 22 | T rho = gen(); 23 | T theta = gen(); 24 | T r = std::sqrt(rho); 25 | T phi = 2 * static_cast(M_PI) * theta; 26 | 27 | // Axis-aligned ellipse coordinates 28 | T x_prime = a * r * std::cos(phi); 29 | T y_prime = b * r * std::sin(phi); 30 | 31 | // Apply rotation 32 | xt[space_dim * j + 0] = cos_alpha * x_prime - sin_alpha * y_prime; 33 | xt[space_dim * j + 1] = sin_alpha * x_prime + cos_alpha * y_prime; 34 | 35 | if (space_dim == 3) 36 | xt[space_dim * j + 2] = z; 37 | } 38 | } 39 | 40 | template 41 | void create_disk(int space_dim, T z, int nr, T *const xt) { 42 | create_rotated_ellipse(space_dim, T(1.), T(1.), T(0.), z, nr, xt); 43 | } 44 | 45 | template 46 | void create_sphere(int nr, T *const xt, std::array offset = {0, 0, 0}) { 47 | 48 | std::mt19937 mersenne_engine(0); 49 | std::uniform_real_distribution dist(0, 1); 50 | auto gen = [&dist, &mersenne_engine]() { 51 | return dist(mersenne_engine); 52 | }; 53 | for (int j = 0; j < nr; j++) { 54 | T rho = gen(); // (T) otherwise integer division! 55 | T theta = 2 * M_PI * gen(); 56 | T phi = std::acos(2 * gen() - 1); 57 | xt[3 * j + 0] = offset[0] + std::cbrt(rho) * std::sin(phi) * std::cos(theta); 58 | xt[3 * j + 1] = offset[1] + std::cbrt(rho) * std::sin(phi) * std::sin(theta); 59 | xt[3 * j + 2] = offset[2] + std::cbrt(rho) * std::cos(phi); 60 | } 61 | } 62 | 63 | } // namespace htool 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_build/test_task_based_hmatrix_build_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_hmatrix_build.hpp" // for test_hmatrix_build 2 | #include // for max 3 | #include 4 | #include // for GeneratorTestComplexSymm... 5 | #include // for initializer_list 6 | #include // for basic_ostream, char_traits 7 | #include // for MPI_Finalize, MPI_Init 8 | using namespace std; 9 | using namespace htool; 10 | 11 | int main(int argc, char *argv[]) { 12 | MPI_Init(&argc, &argv); 13 | 14 | bool is_error = false; 15 | 16 | for (auto nr : {200, 400}) { 17 | for (auto nc : {200, 400}) { 18 | for (auto use_local_cluster : {true, false}) { 19 | for (auto epsilon : {1e-14, 1e-6}) { 20 | for (auto use_dense_block_generator : {true, false}) { 21 | for (auto block_tree_consistency : {true, false}) { 22 | std::cout << nr << " " << nc << " " << use_local_cluster << " " << epsilon << " " << use_dense_block_generator << " " << block_tree_consistency << "\n"; 23 | 24 | is_error = is_error || test_hmatrix_build &&, double, GeneratorTestDoubleSymmetric>(omp_task_policy{}, nr, nc, use_local_cluster, 'N', 'N', epsilon, use_dense_block_generator, block_tree_consistency); 25 | 26 | if (nr == nc && block_tree_consistency) { 27 | for (auto UPLO : {'U', 'L'}) { 28 | std::cout << UPLO << "\n"; 29 | is_error = is_error || test_hmatrix_build &&, double, GeneratorTestDoubleSymmetric>(omp_task_policy{}, nr, nc, use_local_cluster, 'S', UPLO, epsilon, use_dense_block_generator, block_tree_consistency); 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | 39 | MPI_Finalize(); 40 | 41 | if (is_error) { 42 | return 1; 43 | } 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /include/htool/hmatrix/interfaces/virtual_generator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_HMATRIX_VIRTUAL_GENERATOR_HPP 2 | #define HTOOL_HMATRIX_VIRTUAL_GENERATOR_HPP 3 | 4 | namespace htool { 5 | 6 | template 7 | class VirtualInternalGenerator { 8 | 9 | public: 10 | virtual void copy_submatrix(int M, int N, int row_offset, int col_offset, CoefficientPrecision *ptr) const = 0; 11 | 12 | VirtualInternalGenerator() {} 13 | VirtualInternalGenerator(const VirtualInternalGenerator &) = default; 14 | VirtualInternalGenerator &operator=(const VirtualInternalGenerator &) = default; 15 | VirtualInternalGenerator(VirtualInternalGenerator &&) = default; 16 | VirtualInternalGenerator &operator=(VirtualInternalGenerator &&) = default; 17 | virtual ~VirtualInternalGenerator() {} 18 | }; 19 | 20 | template 21 | class VirtualGenerator { 22 | 23 | public: 24 | virtual void copy_submatrix(int M, int N, const int *rows, const int *cols, CoefficientPrecision *ptr) const = 0; 25 | 26 | VirtualGenerator() {} 27 | VirtualGenerator(const VirtualGenerator &) = default; 28 | VirtualGenerator &operator=(const VirtualGenerator &) = default; 29 | VirtualGenerator(VirtualGenerator &&) = default; 30 | VirtualGenerator &operator=(VirtualGenerator &&) = default; 31 | virtual ~VirtualGenerator() {} 32 | }; 33 | 34 | template 35 | class InternalGeneratorWithPermutation : public VirtualInternalGenerator { 36 | 37 | protected: 38 | const VirtualGenerator &m_generator_in_user_numbering; 39 | const int *m_target_permutation; 40 | const int *m_source_permutation; 41 | 42 | public: 43 | InternalGeneratorWithPermutation(const VirtualGenerator &generator_in_user_numbering, const int *target_permutation, const int *source_permutation) : m_generator_in_user_numbering(generator_in_user_numbering), m_target_permutation(target_permutation), m_source_permutation(source_permutation) { 44 | } 45 | 46 | virtual void copy_submatrix(int M, int N, int row_offset, int col_offset, CoefficientPrecision *ptr) const override { 47 | m_generator_in_user_numbering.copy_submatrix(M, N, m_target_permutation + row_offset, m_source_permutation + col_offset, ptr); 48 | } 49 | }; 50 | 51 | } // namespace htool 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /cmake/version.cmake: -------------------------------------------------------------------------------- 1 | # Git 2 | find_package(Git) 3 | if(Git_FOUND) 4 | message(STATUS "Git found: ${GIT_EXECUTABLE}") 5 | else() 6 | message(STATUS "Git not found!") 7 | endif() 8 | 9 | function(check_version_number CODE_VERSION_FILE CODE_VARIABLE_MAJOR_VERSION CODE_VARIABLE_MINOR_VERSION CODE_VARIABLE_SUBMINOR_VERSION) 10 | # Git version number 11 | if(Git_FOUND) 12 | set(git_version_number "unknown") 13 | execute_process( 14 | COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0 15 | WORKING_DIRECTORY "${local_dir}" 16 | OUTPUT_VARIABLE git_version_number 17 | ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) 18 | endif() 19 | 20 | # source version number 21 | set(VERSION_FILE) 22 | if(EXISTS ${CODE_VERSION_FILE}) 23 | set(VERSION_FILE ${CODE_VERSION_FILE}) 24 | elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${CODE_VERSION_FILE}) 25 | set(VERSION_FILE ${VERSION_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/${CODE_VERSION_FILE}) 26 | else() 27 | message(FATAL_ERROR "Source file with version number not found") 28 | endif() 29 | 30 | file(READ ${VERSION_FILE} ver) 31 | string(REGEX MATCH "${CODE_VARIABLE_MAJOR_VERSION} ([0-9]+)" _ ${ver}) 32 | set(code_major_version_number ${CMAKE_MATCH_1}) 33 | string(REGEX MATCH "${CODE_VARIABLE_MINOR_VERSION} ([0-9]+)" _ ${ver}) 34 | set(code_minor_version_number ${CMAKE_MATCH_1}) 35 | string(REGEX MATCH "${CODE_VARIABLE_SUBMINOR_VERSION} ([0-9]+)" _ ${ver}) 36 | set(code_subminor_version_number ${CMAKE_MATCH_1}) 37 | 38 | set(code_version_number "${code_major_version_number}.${code_minor_version_number}.${code_subminor_version_number}") 39 | message(STATUS "Htool version: " "${code_version_number}") 40 | # Check version number: error if code unconsistent 41 | if(NOT "${code_version_number}" STREQUAL "${CMAKE_PROJECT_VERSION}") 42 | message(FATAL_ERROR "Inconsistent version number:\n* Source code version number: ${code_version_number}\n* CMake version number: ${CMAKE_PROJECT_VERSION}\n") 43 | endif() 44 | # Check version number: warning if git tags inconsistent 45 | if(NOT "${git_version_number}" STREQUAL "v${CMAKE_PROJECT_VERSION}") 46 | message(WARNING "Inconsistent version number:\n* GIT last tag: ${git_version_number}\n* Source code version number: ${code_version_number}\n* CMake version number: ${CMAKE_PROJECT_VERSION}\n") 47 | endif() 48 | endfunction() 49 | -------------------------------------------------------------------------------- /include/htool/hmatrix/linalg/scale.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_HMATRIX_LINALG_SCALE_HPP 2 | #define HTOOL_HMATRIX_LINALG_SCALE_HPP 3 | 4 | #include "../hmatrix.hpp" // for HMatrix 5 | #include "../lrmat/linalg/scale.hpp" 6 | #include "htool/basic_types/tree.hpp" // for preorder_tree_traversal 7 | #include // for vector 8 | 9 | namespace htool { 10 | 11 | template > 12 | void openmp_scale(CoefficientPrecision da, HMatrix &A) { 13 | std::vector *> leaves; 14 | preorder_tree_traversal(A, [&leaves](HMatrix ¤t_node) { 15 | if (!current_node.is_hierarchical()) { 16 | leaves.push_back(¤t_node); 17 | } 18 | }); 19 | 20 | #if defined(_OPENMP) 21 | # pragma omp parallel 22 | #endif 23 | { 24 | #if defined(_OPENMP) 25 | # pragma omp for schedule(guided) nowait 26 | #endif 27 | for (int b = 0; b < leaves.size(); b++) { 28 | if (leaves[b]->is_dense()) { 29 | scale(da, *leaves[b]->get_dense_data()); 30 | } else { 31 | scale(da, *leaves[b]->get_low_rank_data()); 32 | } 33 | } 34 | } 35 | } 36 | 37 | template > 38 | void sequential_scale(CoefficientPrecision da, HMatrix &A) { 39 | std::vector *> leaves; 40 | preorder_tree_traversal(A, [&leaves](HMatrix ¤t_node) { 41 | if (!current_node.is_hierarchical()) { 42 | leaves.push_back(¤t_node); 43 | } 44 | }); 45 | for (int b = 0; b < leaves.size(); b++) { 46 | if (leaves[b]->is_dense()) { 47 | scale(da, *leaves[b]->get_dense_data()); 48 | } else { 49 | scale(da, *leaves[b]->get_low_rank_data()); 50 | } 51 | } 52 | } 53 | 54 | template > 55 | void scale(CoefficientPrecision da, HMatrix &A) { 56 | sequential_scale(da, A); 57 | } 58 | 59 | } // namespace htool 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /tests/functional_tests/distributed_operator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | set(data_types "matrix") 6 | list(APPEND data_types "hmatrix") 7 | 8 | set(types "double") 9 | list(APPEND types "complex_double") 10 | 11 | # foreach(data_type ${data_types}) 12 | foreach(type ${types}) 13 | add_executable(Test_distributed_operator_product_${type} test_distributed_operator_product_${type}.cpp) 14 | target_link_libraries(Test_distributed_operator_product_${type} htool) 15 | add_dependencies(build-tests-distributed-operator Test_distributed_operator_product_${type}) 16 | add_test(NAME Test_distributed_operator_product_${type}_1 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 1 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_distributed_operator_product_${type}) 17 | set_tests_properties(Test_distributed_operator_product_${type}_1 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=4) 18 | set_tests_properties(Test_distributed_operator_product_${type}_1 PROPERTIES LABELS "mpi") 19 | add_test(NAME Test_distributed_operator_product_${type}_2 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_distributed_operator_product_${type}) 20 | set_tests_properties(Test_distributed_operator_product_${type}_2 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=2) 21 | set_tests_properties(Test_distributed_operator_product_${type}_2 PROPERTIES LABELS "mpi") 22 | add_test(NAME Test_distributed_operator_product_${type}_4 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_distributed_operator_product_${type}) 23 | set_tests_properties(Test_distributed_operator_product_${type}_4 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=1) 24 | set_tests_properties(Test_distributed_operator_product_${type}_4 PROPERTIES LABELS "mpi") 25 | endforeach() 26 | # endforeach() 27 | 28 | # add_executable(Test_distributed_operator_mat_prod_complex_double test_distributed_operator_mat_prod_complex_double.cpp) 29 | # target_link_libraries(Test_distributed_operator_mat_prod_complex_double htool) 30 | # add_dependencies(build-tests-distributed-operator Test_distributed_operator_mat_prod_complex_double) 31 | 32 | # add_test(Test_distributed_operator_mat_prod_complex_double Test_distributed_operator_mat_prod_complex_double) 33 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/lrmat/test_matrix_matrix_product.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include // for LowRank... 3 | #include // for normFrob 4 | #include // for underly... 5 | #include // for basic_o... 6 | 7 | using namespace std; 8 | using namespace htool; 9 | 10 | template 11 | bool test_matrix_matrix_product(char transa, char transb, T alpha, T beta, const LowRankMatrix &C_auto_approximation, const Matrix &A_dense, const Matrix &B_dense, const Matrix &matrix_result_wo_sum, const Matrix &matrix_result_w_lrmat_sum, htool::underlying_type epsilon, htool::underlying_type additional_compression_tolerance, htool::underlying_type additional_lrmat_sum_tolerance) { 12 | bool is_error = false; 13 | LowRankMatrix lrmat_test(A_dense.nb_rows(), B_dense.nb_cols(), epsilon); 14 | Matrix matrix_test, dense_lrmat_test; 15 | htool::underlying_type error; 16 | 17 | // Product 18 | lrmat_test = C_auto_approximation; 19 | add_matrix_matrix_product(transa, transb, alpha, A_dense, B_dense, T(0), lrmat_test); 20 | dense_lrmat_test.resize(lrmat_test.get_U().nb_rows(), lrmat_test.get_V().nb_cols()); 21 | lrmat_test.copy_to_dense(dense_lrmat_test.data()); 22 | error = normFrob(matrix_result_wo_sum - dense_lrmat_test) / normFrob(matrix_result_wo_sum); 23 | is_error = is_error || !(error < epsilon); 24 | cout << "> Errors on a matrix matrix product to lrmat without sum: " << error << " vs " << epsilon << endl; 25 | 26 | lrmat_test = C_auto_approximation; 27 | add_matrix_matrix_product(transa, transb, alpha, A_dense, B_dense, beta, lrmat_test); 28 | dense_lrmat_test.resize(lrmat_test.get_U().nb_rows(), lrmat_test.get_V().nb_cols()); 29 | lrmat_test.copy_to_dense(dense_lrmat_test.data()); 30 | error = normFrob(matrix_result_w_lrmat_sum - dense_lrmat_test) / normFrob(matrix_result_w_lrmat_sum); 31 | is_error = is_error || !(error < epsilon * (1 + additional_compression_tolerance + additional_lrmat_sum_tolerance)); 32 | cout << "> Errors on a matrix matrix product to lrmat with sum: " << error << " vs " << epsilon * (1 + additional_compression_tolerance + additional_lrmat_sum_tolerance) << endl; 33 | 34 | cout << "test : " << is_error << endl 35 | << endl; 36 | 37 | return is_error; 38 | } 39 | -------------------------------------------------------------------------------- /tools/plot_hmatrix.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import matplotlib.patches as patches 4 | import matplotlib.colors as colors 5 | import pandas as pd 6 | import argparse 7 | 8 | parser = argparse.ArgumentParser() 9 | parser.add_argument("--inputfile", type=str) 10 | parser.add_argument("--show", type=int, choices=[0, 1], default=1) 11 | parser.add_argument("--save", type=str, default="") 12 | 13 | args = parser.parse_args() 14 | inputfile = args.inputfile 15 | 16 | # First Data 17 | size = pd.read_csv(inputfile, nrows=1, header=None) 18 | nr = size.iloc[0][0] 19 | nc = size.iloc[0][1] 20 | matrix = np.zeros((nr, nc)) 21 | 22 | # Figure 23 | fig, axes = plt.subplots(1, 1) 24 | axes.xaxis.tick_top() 25 | plt.imshow(matrix) 26 | 27 | # Issue: there a shift of one pixel along the y-axis... 28 | shift = axes.transData.transform([(0, 0), (1, 1)]) 29 | shift = shift[1, 1] - shift[0, 1] # 1 unit in display coords 30 | shift = 0 31 | # 1/shift # 1 pixel in display coords 32 | 33 | # Loop 34 | data = pd.read_csv(inputfile, skiprows=1, header=None) 35 | for index, row in data.iterrows(): 36 | matrix[ 37 | np.ix_(range(row[0], row[0] + row[1]), range(row[2], row[2] + row[3])) 38 | ] = row[4] 39 | rect = patches.Rectangle( 40 | (row[2] - 0.5, row[0] - 0.5 + shift), 41 | row[3], 42 | row[1], 43 | linewidth=0.75, 44 | edgecolor="k", 45 | facecolor="none", 46 | ) 47 | axes.add_patch(rect) 48 | if row[4] >= 0 and row[3] / float(nc) > 0.05 and row[1] / float(nc) > 0.05: 49 | axes.annotate( 50 | row[4], 51 | (row[2] + row[3] / 2.0, row[0] + row[1] / 2.0), 52 | color="white", 53 | size=10, 54 | va="center", 55 | ha="center", 56 | ) 57 | 58 | 59 | # Colormap 60 | def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=100): 61 | new_cmap = colors.LinearSegmentedColormap.from_list( 62 | "trunc({n},{a:.2f},{b:.2f})".format(n=cmap.name, a=minval, b=maxval), 63 | cmap(np.linspace(minval, maxval, n)), 64 | ) 65 | return new_cmap 66 | 67 | 68 | cmap = plt.get_cmap("YlGn") 69 | new_cmap = truncate_colormap(cmap, 0.4, 1) 70 | 71 | 72 | # Plot 73 | matrix = np.ma.masked_where(0 > matrix, matrix) 74 | new_cmap.set_bad(color="red") 75 | plt.imshow(matrix, cmap=new_cmap, vmin=0, vmax=10) 76 | 77 | # Output 78 | if args.show: 79 | plt.show() 80 | 81 | 82 | if args.save != "": 83 | fig.savefig(args.save, bbox_inches="tight", pad_inches=0) 84 | -------------------------------------------------------------------------------- /tests/functional_tests/local_operators/test_local_operator_dense_matrix.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | using namespace htool; 10 | 11 | int main(int argc, char *argv[]) { 12 | MPI_Init(&argc, &argv); 13 | int sizeWorld; 14 | MPI_Comm_size(MPI_COMM_WORLD, &sizeWorld); 15 | srand(1); 16 | bool test = 0; 17 | 18 | // Geometry 19 | int size = 200; 20 | int dim = 3; 21 | vector pt(size * dim); 22 | vector r(size, 0); 23 | vector g(size, 1); 24 | vector tab(size); 25 | 26 | double z1 = 1; 27 | create_disk(dim, z1, size, pt.data()); 28 | 29 | // Cluster 30 | ClusterTreeBuilder, RegularSplitting> recursive_build_strategy(size, dim, pt.data(), r.data(), g.data(), 2, sizeWorld); 31 | 32 | std::shared_ptr> cluster = make_shared>(recursive_build_strategy.create_cluster_tree()); 33 | 34 | // Generator 35 | GeneratorTestDoubleSymmetric generator(3, size, size, pt, pt, cluster, cluster); 36 | 37 | // LocalDenseMatrix 38 | LocalDenseMatrix A(generator, cluster, cluster); 39 | 40 | // Random input vector 41 | std::vector in(size, 1); 42 | 43 | double lower_bound = 0; 44 | double upper_bound = 10000; 45 | std::random_device rd; 46 | std::mt19937 mersenne_engine(rd()); 47 | std::uniform_real_distribution dist(lower_bound, upper_bound); 48 | auto gen = [&dist, &mersenne_engine]() { 49 | return dist(mersenne_engine); 50 | }; 51 | generate(begin(in), end(in), gen); 52 | 53 | // Test 54 | std::vector in_permuted(size, 1); 55 | std::vector out(size, 1); 56 | std::vector out_permuted(size, 0); 57 | std::vector out_ref(size, 1); 58 | generator.mvprod(in.data(), out_ref.data(), 1); 59 | 60 | global_to_root_cluster(*cluster, in.data(), in_permuted.data()); 61 | A.add_vector_product_global_to_local(1, in_permuted.data(), 0, out_permuted.data()); 62 | root_cluster_to_global(*cluster, out_permuted.data(), out.data()); 63 | 64 | // Error 65 | double error = norm2(out - out_ref) / norm2(out_ref); 66 | cout << "error: " << error << endl; 67 | test = test || !(error < 1e-14); 68 | 69 | MPI_Finalize(); 70 | return test; 71 | } 72 | -------------------------------------------------------------------------------- /tests/functional_tests/clustering/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | add_executable(Test_cluster test_cluster.cpp) 6 | target_link_libraries(Test_cluster htool) 7 | add_dependencies(build-tests-clustering Test_cluster) 8 | 9 | add_test(NAME Test_cluster_1 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 1 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_cluster) 10 | set_tests_properties(Test_cluster_1 PROPERTIES LABELS "mpi") 11 | add_test(NAME Test_cluster_2 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_cluster) 12 | set_tests_properties(Test_cluster_2 PROPERTIES LABELS "mpi") 13 | add_test(NAME Test_cluster_3 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 3 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_cluster) 14 | set_tests_properties(Test_cluster_3 PROPERTIES LABELS "mpi") 15 | add_test(NAME Test_cluster_4 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_cluster) 16 | set_tests_properties(Test_cluster_4 PROPERTIES LABELS "mpi") 17 | 18 | # set(cluster_types "pca") 19 | # list(APPEND cluster_types "bounding_box") 20 | 21 | # set(splitting_types "geometric_splitting") 22 | # list(APPEND splitting_types "regular_splitting") 23 | 24 | # foreach(cluster_type ${cluster_types}) 25 | # foreach(splitting_type ${splitting_types}) 26 | 27 | # add_executable(Test_cluster_${cluster_type}_${splitting_type} test_cluster_${cluster_type}_${splitting_type}.cpp) 28 | # target_link_libraries(Test_cluster_${cluster_type}_${splitting_type} htool) 29 | # add_dependencies(build-tests-clustering Test_cluster_${cluster_type}_${splitting_type}) 30 | 31 | # add_test(NAME Test_cluster_${cluster_type}_${splitting_type}_1 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 1 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_cluster_${cluster_type}_${splitting_type}) 32 | 33 | # add_test(NAME Test_cluster_${cluster_type}_${splitting_type}_2 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_cluster_${cluster_type}_${splitting_type}) 34 | 35 | # add_test(NAME Test_cluster_${cluster_type}_${splitting_type}_4 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_cluster_${cluster_type}_${splitting_type}) 36 | 37 | # endforeach() 38 | # endforeach() 39 | -------------------------------------------------------------------------------- /include/htool/matrix/utils/SVD_truncation.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_MATRIX_UTILS_SVD_TRUNCATION_HPP 2 | #define HTOOL_MATRIX_UTILS_SVD_TRUNCATION_HPP 3 | 4 | #include "../../matrix/matrix.hpp" // for Matrix 5 | #include "../../misc/misc.hpp" // for underlying_type 6 | #include "../../wrappers/wrapper_lapack.hpp" // for Lapack 7 | #include // for min 8 | #include // for real 9 | #include // for vector 10 | 11 | namespace htool { 12 | 13 | template 14 | int SVD_truncation(Matrix &A, htool::underlying_type epsilon, Matrix &u, Matrix &vt, std::vector> &singular_values) { 15 | // A= u*S*vt 16 | singular_values.resize(std::min(A.nb_rows(), A.nb_cols())); 17 | u.resize(A.nb_rows(), A.nb_rows()); 18 | vt.resize(A.nb_cols(), A.nb_cols()); 19 | { 20 | int M = A.nb_rows(); 21 | int N = A.nb_cols(); 22 | int lda = M; 23 | int ldu = M; 24 | int ldvt = N; 25 | int lwork = -1; 26 | int info; 27 | std::vector work(1); 28 | std::vector> rwork(5 * std::min(M, N)); 29 | 30 | Lapack::gesvd("A", "A", &M, &N, A.data(), &lda, singular_values.data(), u.data(), &ldu, vt.data(), &ldvt, work.data(), &lwork, rwork.data(), &info); 31 | lwork = static_cast(std::real(work[0])); 32 | work.resize(lwork); 33 | Lapack::gesvd("A", "A", &M, &N, A.data(), &lda, singular_values.data(), u.data(), &ldu, vt.data(), &ldvt, work.data(), &lwork, rwork.data(), &info); 34 | } 35 | 36 | // Compute truncated rank to define tildeS 37 | int truncated_rank; 38 | { 39 | int j = singular_values.size(); 40 | underlying_type svd_norm = 0; 41 | underlying_type error = 0; 42 | for (auto &elt : singular_values) 43 | svd_norm += elt * elt; 44 | svd_norm = std::sqrt(svd_norm); 45 | 46 | do { 47 | j = j - 1; 48 | error += std::pow(std::abs(singular_values[j]), 2); 49 | } while (j > 0 && std::sqrt(error) / svd_norm < epsilon); 50 | 51 | truncated_rank = j + 1; 52 | } 53 | 54 | return truncated_rank; 55 | } 56 | } // namespace htool 57 | #endif 58 | -------------------------------------------------------------------------------- /include/htool/matrix/utils/output.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_MATRIX_UTILS_OUTPUT_HPP 2 | #define HTOOL_MATRIX_UTILS_OUTPUT_HPP 3 | 4 | #include "../../misc/logger.hpp" 5 | #include "modifiers.hpp" 6 | #include 7 | #include 8 | #include 9 | 10 | namespace htool { 11 | 12 | template 13 | void print(const Mat &mat, std::ostream &os, const std::string &delimiter) { 14 | using T = typename Mat::value_type; 15 | int rows = mat.nb_rows(); 16 | 17 | if (mat.nb_cols() > 0) { 18 | for (int i = 0; i < rows; i++) { 19 | std::vector row = get_row(mat, i); 20 | std::copy(row.begin(), row.end() - 1, std::ostream_iterator(os, delimiter.c_str())); 21 | os << row.back(); 22 | os << '\n'; 23 | } 24 | } 25 | } 26 | 27 | template 28 | void csv_save(const Mat &mat, const std::string &file, const std::string &delimiter = ",") { 29 | std::ofstream os(file); 30 | if (!os) { 31 | htool::Logger::get_instance().log(LogLevel::WARNING, "Cannot create file " + file); // LCOV_EXCL_LINE 32 | } 33 | 34 | print(mat, os, delimiter); 35 | 36 | os.close(); 37 | } 38 | 39 | template 40 | void matrix_to_bytes(const Mat &mat, const std::string &file) { 41 | using T = typename Mat::value_type; 42 | std::ofstream out(file, std::ios::out | std::ios::binary | std::ios::trunc); 43 | 44 | if (!out) { 45 | htool::Logger::get_instance().log(LogLevel::WARNING, "Cannot open file " + file); // LCOV_EXCL_LINE 46 | } 47 | int rows = mat.nb_rows(); 48 | int cols = mat.nb_cols(); 49 | out.write(reinterpret_cast(&rows), sizeof(int)); 50 | out.write(reinterpret_cast(&cols), sizeof(int)); 51 | out.write(reinterpret_cast(mat.data()), rows * cols * sizeof(T)); 52 | 53 | out.close(); 54 | } 55 | 56 | template 57 | void bytes_to_matrix(const std::string &file, Matrix &mat) { 58 | std::ifstream in(file, std::ios::in | std::ios::binary); 59 | 60 | if (!in) { 61 | htool::Logger::get_instance().log(LogLevel::WARNING, "Cannot open file " + file); // LCOV_EXCL_LINE 62 | } 63 | 64 | int rows = 0, cols = 0; 65 | in.read(reinterpret_cast(&rows), sizeof(int)); 66 | in.read(reinterpret_cast(&cols), sizeof(int)); 67 | T *new_data = new T[rows * cols]; 68 | mat.assign(rows, cols, new_data, true); 69 | in.read(reinterpret_cast(&(new_data[0])), rows * cols * sizeof(T)); 70 | 71 | in.close(); 72 | } 73 | 74 | } // namespace htool 75 | #endif 76 | -------------------------------------------------------------------------------- /include/htool/distributed_operator/implementations/partition_from_cluster.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_DISTRIBUTED_OPERATOR_PARTITION_FROM_CLUSTER_HPP 2 | #define HTOOL_DISTRIBUTED_OPERATOR_PARTITION_FROM_CLUSTER_HPP 3 | 4 | #include "../../clustering/cluster_node.hpp" // for global_to_root_cluster 5 | #include "../../misc/misc.hpp" // for underlying_type 6 | #include "../interfaces/virtual_partition.hpp" // for IPartition 7 | 8 | namespace htool { 9 | 10 | template > 11 | class PartitionFromCluster final : public VirtualPartition { 12 | const Cluster &m_root_cluster; 13 | 14 | public: 15 | explicit PartitionFromCluster(const Cluster &root_cluster) : m_root_cluster(root_cluster) {} 16 | 17 | PartitionFromCluster(const PartitionFromCluster &) = default; 18 | PartitionFromCluster &operator=(const PartitionFromCluster &) = default; 19 | PartitionFromCluster(PartitionFromCluster &&PartitionFromCluster) noexcept = default; 20 | PartitionFromCluster &operator=(PartitionFromCluster &&PartitionFromCluster) noexcept = default; 21 | 22 | int get_size_of_partition(int subdomain_number) const { return m_root_cluster.get_clusters_on_partition()[subdomain_number]->get_size(); } 23 | int get_offset_of_partition(int subdomain_number) const { return m_root_cluster.get_clusters_on_partition()[subdomain_number]->get_offset(); } 24 | 25 | int get_global_size() const { return m_root_cluster.get_size(); } 26 | 27 | void global_to_partition_numbering(const CoefficientPrecision *const in, CoefficientPrecision *const out) const { 28 | global_to_root_cluster(m_root_cluster, in, out); 29 | } 30 | void partition_to_global_numbering(const CoefficientPrecision *const in, CoefficientPrecision *const out) const { 31 | root_cluster_to_global(m_root_cluster, in, out); 32 | } 33 | 34 | void local_to_local_partition_numbering(int subdomain_number, const CoefficientPrecision *const in, CoefficientPrecision *const out) const { 35 | local_to_local_cluster(m_root_cluster, subdomain_number, in, out); 36 | } 37 | void local_partition_to_local_numbering(int subdomain_number, const CoefficientPrecision *const in, CoefficientPrecision *const out) const { 38 | local_cluster_to_local(m_root_cluster, subdomain_number, in, out); 39 | } 40 | 41 | bool is_renumbering_local() const { return m_root_cluster.is_permutation_local(); } 42 | }; 43 | } // namespace htool 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_product/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | set(types "double") 6 | list(APPEND types "complex_double") 7 | 8 | foreach(type ${types}) 9 | add_executable(Test_hmatrix_product_${type} test_hmatrix_product_${type}.cpp) 10 | target_link_libraries(Test_hmatrix_product_${type} htool) 11 | add_dependencies(build-tests-hmatrix-product Test_hmatrix_product_${type}) 12 | add_test(NAME Test_hmatrix_product_${type}_1 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 1 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_hmatrix_product_${type}) 13 | set_tests_properties(Test_hmatrix_product_${type}_1 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=4) 14 | set_tests_properties(Test_hmatrix_product_${type}_1 PROPERTIES LABELS "mpi") 15 | add_test(NAME Test_hmatrix_product_${type}_2 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_hmatrix_product_${type}) 16 | set_tests_properties(Test_hmatrix_product_${type}_2 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=2) 17 | set_tests_properties(Test_hmatrix_product_${type}_2 PROPERTIES LABELS "mpi") 18 | add_test(NAME Test_hmatrix_product_${type}_4 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_hmatrix_product_${type}) 19 | set_tests_properties(Test_hmatrix_product_${type}_4 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=1) 20 | set_tests_properties(Test_hmatrix_product_${type}_4 PROPERTIES LABELS "mpi") 21 | endforeach() 22 | 23 | foreach(type ${types}) 24 | add_executable(Test_task_based_hmatrix_product_${type} test_task_based_hmatrix_product_${type}.cpp) 25 | target_link_libraries(Test_task_based_hmatrix_product_${type} htool) 26 | add_dependencies(build-tests-hmatrix-product Test_task_based_hmatrix_product_${type}) 27 | add_test(Test_task_based_hmatrix_product_${type}_1 Test_task_based_hmatrix_product_${type}) 28 | set_tests_properties(Test_task_based_hmatrix_product_${type}_1 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=1) 29 | add_test(Test_task_based_hmatrix_product_${type}_2 Test_task_based_hmatrix_product_${type}) 30 | set_tests_properties(Test_task_based_hmatrix_product_${type}_2 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=2) 31 | add_test(Test_task_based_hmatrix_product_${type}_4 Test_task_based_hmatrix_product_${type}) 32 | set_tests_properties(Test_task_based_hmatrix_product_${type}_4 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=4) 33 | endforeach() 34 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_build/test_task_based_hmatrix_build_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_hmatrix_build.hpp" // for test_hmatrix_build 2 | #include // for max 3 | #include // for complex, abs, operator- 4 | #include // for GeneratorTestComplexSymm... 5 | #include // for initializer_list 6 | #include // for basic_ostream, char_traits 7 | #include // for MPI_Finalize, MPI_Init 8 | 9 | using namespace std; 10 | using namespace htool; 11 | 12 | int main(int argc, char *argv[]) { 13 | MPI_Init(&argc, &argv); 14 | 15 | bool is_error = false; 16 | 17 | for (auto nr : {200, 400}) { 18 | for (auto nc : {200, 400}) { 19 | for (auto use_local_cluster : {true, false}) { 20 | for (auto epsilon : {1e-14, 1e-6}) { 21 | for (auto use_dense_block_generator : {true, false}) { 22 | for (auto block_tree_consistency : {true, false}) { 23 | std::cout << nr << " " << nc << " " << use_local_cluster << " " << epsilon << " " << use_dense_block_generator << " " << block_tree_consistency << "\n"; 24 | 25 | is_error = is_error || test_hmatrix_build> &&, std::complex, GeneratorTestComplexSymmetric>(omp_task_policy>{}, nr, nc, use_local_cluster, 'N', 'N', epsilon, use_dense_block_generator, block_tree_consistency); 26 | if (nr == nc && block_tree_consistency) { 27 | for (auto UPLO : {'U', 'L'}) { 28 | is_error = is_error || test_hmatrix_build> &&, std::complex, GeneratorTestComplexSymmetric>(omp_task_policy>{}, nr, nr, use_local_cluster, 'S', UPLO, epsilon, use_dense_block_generator, block_tree_consistency); 29 | 30 | is_error = is_error || test_hmatrix_build> &&, std::complex, GeneratorTestComplexHermitian>(omp_task_policy>{}, nr, nr, use_local_cluster, 'H', UPLO, epsilon, use_dense_block_generator, block_tree_consistency); 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | 40 | MPI_Finalize(); 41 | 42 | if (is_error) { 43 | return 1; 44 | } 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_product/test_hmatrix_product_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_hmatrix_product.hpp" // for test_he... 2 | #include // for max, copy 3 | #include // for array 4 | #include // for complex 5 | #include // for Generat... 6 | #include // for initial... 7 | #include // for basic_o... 8 | #include // for MPI_Fin... 9 | using namespace std; 10 | using namespace htool; 11 | 12 | int main(int argc, char *argv[]) { 13 | 14 | MPI_Init(&argc, &argv); 15 | bool is_error = false; 16 | const std::array additional_lrmat_sum_tolerances{10., 10., 10., 10., 10.}; 17 | 18 | for (auto epsilon : {1e-10}) { 19 | for (auto n1 : {200, 400}) { 20 | for (auto n3 : {100}) { 21 | for (auto use_local_cluster : {true, false}) { 22 | for (auto n2 : {200, 400}) { 23 | for (auto transa : {'N', 'T', 'C'}) { 24 | for (auto transb : {'N', 'T', 'C'}) { 25 | std::cout << "hmatrix product: " << use_local_cluster << " " << epsilon << " " << n1 << " " << n2 << " " << n3 << " " << transa << " " << transb << "\n"; 26 | 27 | is_error = is_error || test_hmatrix_product, GeneratorTestComplex>(transa, transb, n1, n2, n3, use_local_cluster, epsilon, additional_lrmat_sum_tolerances); 28 | } 29 | } 30 | } 31 | } 32 | for (auto side : {'L', 'R'}) { 33 | for (auto UPLO : {'U', 'L'}) { 34 | const double margin = 0; 35 | std::cout << "symmetric matrix product: " << n1 << " " << n3 << " " << side << " " << UPLO << " " << epsilon << "\n"; 36 | is_error = is_error || test_symmetric_hmatrix_product, GeneratorTestComplexSymmetric>(n1, n3, side, UPLO, epsilon, margin); 37 | std::cout << "hermitian matrix product: " << n1 << " " << n3 << " " << side << " " << UPLO << " " << epsilon << "\n"; 38 | is_error = is_error || test_hermitian_hmatrix_product, GeneratorTestComplexHermitian>(n1, n3, side, UPLO, epsilon, margin); 39 | } 40 | } 41 | } 42 | } 43 | } 44 | MPI_Finalize(); 45 | if (is_error) { 46 | return 1; 47 | } 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_build/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | set(types "double") 6 | list(APPEND types "complex_double") 7 | 8 | foreach(type ${types}) 9 | add_executable(Test_hmatrix_build_${type} test_hmatrix_build_${type}.cpp) 10 | target_link_libraries(Test_hmatrix_build_${type} htool) 11 | add_dependencies(build-tests-hmatrix-build Test_hmatrix_build_${type}) 12 | add_test(NAME Test_hmatrix_build_${type}_1 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 1 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_hmatrix_build_${type}) 13 | set_tests_properties(Test_hmatrix_build_${type}_1 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=4) 14 | set_tests_properties(Test_hmatrix_build_${type}_1 PROPERTIES LABELS "mpi") 15 | 16 | add_test(NAME Test_hmatrix_build_${type}_2 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_hmatrix_build_${type}) 17 | set_tests_properties(Test_hmatrix_build_${type}_2 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=2) 18 | set_tests_properties(Test_hmatrix_build_${type}_2 PROPERTIES LABELS "mpi") 19 | 20 | add_test(NAME Test_hmatrix_build_${type}_4 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_hmatrix_build_${type}) 21 | set_tests_properties(Test_hmatrix_build_${type}_4 PROPERTIES ENVIRONMENT OMP_NUM_THREADS=1) 22 | set_tests_properties(Test_hmatrix_build_${type}_4 PROPERTIES LABELS "mpi") 23 | 24 | endforeach() 25 | 26 | foreach(type ${types}) 27 | add_executable(Test_task_based_hmatrix_build_${type} test_task_based_hmatrix_build_${type}.cpp) 28 | target_link_libraries(Test_task_based_hmatrix_build_${type} htool) 29 | add_dependencies(build-tests-hmatrix-build Test_task_based_hmatrix_build_${type}) 30 | add_test(Test_task_based_hmatrix_build_${type}_1 Test_task_based_hmatrix_build_${type}) 31 | set_tests_properties(Test_task_based_hmatrix_build_${type}_1 PROPERTIES ENVIRONMENT "ASAN_OPTIONS=detect_leaks=0;OMP_NUM_THREADS=1") 32 | 33 | add_test(Test_task_based_hmatrix_build_${type}_2 Test_task_based_hmatrix_build_${type}) 34 | set_tests_properties(Test_task_based_hmatrix_build_${type}_2 PROPERTIES ENVIRONMENT "ASAN_OPTIONS=detect_leaks=0;OMP_NUM_THREADS=2") 35 | 36 | add_test(Test_task_based_hmatrix_build_${type}_4 Test_task_based_hmatrix_build_${type}) 37 | set_tests_properties(Test_task_based_hmatrix_build_${type}_4 PROPERTIES ENVIRONMENT "ASAN_OPTIONS=detect_leaks=0;OMP_NUM_THREADS=4") 38 | 39 | endforeach() 40 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/task_based/test_task_based_hmatrix_dependencies.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_task_based_hmatrix_dependencies.hpp" 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | using namespace htool; 7 | 8 | int main(int, char *[]) { 9 | 10 | bool is_error = false; 11 | 12 | char sym = 'N'; 13 | for (auto epsilon : {1e-4, 1e-8}) { 14 | for (auto n1 : {1000}) { 15 | for (auto n2 : {1000, 1100}) { 16 | for (auto block_tree_consistency : {true}) { 17 | 18 | // Non symmetric case 19 | sym = 'N'; 20 | 21 | std::cout << "task based hmatrix build test case: " << "epsilon = " << epsilon << ", n1 = " << n1 << ", n2 = " << n2 << ", sym = " << sym << ", block_tree_consistency = " << block_tree_consistency << "\n"; 22 | 23 | TestCaseProduct test_case('N', 'N', n1, n2, 1, 1, 2); 24 | 25 | is_error = is_error || test_task_based_hmatrix_dependencies>(test_case, sym, epsilon, block_tree_consistency); 26 | 27 | // Symmetric case 28 | if (n1 == n2 && block_tree_consistency) { 29 | for (auto UPLO : {'L'}) { 30 | sym = 'S'; 31 | 32 | std::cout << "task based symmetric hmatrix build test case: " << "epsilon = " << epsilon << ", n1 = n2 = " << n1 << ", sym = " << sym << ", UPLO = " << UPLO << ", block_tree_consistency = " << block_tree_consistency << "\n"; 33 | 34 | TestCaseSymmetricProduct sym_test_case(n1, n2, 2, 'L', sym, UPLO); 35 | 36 | is_error = is_error || test_task_based_hmatrix_dependencies>(sym_test_case, sym, epsilon, block_tree_consistency, UPLO); // with symmetry 37 | } 38 | } 39 | } 40 | } 41 | } 42 | } 43 | std::cout << "+++++++++++++++++++++++++++++++++++++++++++" << std::endl; 44 | if (is_error) { 45 | htool::Logger::get_instance().log(LogLevel::ERROR, "At least one test_task_based_hmatrix_build case failed."); // LCOV_EXCL_LINE 46 | return 1; 47 | 48 | } else { 49 | std::cout << "SUCCESS: All test_task_based_hmatrix_build cases passed." << std::endl; 50 | } 51 | std::cout << "+++++++++++++++++++++++++++++++++++++++++++\n" 52 | << std::endl; 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /include/htool/distributed_operator/implementations/global_to_local_operators/hmatrix.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef HTOOL_DISTRIBUTED_OPERATOR_LOCAL_HMATRIX_HPP 3 | #define HTOOL_DISTRIBUTED_OPERATOR_LOCAL_HMATRIX_HPP 4 | 5 | #include "../../../clustering/cluster_node.hpp" // for Cluster 6 | #include "../../../hmatrix/hmatrix.hpp" 7 | #include "../../../hmatrix/linalg/add_hmatrix_matrix_product_row_major.hpp" 8 | #include "../../../hmatrix/linalg/add_hmatrix_vector_product.hpp" 9 | #include "../../../misc/misc.hpp" 10 | #include "restricted_operator.hpp" 11 | 12 | namespace htool { 13 | 14 | template > 15 | class RestrictedGlobalToLocalHMatrix final : public RestrictedGlobalToLocalOperator { 16 | const HMatrix &m_data; 17 | 18 | public: 19 | RestrictedGlobalToLocalHMatrix(const HMatrix &hmatrix, const LocalRenumbering &target_local_numbering, const LocalRenumbering &source_local_numbering, bool target_use_permutation_to_mvprod = false, bool source_use_permutation_to_mvprod = false) : RestrictedGlobalToLocalOperator(target_local_numbering, source_local_numbering, target_use_permutation_to_mvprod, source_use_permutation_to_mvprod), m_data(hmatrix) {} 20 | 21 | RestrictedGlobalToLocalHMatrix(const RestrictedGlobalToLocalHMatrix &) = default; 22 | RestrictedGlobalToLocalHMatrix &operator=(const RestrictedGlobalToLocalHMatrix &) = default; 23 | RestrictedGlobalToLocalHMatrix(RestrictedGlobalToLocalHMatrix &&RestrictedGlobalToLocalHMatrix) noexcept = default; 24 | RestrictedGlobalToLocalHMatrix &operator=(RestrictedGlobalToLocalHMatrix &&RestrictedGlobalToLocalHMatrix) noexcept = default; 25 | ~RestrictedGlobalToLocalHMatrix() = default; 26 | 27 | void local_add_vector_product(char trans, CoefficientPrecision alpha, const CoefficientPrecision *in, CoefficientPrecision beta, CoefficientPrecision *out) const override { 28 | openmp_internal_add_hmatrix_vector_product(trans, alpha, m_data, in, beta, out); 29 | } 30 | void local_add_matrix_product_row_major(char trans, CoefficientPrecision alpha, const CoefficientPrecision *in, CoefficientPrecision beta, CoefficientPrecision *out, int mu) const override { 31 | openmp_internal_add_hmatrix_matrix_product_row_major(trans, 'N', alpha, m_data, in, beta, out, mu); 32 | } 33 | 34 | const HMatrix &get_hmatrix() const { return *m_data.get(); } 35 | }; 36 | } // namespace htool 37 | #endif 38 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/hmatrix_build/test_hmatrix_build_double.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_hmatrix_build.hpp" // for test_hmatrix_build 2 | #include // for max 3 | #include 4 | #include // for GeneratorTestComplexSymm... 5 | #include // for initializer_list 6 | #include // for basic_ostream, char_traits 7 | #include // for MPI_Finalize, MPI_Init 8 | using namespace std; 9 | using namespace htool; 10 | 11 | int main(int argc, char *argv[]) { 12 | MPI_Init(&argc, &argv); 13 | 14 | bool is_error = false; 15 | 16 | for (auto nr : {200, 400}) { 17 | for (auto nc : {200, 400}) { 18 | for (auto use_local_cluster : {true, false}) { 19 | for (auto epsilon : {1e-14, 1e-6}) { 20 | for (auto use_dense_block_generator : {true, false}) { 21 | for (auto block_tree_consistency : {true, false}) { 22 | std::cout << nr << " " << nc << " " << use_local_cluster << " " << epsilon << " " << use_dense_block_generator << " " << block_tree_consistency << "\n"; 23 | 24 | is_error = is_error || test_hmatrix_build(exec_compat::seq, nr, nc, use_local_cluster, 'N', 'N', epsilon, use_dense_block_generator, block_tree_consistency); 25 | 26 | is_error = is_error || test_hmatrix_build(exec_compat::par, nr, nc, use_local_cluster, 'N', 'N', epsilon, use_dense_block_generator, block_tree_consistency); 27 | 28 | if (nr == nc && block_tree_consistency) { 29 | for (auto UPLO : {'U', 'L'}) { 30 | std::cout << UPLO << "\n"; 31 | is_error = is_error || test_hmatrix_build(exec_compat::seq, nr, nc, use_local_cluster, 'S', UPLO, epsilon, use_dense_block_generator, block_tree_consistency); 32 | 33 | is_error = is_error || test_hmatrix_build(exec_compat::par, nr, nc, use_local_cluster, 'S', UPLO, epsilon, use_dense_block_generator, block_tree_consistency); 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | } 41 | } 42 | 43 | MPI_Finalize(); 44 | 45 | if (is_error) { 46 | return 1; 47 | } 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /include/htool/distributed_operator/local_renumbering.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_LOCAL_RENUMBERING_HPP 2 | #define HTOOL_LOCAL_RENUMBERING_HPP 3 | 4 | #include "../clustering/cluster_node.hpp" 5 | 6 | namespace htool { 7 | class LocalRenumbering { 8 | int m_offset; 9 | int m_size; 10 | int m_global_size; 11 | const int *m_permutation; 12 | bool m_is_stable; 13 | 14 | public: 15 | LocalRenumbering(int offset, int size, int global_size, const int *permutation) : m_offset(offset), m_size(size), m_global_size(global_size), m_permutation(permutation), m_is_stable(true) {} 16 | template 17 | LocalRenumbering(const Cluster &cluster) : m_offset(cluster.get_offset()), m_size(cluster.get_size()), m_global_size(cluster.get_permutation().size()), m_permutation(cluster.get_permutation().data()), m_is_stable(cluster.is_root() || (is_cluster_on_partition(cluster) && cluster.is_permutation_local())) {} 18 | 19 | LocalRenumbering(const LocalRenumbering &) = default; 20 | LocalRenumbering &operator=(const LocalRenumbering &) = default; 21 | LocalRenumbering(LocalRenumbering &&) = default; 22 | LocalRenumbering &operator=(LocalRenumbering &&) = default; 23 | virtual ~LocalRenumbering() {} 24 | 25 | int get_offset() const { return m_offset; } 26 | int get_size() const { return m_size; } 27 | int get_global_size() const { return m_global_size; } 28 | const int *get_permutation() const { return m_permutation; } 29 | bool is_stable() const { return m_is_stable; } 30 | }; 31 | 32 | template 33 | void htool_to_user_numbering(const LocalRenumbering &local_renumbering, const CoefficientPrecision *in, CoefficientPrecision *out) { 34 | if (!local_renumbering.is_stable()) { 35 | htool::Logger::get_instance().log(LogLevel::ERROR, "Renumbering is not stable."); // LCOV_EXCL_LINE 36 | } 37 | const auto &permutation = local_renumbering.get_permutation(); 38 | for (int i = 0; i < local_renumbering.get_size(); i++) { 39 | out[permutation[local_renumbering.get_offset() + i] - local_renumbering.get_offset()] = in[i]; 40 | } 41 | } 42 | 43 | template 44 | void user_to_htool_numbering(const LocalRenumbering &local_renumbering, const CoefficientPrecision *in, CoefficientPrecision *out) { 45 | if (!local_renumbering.is_stable()) { 46 | htool::Logger::get_instance().log(LogLevel::ERROR, "Renumbering is not stable."); // LCOV_EXCL_LINE 47 | } 48 | 49 | const auto &permutation = local_renumbering.get_permutation(); 50 | for (int i = 0; i < local_renumbering.get_size(); i++) { 51 | out[i] = in[permutation[local_renumbering.get_offset() + i] - local_renumbering.get_offset()]; 52 | } 53 | } 54 | 55 | } // namespace htool 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /include/htool/matrix/matrix_view.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_BASIC_TYPES_MATRIX_VIEW_HPP 2 | #define HTOOL_BASIC_TYPES_MATRIX_VIEW_HPP 3 | 4 | #include "../misc/logger.hpp" // for Logger, LogLevel 5 | #include "../misc/misc.hpp" // for conj_if_complex, is_complex_t 6 | #include "matrix.hpp" // for Matrix 7 | #include // for transform, copy_n, fill_n 8 | #include // for sqrt 9 | #include // for conj, complex 10 | #include // for basic_ofstream, basic_ostream 11 | #include // for cout, cerr 12 | #include // for ostream_iterator 13 | #include // for operator+, basic_string, all... 14 | #include // for enable_if 15 | #include // for pair 16 | #include // for vector 17 | namespace htool { 18 | 19 | template 20 | class MatrixView { 21 | 22 | protected: 23 | int m_number_of_rows, m_number_of_cols; 24 | T *m_data; 25 | 26 | public: 27 | using element_type = T; 28 | using value_type = std::remove_cv_t; 29 | MatrixView() : m_number_of_rows(0), m_number_of_cols(0), m_data(nullptr) {} 30 | MatrixView(int nb_rows, int nb_cols, T *data) : m_number_of_rows(nb_rows), m_number_of_cols(nb_cols), m_data(data) {} 31 | 32 | // Implicit conversion from Matrix to MatrixView if T = const U 33 | template ::value>> 34 | MatrixView(const Matrix &mat) : m_number_of_rows(mat.nb_rows()), m_number_of_cols(mat.nb_cols()), m_data(mat.data()) {} 35 | 36 | // Implicit conversion from Matrix to MatrixView if T = U 37 | template ::value>> 38 | MatrixView(Matrix &mat) : m_number_of_rows(mat.nb_rows()), m_number_of_cols(mat.nb_cols()), m_data(mat.data()) {} 39 | 40 | void assign(int number_of_rows, int number_of_cols, T *ptr) { 41 | m_number_of_rows = number_of_rows; 42 | m_number_of_cols = number_of_cols; 43 | m_data = ptr; 44 | } 45 | 46 | void operator=(const T &z) { 47 | if (m_number_of_rows * m_number_of_cols > 0) 48 | std::fill_n(m_data, m_number_of_rows * m_number_of_cols, z); 49 | } 50 | T &operator()(const int &j, const int &k) { 51 | return m_data[j + k * m_number_of_rows]; 52 | } 53 | const T &operator()(const int &j, const int &k) const { 54 | return m_data[j + k * m_number_of_rows]; 55 | } 56 | T *data() { 57 | return m_data; 58 | } 59 | const T *data() const { 60 | return m_data; 61 | } 62 | int nb_cols() const { return m_number_of_cols; } 63 | int nb_rows() const { return m_number_of_rows; } 64 | }; 65 | 66 | } // namespace htool 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/lrmat/test_matrix_lrmat_product.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | using namespace htool; 9 | 10 | template 11 | bool test_matrix_lrmat_product(char transa, char transb, T alpha, T beta, const LowRankMatrix &B_auto_approximation, const LowRankMatrix &C_auto_approximation, const Matrix &A_dense, const Matrix &C_dense, const Matrix &matrix_result_w_matrix_sum, const Matrix &matrix_result_wo_sum, const Matrix &matrix_result_w_lrmat_sum, htool::underlying_type epsilon, htool::underlying_type additional_compression_tolerance, htool::underlying_type additional_lrmat_sum_tolerance) { 12 | bool is_error = false; 13 | Matrix matrix_test, dense_lrmat_test; 14 | LowRankMatrix lrmat_test(A_dense.nb_rows(), B_auto_approximation.nb_cols(), epsilon); 15 | htool::underlying_type error; 16 | 17 | // Products with auto approximation 18 | matrix_test = C_dense; 19 | add_matrix_lrmat_product(transa, transb, alpha, A_dense, B_auto_approximation, beta, matrix_test); 20 | error = normFrob(matrix_result_w_matrix_sum - matrix_test) / normFrob(matrix_result_w_matrix_sum); 21 | is_error = is_error || !(error < epsilon); 22 | cout << "> Errors on a matrix lrmat product to matrix with automatic approximation: " << error << endl; 23 | 24 | lrmat_test = C_auto_approximation; 25 | add_matrix_lrmat_product(transa, transb, alpha, A_dense, B_auto_approximation, T(0), lrmat_test); 26 | dense_lrmat_test.resize(lrmat_test.get_U().nb_rows(), lrmat_test.get_V().nb_cols()); 27 | lrmat_test.copy_to_dense(dense_lrmat_test.data()); 28 | error = normFrob(matrix_result_wo_sum - dense_lrmat_test) / normFrob(matrix_result_wo_sum); 29 | is_error = is_error || !(error < epsilon); 30 | cout << "> Errors on a matrix lrmat product to lrmat with automatic approximation and without lrmat sum: " << error << endl; 31 | 32 | lrmat_test = C_auto_approximation; 33 | add_matrix_lrmat_product(transa, transb, alpha, A_dense, B_auto_approximation, beta, lrmat_test); 34 | dense_lrmat_test.resize(lrmat_test.get_U().nb_rows(), lrmat_test.get_V().nb_cols()); 35 | lrmat_test.copy_to_dense(dense_lrmat_test.data()); 36 | error = normFrob(matrix_result_w_lrmat_sum - dense_lrmat_test) / normFrob(matrix_result_w_lrmat_sum); 37 | is_error = is_error || !(error < epsilon * (1 + additional_compression_tolerance + additional_lrmat_sum_tolerance)); 38 | cout << "> Errors on a matrix lrmat product to lrmat with automatic approximation and with lrmat sum: " << error << endl; 39 | 40 | cout << "test : " << is_error << endl 41 | << endl; 42 | 43 | return is_error; 44 | } 45 | -------------------------------------------------------------------------------- /include/htool/misc/logger.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_LOGGER 2 | #define HTOOL_LOGGER 3 | #include // for operator<<, basic_ostream, cout, ostream 4 | #include // for shared_ptr, __shared_ptr_access, make_shared 5 | #include // for string, operator+, operator<<, char_traits 6 | 7 | namespace htool { 8 | 9 | // Meyer's singleton 10 | // https://stackoverflow.com/a/1008289 11 | 12 | enum class LogLevel : unsigned int { 13 | CRITICAL = 0, 14 | ERROR = 10, 15 | WARNING = 20, 16 | DEBUG = 30, 17 | INFO = 40, 18 | }; 19 | 20 | inline std::string logging_level_to_string(LogLevel logging_level) { 21 | switch (logging_level) { 22 | case LogLevel::CRITICAL: 23 | return "[Htool critical] "; 24 | break; 25 | case LogLevel::ERROR: 26 | return "[Htool error] "; 27 | break; 28 | case LogLevel::WARNING: 29 | return "[Htool warning] "; 30 | break; 31 | case LogLevel::DEBUG: 32 | return "[Htool debug] "; 33 | break; 34 | case LogLevel::INFO: 35 | return "[Htool info] "; 36 | break; 37 | default: 38 | break; 39 | } 40 | return ""; 41 | } 42 | 43 | class IObjectWriter { 44 | public: 45 | virtual void set_log_level(LogLevel) = 0; 46 | virtual void write(LogLevel, const std::string &) = 0; 47 | virtual ~IObjectWriter() {} 48 | }; 49 | 50 | class StandartOutputWriter : public IObjectWriter { 51 | LogLevel m_current_log_level = LogLevel::ERROR; 52 | 53 | public: 54 | void write(LogLevel log_level, const std::string &message) override { 55 | std::string prefix; 56 | if (log_level <= m_current_log_level) { 57 | std::cout << logging_level_to_string(log_level) + message << "\n"; 58 | } 59 | } 60 | void set_log_level(LogLevel log_level) override { m_current_log_level = log_level; } 61 | }; 62 | 63 | class Logger { 64 | public: 65 | void set_current_log_level(unsigned int log_level) { m_writer->set_log_level(static_cast(log_level)); } 66 | void set_current_log_level(LogLevel log_level) { m_writer->set_log_level(log_level); } 67 | static Logger &get_instance() { 68 | static Logger instance; 69 | return instance; 70 | } 71 | 72 | void set_current_writer(std::shared_ptr writer) { m_writer = writer; } 73 | 74 | void log(LogLevel log_level, std::string message) { 75 | m_writer->write(log_level, message); 76 | } 77 | 78 | protected: 79 | Logger() = default; 80 | Logger(Logger const &) = delete; 81 | Logger &operator=(Logger &&) = delete; 82 | Logger &operator=(const Logger &) = delete; 83 | virtual ~Logger() {} 84 | 85 | private: 86 | std::shared_ptr m_writer = std::make_shared(); 87 | }; 88 | 89 | } // namespace htool 90 | #endif 91 | -------------------------------------------------------------------------------- /tests/functional_tests/misc/test_logger.cpp: -------------------------------------------------------------------------------- 1 | #include // for array 2 | #include // for LogLevel, Logger, logging_level_to_... 3 | #include // for initializer_list 4 | #include // for basic_ostream, cout 5 | #include // for allocator, shared_ptr, __shared_ptr... 6 | #include // for basic_string, operator+, char_traits 7 | 8 | class TestWriter : public htool::IObjectWriter { 9 | public: 10 | std::string m_string = ""; 11 | htool::LogLevel m_current_log_level; 12 | void write(htool::LogLevel log_level, const std::string &message) override { 13 | if (log_level <= m_current_log_level) { 14 | m_string.append(logging_level_to_string(log_level) + message); 15 | } 16 | } 17 | void set_log_level(htool::LogLevel log_level) override { m_current_log_level = log_level; } 18 | htool::LogLevel get_log_level() { return m_current_log_level; } 19 | }; 20 | 21 | int main() { 22 | std::array log_levels{ 23 | htool::LogLevel::CRITICAL, 24 | htool::LogLevel::ERROR, 25 | htool::LogLevel::WARNING, 26 | htool::LogLevel::DEBUG, 27 | htool::LogLevel::INFO}; 28 | 29 | auto test_writer = std::make_shared(); 30 | for (auto log_level : log_levels) { 31 | for (auto verbosity : {0, 5, 10, 15, 20, 25, 30, 40}) { 32 | auto &logger = htool::Logger::get_instance(); 33 | logger.set_current_log_level(verbosity); 34 | logger.set_current_writer(test_writer); 35 | unsigned int current_log_level = static_cast(test_writer->get_log_level()); 36 | logger.log(log_level, "current log level: " + std::to_string(current_log_level) + "\n"); 37 | } 38 | } 39 | 40 | std::string ref_string = R"([Htool critical] current log level: 0 41 | [Htool critical] current log level: 5 42 | [Htool critical] current log level: 10 43 | [Htool critical] current log level: 15 44 | [Htool critical] current log level: 20 45 | [Htool critical] current log level: 25 46 | [Htool critical] current log level: 30 47 | [Htool critical] current log level: 40 48 | [Htool error] current log level: 10 49 | [Htool error] current log level: 15 50 | [Htool error] current log level: 20 51 | [Htool error] current log level: 25 52 | [Htool error] current log level: 30 53 | [Htool error] current log level: 40 54 | [Htool warning] current log level: 20 55 | [Htool warning] current log level: 25 56 | [Htool warning] current log level: 30 57 | [Htool warning] current log level: 40 58 | [Htool debug] current log level: 30 59 | [Htool debug] current log level: 40 60 | [Htool info] current log level: 40 61 | )"; 62 | if (!(ref_string == test_writer->m_string)) { 63 | std::cout << test_writer->m_string; 64 | } 65 | return !(ref_string == test_writer->m_string); 66 | } 67 | -------------------------------------------------------------------------------- /include/htool/hmatrix/interfaces/virtual_lrmat_generator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTOOL_HMATRIX_VIRTUAL_LRMAT_GENERATOR_HPP 2 | #define HTOOL_HMATRIX_VIRTUAL_LRMAT_GENERATOR_HPP 3 | 4 | #include "../../clustering/cluster_node.hpp" // for Cluster 5 | #include "../../hmatrix/lrmat/lrmat.hpp" // for LowRankMatrix 6 | #include "../../matrix/matrix.hpp" // for Matrix 7 | #include "../../misc/misc.hpp" // for underlying_type 8 | 9 | namespace htool { 10 | 11 | template 12 | class VirtualInternalLowRankGenerator { 13 | public: 14 | VirtualInternalLowRankGenerator() {} 15 | 16 | // C style 17 | virtual bool copy_low_rank_approximation(int M, int N, int row_offset, int col_offset, LowRankMatrix &lrmat) const = 0; 18 | 19 | virtual bool copy_low_rank_approximation(int M, int N, int row_offset, int col_offset, int reqrank, LowRankMatrix &lrmat) const = 0; 20 | 21 | virtual ~VirtualInternalLowRankGenerator() {} 22 | }; 23 | 24 | template > 25 | class VirtualLowRankGenerator { 26 | public: 27 | VirtualLowRankGenerator() {} 28 | 29 | // C style 30 | virtual bool copy_low_rank_approximation(int M, int N, const int *rows, const int *cols, LowRankMatrix &lrmat) const = 0; 31 | 32 | virtual bool copy_low_rank_approximation(int M, int N, const int *rows, const int *cols, int reqrank, LowRankMatrix &lrmat) const = 0; 33 | 34 | virtual ~VirtualLowRankGenerator() {} 35 | }; 36 | 37 | template 38 | class InternalLowRankGenerator : public VirtualInternalLowRankGenerator { 39 | 40 | protected: 41 | const VirtualLowRankGenerator &m_low_rank_generator; 42 | const int *m_target_permutation; 43 | const int *m_source_permutation; 44 | 45 | public: 46 | InternalLowRankGenerator(const VirtualLowRankGenerator &low_rank_generator, const int *target_permutation, const int *source_permutation) : m_low_rank_generator(low_rank_generator), m_target_permutation(target_permutation), m_source_permutation(source_permutation) { 47 | } 48 | 49 | virtual bool copy_low_rank_approximation(int M, int N, int row_offset, int col_offset, LowRankMatrix &lrmat) const override { 50 | return m_low_rank_generator.copy_low_rank_approximation(M, N, m_target_permutation + row_offset, m_source_permutation + col_offset, lrmat); 51 | } 52 | 53 | virtual bool copy_low_rank_approximation(int M, int N, int row_offset, int col_offset, int reqrank, LowRankMatrix &lrmat) const override { 54 | return m_low_rank_generator.copy_low_rank_approximation(M, N, m_target_permutation + row_offset, m_source_permutation + col_offset, reqrank, lrmat); 55 | } 56 | }; 57 | 58 | } // namespace htool 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/lrmat/test_lrmat_lrmat_product.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | using namespace htool; 9 | 10 | template 11 | bool test_lrmat_lrmat_product(char transa, char transb, T alpha, T beta, const LowRankMatrix &A_auto_approximation, const LowRankMatrix &B_auto_approximation, const LowRankMatrix &C_auto_approximation, const Matrix &C_dense, const Matrix &matrix_result_w_matrix_sum, const Matrix &matrix_result_wo_sum, const Matrix &matrix_result_w_lrmat_sum, htool::underlying_type epsilon, htool::underlying_type additional_compression_tolerance, htool::underlying_type additional_lrmat_sum_tolerance) { 12 | 13 | bool is_error = false; 14 | Matrix matrix_test, dense_lrmat_test; 15 | LowRankMatrix lrmat_test(A_auto_approximation.nb_rows(), B_auto_approximation.nb_cols(), epsilon); 16 | htool::underlying_type error; 17 | 18 | // Product with automatic rank 19 | matrix_test = C_dense; 20 | add_lrmat_lrmat_product(transa, transb, alpha, A_auto_approximation, B_auto_approximation, beta, matrix_test); 21 | error = normFrob(matrix_result_w_matrix_sum - matrix_test) / normFrob(matrix_result_w_matrix_sum); 22 | is_error = is_error || !(error < A_auto_approximation.get_epsilon() * (1 + additional_compression_tolerance)); 23 | cout << "> Errors on a lrmat lrmat product to matrix with auto approximation: " << error << endl; 24 | 25 | lrmat_test = C_auto_approximation; 26 | add_lrmat_lrmat_product(transa, transb, alpha, A_auto_approximation, B_auto_approximation, T(0), lrmat_test); 27 | dense_lrmat_test.resize(lrmat_test.get_U().nb_rows(), lrmat_test.get_V().nb_cols()); 28 | lrmat_test.copy_to_dense(dense_lrmat_test.data()); 29 | error = normFrob(matrix_result_wo_sum - dense_lrmat_test) / normFrob(matrix_result_wo_sum); 30 | is_error = is_error || !(error < A_auto_approximation.get_epsilon() * (1 + additional_compression_tolerance)); 31 | cout << "> Errors on a lrmat lrmat product to lrmat with auto approximation and without lrmat sum: " << error << endl; 32 | 33 | lrmat_test = C_auto_approximation; 34 | add_lrmat_lrmat_product(transa, transb, alpha, A_auto_approximation, B_auto_approximation, beta, lrmat_test); 35 | dense_lrmat_test.resize(lrmat_test.get_U().nb_rows(), lrmat_test.get_V().nb_cols()); 36 | lrmat_test.copy_to_dense(dense_lrmat_test.data()); 37 | error = normFrob(matrix_result_w_lrmat_sum - dense_lrmat_test) / normFrob(matrix_result_w_lrmat_sum); 38 | is_error = is_error || !(error < A_auto_approximation.get_epsilon() * (1 + additional_compression_tolerance + additional_lrmat_sum_tolerance)); 39 | cout << "> Errors on a lrmat lrmat product to lrmat with auto approximation and with lrmat sum: " << error << endl; 40 | 41 | cout << "test : " << is_error << endl 42 | << endl; 43 | 44 | return is_error; 45 | } 46 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/test_lrmat_hmatrix_addition.hpp: -------------------------------------------------------------------------------- 1 | #include // for basic_o... 2 | #include // for HMatrix 3 | #include // for add_lrm... 4 | #include // for LowRank... 5 | #include // for HMatrix... 6 | #include // for add_mat... 7 | #include // for Matrix 8 | #include // for underly... 9 | #include // for TestCas... 10 | #include // for cout 11 | 12 | using namespace std; 13 | using namespace htool; 14 | 15 | template 16 | bool test_lrmat_hmatrix_addition(int n1, int n2, htool::underlying_type epsilon, htool::underlying_type) { 17 | 18 | bool is_error = false; 19 | htool::underlying_type error; 20 | htool::underlying_type eta = 10; 21 | TestCaseProduct test_case('N', 'N', n1, n2, n2, 1, 4); 22 | 23 | // HMatrix 24 | HMatrixTreeBuilder> hmatrix_tree_builder_A(epsilon, eta, 'N', 'N'); 25 | HMatrix> A = hmatrix_tree_builder_A.build(*test_case.operator_A, *test_case.root_cluster_A_output, *test_case.root_cluster_A_input); 26 | HMatrix> hmatrix_test(A); 27 | 28 | // lrmat 29 | Compressor compressor(*test_case.operator_C); 30 | LowRankMatrix C_approximation(test_case.root_cluster_C_output->get_size(), test_case.root_cluster_C_input->get_size(), epsilon); 31 | compressor.copy_low_rank_approximation(test_case.root_cluster_C_output->get_size(), test_case.root_cluster_C_input->get_size(), test_case.root_cluster_C_output->get_offset(), test_case.root_cluster_C_input->get_offset(), C_approximation); 32 | 33 | // Reference 34 | Matrix A_dense(A.nb_rows(), A.nb_cols(), 0); 35 | copy_to_dense(A, A_dense.data()); 36 | Matrix C_dense(C_approximation.nb_rows(), C_approximation.nb_cols(), 0); 37 | 38 | Matrix result(A_dense), matrix_test, densified_hmatrix_test(n1, n2); 39 | add_matrix_matrix_product('N', 'N', T(1), C_approximation.get_U(), C_approximation.get_V(), T(1), result); 40 | 41 | // 42 | hmatrix_test = A; 43 | internal_add_lrmat_hmatrix(C_approximation, hmatrix_test); 44 | copy_to_dense(hmatrix_test, densified_hmatrix_test.data()); 45 | error = normFrob(result - densified_hmatrix_test) / normFrob(result); 46 | is_error = is_error || !(error < epsilon); 47 | cout << "> Errors on a lrmat hmatrix addition: " << error << endl; 48 | 49 | std::ofstream densified_hmatrix_test_file("densified_hmatrix_test"); 50 | print(densified_hmatrix_test, densified_hmatrix_test_file, ","); 51 | 52 | std::ofstream result_file("result"); 53 | print(result, result_file, ","); 54 | return is_error; 55 | } 56 | -------------------------------------------------------------------------------- /include/htool/distributed_operator/implementations/global_to_local_operators/dense_matrix.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef HTOOL_DISTRIBUTED_OPERATOR_LOCAL_DENSE_MATRIX_HPP 3 | #define HTOOL_DISTRIBUTED_OPERATOR_LOCAL_DENSE_MATRIX_HPP 4 | 5 | #include "../../../matrix/matrix.hpp" // for Matrix 6 | #include "restricted_operator.hpp" // for LocalOperator 7 | 8 | namespace htool { 9 | 10 | template 11 | class RestrictedGlobalToLocalDenseMatrix final : public RestrictedGlobalToLocalOperator { 12 | const Matrix &m_data; 13 | char m_symmetry = 'N'; 14 | char m_UPLO = 'N'; 15 | 16 | public: 17 | RestrictedGlobalToLocalDenseMatrix(const Matrix &matrix, const LocalRenumbering &target_local_renumbering, const LocalRenumbering &source_local_renumbering, char symmetry = 'N', char UPLO = 'N', bool target_use_permutation_to_mvprod = false, bool source_use_permutation_to_mvprod = false) : RestrictedGlobalToLocalOperator(target_local_renumbering, source_local_renumbering, target_use_permutation_to_mvprod, source_use_permutation_to_mvprod), m_data(matrix), m_symmetry(symmetry), m_UPLO(UPLO) {} 18 | 19 | RestrictedGlobalToLocalDenseMatrix(const RestrictedGlobalToLocalDenseMatrix &) = default; 20 | RestrictedGlobalToLocalDenseMatrix &operator=(const RestrictedGlobalToLocalDenseMatrix &) = default; 21 | RestrictedGlobalToLocalDenseMatrix(RestrictedGlobalToLocalDenseMatrix &&RestrictedGlobalToLocalDenseMatrix) noexcept = default; 22 | RestrictedGlobalToLocalDenseMatrix &operator=(RestrictedGlobalToLocalDenseMatrix &&RestrictedGlobalToLocalDenseMatrix) noexcept = default; 23 | ~RestrictedGlobalToLocalDenseMatrix() = default; 24 | 25 | void local_add_vector_product(char trans, CoefficientPrecision alpha, const CoefficientPrecision *in, CoefficientPrecision beta, CoefficientPrecision *out) const override { 26 | if (m_symmetry == 'N') { 27 | add_matrix_vector_product(trans, alpha, m_data, in, beta, out); 28 | } else if (m_symmetry == 'S') { 29 | add_symmetric_matrix_vector_product(m_UPLO, alpha, m_data, in, beta, out); 30 | } else if (m_symmetry == 'H') { 31 | add_hermitian_matrix_vector_product(m_UPLO, alpha, m_data, in, beta, out); 32 | } 33 | } 34 | 35 | void local_add_matrix_product_row_major(char trans, CoefficientPrecision alpha, const CoefficientPrecision *in, CoefficientPrecision beta, CoefficientPrecision *out, int mu) const override { 36 | if (m_symmetry == 'N') { 37 | add_matrix_matrix_product_row_major(trans, 'N', alpha, m_data, in, beta, out, mu); 38 | } else if (m_symmetry == 'S') { 39 | add_symmetric_matrix_matrix_product_row_major('L', m_UPLO, alpha, m_data, in, beta, out, mu); 40 | } else if (m_symmetry == 'H') { 41 | add_hermitian_matrix_matrix_product_row_major('L', m_UPLO, alpha, m_data, in, beta, out, mu); 42 | } 43 | } 44 | }; 45 | } // namespace htool 46 | #endif 47 | -------------------------------------------------------------------------------- /tests/functional_tests/matrix/test_matrix_factorization.hpp: -------------------------------------------------------------------------------- 1 | #include // for max_ele... 2 | #include // for cholesk... 3 | #include // for Matrix 4 | #include // for normFrob 5 | #include // for underly... 6 | #include // for generat... 7 | #include // for basic_o... 8 | 9 | using namespace std; 10 | using namespace htool; 11 | 12 | template 13 | bool test_matrix_lu(char trans, int n, int nrhs) { 14 | 15 | bool is_error = false; 16 | 17 | // Generate random matrix 18 | htool::underlying_type error; 19 | Matrix result(n, nrhs), B(n, nrhs); 20 | generate_random_array(result.data(), result.nb_rows() * result.nb_cols()); 21 | 22 | Matrix A(n, n), test_factorization, test_solve; 23 | generate_random_array(A.data(), A.nb_rows() * A.nb_cols()); 24 | for (int i = 0; i < n; i++) { 25 | T sum = 0; 26 | for (int j = 0; j < n; j++) { 27 | sum += std::abs(A(i, j)); 28 | } 29 | A(i, i) = sum; 30 | } 31 | 32 | add_matrix_matrix_product(trans, 'N', T(1), A, result, T(1), B); 33 | 34 | // LU factorization 35 | test_factorization = A; 36 | test_solve = B; 37 | lu_factorization(test_factorization); 38 | lu_solve(trans, test_factorization, test_solve); 39 | error = normFrob(result - test_solve) / normFrob(result); 40 | is_error = is_error || !(error < 1e-9); 41 | cout << "> Errors on matrix lu solve: " << error << endl; 42 | 43 | return is_error; 44 | } 45 | 46 | template 47 | bool test_matrix_cholesky(char trans, int n, int nrhs, char symmetry, char UPLO) { 48 | 49 | bool is_error = false; 50 | 51 | // Generate random matrix 52 | htool::underlying_type error; 53 | Matrix result(n, nrhs), B(n, nrhs); 54 | generate_random_array(result.data(), result.nb_rows() * result.nb_cols()); 55 | 56 | Matrix A(n, n), test_factorization, test_solve; 57 | Matrix random_matrix(n, n); 58 | generate_random_array(random_matrix.data(), random_matrix.nb_rows() * random_matrix.nb_cols()); 59 | char op = symmetry == 'S' ? 'T' : 'C'; 60 | add_matrix_matrix_product(op, 'N', T(1), random_matrix, random_matrix, T(1), A); 61 | T eps = *std::max_element(random_matrix.data(), random_matrix.data() + random_matrix.nb_cols() * random_matrix.nb_rows(), [](const T &lhs, const T &rhs) { return std::abs(lhs) < std::abs(rhs); }); 62 | for (int i = 0; i < n; i++) { 63 | A(i, i) += std::abs(eps); 64 | } 65 | 66 | add_matrix_matrix_product(trans, 'N', T(1), A, result, T(1), B); 67 | 68 | // LU factorization 69 | test_factorization = A; 70 | test_solve = B; 71 | cholesky_factorization(UPLO, test_factorization); 72 | cholesky_solve(UPLO, test_factorization, test_solve); 73 | error = normFrob(result - test_solve) / normFrob(result); 74 | is_error = is_error || !(error < 1e-9); 75 | cout << "> Errors on matrix cholesky solve: " << error << endl; 76 | 77 | return is_error; 78 | } 79 | -------------------------------------------------------------------------------- /tests/functional_tests/solvers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | #=========================== Executables =====================================# 3 | #=============================================================================# 4 | 5 | include(FetchContent) 6 | FetchContent_Declare( 7 | data_test_repository 8 | GIT_REPOSITORY "https://github.com/PierreMarchand20/htool_generate_data_test" 9 | GIT_TAG origin/main 10 | GIT_SHALLOW TRUE 11 | GIT_SUBMODULES_RECURSE FALSE 12 | GIT_SUBMODULES "" SOURCE_SUBDIR AVOID_calling_ADD_SUBDIR_in_subseqeuent_MAKEAVILABLE) 13 | # weird hack, see https://gitlab.kitware.com/cmake/cmake/-/issues/26220 and 14 | 15 | FetchContent_MakeAvailable(data_test_repository) 16 | 17 | set(Test_solver_ARGS ${data_test_repository_SOURCE_DIR}/data/) 18 | 19 | add_executable(Test_solver_double test_solver_double.cpp) 20 | target_link_libraries(Test_solver_double htool) 21 | add_dependencies(build-tests-solvers Test_solver_double) 22 | 23 | add_executable(Test_solver_complex_double test_solver_complex_double.cpp) 24 | target_link_libraries(Test_solver_complex_double htool) 25 | add_dependencies(build-tests-solvers Test_solver_complex_double) 26 | 27 | add_test(NAME Test_solver_double_1 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 1 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_solver_double ${Test_solver_ARGS}) 28 | set_tests_properties(Test_solver_double_1 PROPERTIES LABELS "mpi") 29 | add_test(NAME Test_solver_double_2 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_solver_double ${Test_solver_ARGS}) 30 | set_tests_properties(Test_solver_double_2 PROPERTIES LABELS "mpi") 31 | add_test(NAME Test_solver_double_3 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 3 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_solver_double ${Test_solver_ARGS}) 32 | set_tests_properties(Test_solver_double_3 PROPERTIES LABELS "mpi") 33 | add_test(NAME Test_solver_double_4 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_solver_double ${Test_solver_ARGS}) 34 | set_tests_properties(Test_solver_double_4 PROPERTIES LABELS "mpi") 35 | 36 | add_test(NAME Test_solver_complex_double_1 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 1 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_solver_complex_double ${Test_solver_ARGS}) 37 | set_tests_properties(Test_solver_complex_double_1 PROPERTIES LABELS "mpi") 38 | add_test(NAME Test_solver_complex_double_2 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_solver_complex_double ${Test_solver_ARGS}) 39 | set_tests_properties(Test_solver_complex_double_2 PROPERTIES LABELS "mpi") 40 | add_test(NAME Test_solver_complex_double_3 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 3 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_solver_complex_double ${Test_solver_ARGS}) 41 | set_tests_properties(Test_solver_complex_double_3 PROPERTIES LABELS "mpi") 42 | add_test(NAME Test_solver_complex_double_4 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/Test_solver_complex_double ${Test_solver_ARGS}) 43 | set_tests_properties(Test_solver_complex_double_4 PROPERTIES LABELS "mpi") 44 | -------------------------------------------------------------------------------- /tests/functional_tests/solvers/test_solver_complex_double.cpp: -------------------------------------------------------------------------------- 1 | #include "test_solver_ddm.hpp" // for test_so... 2 | #include "test_solver_ddm_adding_overlap.hpp" // for test_so... 3 | #include "test_solver_wo_overlap.hpp" // for test_so... 4 | #include // for max, copy 5 | #include // for complex 6 | #include // for DDMSolv... 7 | #include // for initial... 8 | #include // for basic_o... 9 | #include // for MPI_Fin... 10 | #include // for operator<< 11 | #include // for vector 12 | 13 | int main(int argc, char *argv[]) { 14 | // Initialize the MPI environment 15 | MPI_Init(&argc, &argv); 16 | 17 | // Input file 18 | if (argc < 2) { // argc should be 5 or more for correct execution 19 | // We print argv[0] assuming it is the program name 20 | cout << "usage: " << argv[0] << " datapath\n"; // LCOV_EXCL_LINE 21 | return 1; // LCOV_EXCL_LINE 22 | } 23 | string datapath = argv[1]; 24 | 25 | bool is_error = false; 26 | std::string datapath_final = datapath + "/output_non_sym/"; 27 | 28 | for (auto nb_rhs : {1, 5}) { 29 | for (auto data_symmetry : {'N'}) { 30 | std::vector symmetries = {'N'}; 31 | for (auto symmetry : symmetries) { 32 | std::cout << nb_rhs << " " << data_symmetry << " " << symmetry << "\n"; 33 | 34 | is_error = is_error || test_solver_wo_overlap, double, DDMSolverWithDenseLocalSolver, double>>(argc, argv, nb_rhs, symmetry, symmetry == 'N' ? 'N' : 'L', datapath_final); 35 | is_error = is_error || test_solver_ddm_adding_overlap, double, DDMSolverWithDenseLocalSolver>, DefaultApproximationBuilder, double>>(argc, argv, nb_rhs, data_symmetry, symmetry, symmetry == 'N' ? 'N' : 'L', datapath_final); 36 | is_error = is_error || test_solver_ddm, double, DDMSolverWithDenseLocalSolver>>(argc, argv, nb_rhs, data_symmetry, symmetry, symmetry == 'N' ? 'N' : 'L', datapath_final); 37 | 38 | is_error = is_error || test_solver_wo_overlap, double, DDMSolverBuilder, double>>(argc, argv, nb_rhs, symmetry, 'N', datapath_final); 39 | is_error = is_error || test_solver_ddm_adding_overlap, double, DDMSolverBuilder, double>, DefaultLocalApproximationBuilder, double>>(argc, argv, nb_rhs, data_symmetry, symmetry, 'N', datapath_final); 40 | is_error = is_error || test_solver_ddm, double, DDMSolverBuilder>>(argc, argv, nb_rhs, data_symmetry, symmetry, 'N', datapath_final); 41 | } 42 | } 43 | } 44 | 45 | // Finalize the MPI environment. 46 | MPI_Finalize(); 47 | if (is_error) { 48 | return 1; 49 | } 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /tests/functional_tests/distributed_operator/test_distributed_operator_product_double.cpp: -------------------------------------------------------------------------------- 1 | #include "test_distributed_operator.hpp" // for test_distributed_operator 2 | #include // for GeneratorTestComplex 3 | #include // for initializer_list 4 | #include // for basic_ostream, char_traits 5 | #include // for MPI_Finalize, MPI_Init 6 | 7 | using namespace std; 8 | using namespace htool; 9 | 10 | int main(int argc, char *argv[]) { 11 | MPI_Init(&argc, &argv); 12 | 13 | bool is_error = false; 14 | const int number_of_rows = 200; 15 | const int number_of_rows_increased = 400; 16 | const int number_of_columns = 200; 17 | const int number_of_columns_increased = 400; 18 | 19 | for (auto number_of_right_hand_side : {1, 5}) { 20 | for (auto offdiagonal_approximation : {true, false}) { 21 | for (auto use_buffer : {true, false}) { 22 | for (auto operation : {'N', 'T'}) { 23 | for (auto data_type : {DataType::Matrix, DataType::HMatrix}) { 24 | std::vector tolerances{1e-14}; 25 | if (data_type == DataType::HMatrix) { 26 | tolerances.push_back(1e-3); 27 | } 28 | for (auto epsilon : tolerances) { 29 | std::cout << use_buffer << " " << epsilon << " " << number_of_right_hand_side << " " << operation << " " << epsilon << " " << offdiagonal_approximation << "\n"; 30 | 31 | // Square matrix 32 | is_error = is_error || test_distributed_operator(number_of_rows, number_of_columns, number_of_right_hand_side, use_buffer, 'N', 'N', operation, offdiagonal_approximation, data_type, epsilon); 33 | is_error = is_error || test_distributed_operator(number_of_rows, number_of_columns, number_of_right_hand_side, use_buffer, 'S', 'L', operation, offdiagonal_approximation, data_type, epsilon); 34 | is_error = is_error || test_distributed_operator(number_of_rows, number_of_columns, number_of_right_hand_side, use_buffer, 'S', 'U', operation, offdiagonal_approximation, data_type, epsilon); 35 | 36 | // // Rectangular matrix 37 | is_error = is_error || test_distributed_operator(number_of_rows_increased, number_of_columns, number_of_right_hand_side, use_buffer, 'N', 'N', operation, offdiagonal_approximation, data_type, epsilon); 38 | is_error = is_error || test_distributed_operator(number_of_rows, number_of_columns_increased, number_of_right_hand_side, use_buffer, 'N', 'N', operation, offdiagonal_approximation, data_type, epsilon); 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | MPI_Finalize(); 46 | 47 | if (is_error) { 48 | return 1; 49 | } 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /tests/functional_tests/hmatrix/lrmat/lrmat_build/test_lrmat_build_partialACA.cpp: -------------------------------------------------------------------------------- 1 | #include "../test_lrmat_build.hpp" // for test_lrmat 2 | #include // for max, copy 3 | #include // for pow, sqrt 4 | #include // for Cluster 5 | #include // for Cluster... 6 | #include // for Generat... 7 | #include // for LowRank... 8 | #include // for partialACA 9 | #include // for Generat... 10 | #include // for create_... 11 | #include // for basic_o... 12 | #include // for pair 13 | #include // for vector 14 | 15 | using namespace std; 16 | using namespace htool; 17 | 18 | int main(int, char *[]) { 19 | 20 | const int ndistance = 4; 21 | double distance[ndistance]; 22 | distance[0] = 15; 23 | distance[1] = 20; 24 | distance[2] = 30; 25 | distance[3] = 40; 26 | 27 | double epsilon = 0.0001; 28 | 29 | int nr = 500; 30 | int nc = 100; 31 | std::vector xt(3 * nr); 32 | std::vector xs(3 * nc); 33 | std::vector tabt(500); 34 | std::vector tabs(100); 35 | bool test = 0; 36 | for (int idist = 0; idist < ndistance; idist++) { 37 | 38 | create_disk(3, 0., nr, xt.data()); 39 | create_disk(3, distance[idist], nc, xs.data()); 40 | 41 | ClusterTreeBuilder recursive_build_strategy; 42 | 43 | Cluster t = recursive_build_strategy.create_cluster_tree(nr, 3, xt.data(), 2, 2); 44 | Cluster s = recursive_build_strategy.create_cluster_tree(nc, 3, xt.data(), 2, 2); 45 | 46 | GeneratorTestDouble A_in_user_numbering(3, xt, xs); 47 | InternalGeneratorWithPermutation A(A_in_user_numbering, t.get_permutation().data(), s.get_permutation().data()); 48 | 49 | // partialACA fixed rank 50 | int reqrank_max = 10; 51 | partialACA compressor(A_in_user_numbering, t.get_permutation().data(), s.get_permutation().data()); 52 | 53 | LowRankMatrix A_partialACA_fixed(t.get_size(), s.get_size(), reqrank_max, epsilon); 54 | compressor.copy_low_rank_approximation(t.get_size(), s.get_size(), t.get_offset(), s.get_offset(), reqrank_max, A_partialACA_fixed); 55 | 56 | // ACA automatic building 57 | LowRankMatrix A_partialACA(t.get_size(), s.get_size(), epsilon); 58 | compressor.copy_low_rank_approximation(t.get_size(), s.get_size(), t.get_offset(), s.get_offset(), A_partialACA); 59 | 60 | std::pair fixed_compression_interval(0.87, 0.89); 61 | std::pair auto_compression_interval(0.93, 0.96); 62 | test = test || (test_lrmat(t, s, A, A_partialACA_fixed, A_partialACA, fixed_compression_interval, auto_compression_interval)); 63 | } 64 | 65 | cout << "test : " << test << endl; 66 | 67 | return test; 68 | } 69 | --------------------------------------------------------------------------------