diff --git a/cmake_modules/FindMPI4PY.cmake b/cmake_modules/FindMPI4PY.cmake index 6ac4af6..0a88cbc 100644 --- a/cmake_modules/FindMPI4PY.cmake +++ b/cmake_modules/FindMPI4PY.cmake @@ -6,35 +6,32 @@ # https://compacc.fnal.gov/projects/repositories/entry/synergia2/CMake/FindMPI4PY.cmake?rev=c147eafb60728606af4fe7b1b161a660df142e9a -if(NOT MPI4PY_INCLUDE_DIR) - if (NOT PYTHON_EXECUTABLE) - set(PYTHON_EXECUTABLE "python3") - endif(NOT PYTHON_EXECUTABLE) - execute_process( - COMMAND "${PYTHON_EXECUTABLE}" "-c" "import mpi4py; print(mpi4py.get_include())" - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - OUTPUT_VARIABLE MPI4PY_INCLUDE_DIR - RESULT_VARIABLE MPI4PY_COMMAND_RESULT - OUTPUT_STRIP_TRAILING_WHITESPACE) - if(MPI4PY_COMMAND_RESULT) - message("jfa: mpi4py not found") +if(NOT PYTHON_EXECUTABLE) + set(PYTHON_EXECUTABLE "python3") +endif(NOT PYTHON_EXECUTABLE) +execute_process(COMMAND "which" "${PYTHON_EXECUTABLE}") +execute_process( + COMMAND "${PYTHON_EXECUTABLE}" "-c" "import mpi4py; print(mpi4py.get_include())" + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE MPI4PY_INCLUDE_DIR + RESULT_VARIABLE MPI4PY_COMMAND_RESULT + OUTPUT_STRIP_TRAILING_WHITESPACE) +if(MPI4PY_COMMAND_RESULT) + message("jfa: mpi4py not found") + set(MPI4PY_FOUND FALSE) +else(MPI4PY_COMMAND_RESULT) + if(MPI4PY_INCLUDE_DIR MATCHES "Traceback") + message("jfa: mpi4py matches traceback") + ## Did not successfully include MPI4PY set(MPI4PY_FOUND FALSE) - else(MPI4PY_COMMAND_RESULT) - if(MPI4PY_INCLUDE_DIR MATCHES "Traceback") - message("jfa: mpi4py matches traceback") - ## Did not successfully include MPI4PY - set(MPI4PY_FOUND FALSE) - else(MPI4PY_INCLUDE_DIR MATCHES "Traceback") - ## successful - set(MPI4PY_FOUND TRUE) - set(MPI4PY_INCLUDE_DIR - ${MPI4PY_INCLUDE_DIR} - CACHE STRING "mpi4py include path") - endif(MPI4PY_INCLUDE_DIR MATCHES "Traceback") - endif(MPI4PY_COMMAND_RESULT) -else(NOT MPI4PY_INCLUDE_DIR) - set(MPI4PY_FOUND TRUE) -endif(NOT MPI4PY_INCLUDE_DIR) + else(MPI4PY_INCLUDE_DIR MATCHES "Traceback") + ## successful + set(MPI4PY_FOUND TRUE) + set(MPI4PY_INCLUDE_DIR + ${MPI4PY_INCLUDE_DIR} + CACHE STRING "mpi4py include path") + endif(MPI4PY_INCLUDE_DIR MATCHES "Traceback") +endif(MPI4PY_COMMAND_RESULT) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(MPI4PY DEFAULT_MSG MPI4PY_INCLUDE_DIR) diff --git a/example/use_custom_dense_block_generator.py b/example/use_custom_dense_block_generator.py index 2988c7d..b7055df 100644 --- a/example/use_custom_dense_block_generator.py +++ b/example/use_custom_dense_block_generator.py @@ -34,17 +34,8 @@ ) # Build HMatrix -hmatrix_builder = Htool.HMatrixBuilder( - target_cluster, - target_cluster, - epsilon, - eta, - "N", - "N", - -1, - mpi4py.MPI.COMM_WORLD.rank, - mpi4py.MPI.COMM_WORLD.rank, -) +# low_rank_generator = CustomSVD(generator) +hmatrix_builder = Htool.HMatrixBuilder(epsilon, eta, "N", "N") hmatrix_builder.set_dense_blocks_generator(custom_dense_blocks_generator) diff --git a/example/use_custom_low_rank_approximation.py b/example/use_custom_low_rank_approximation.py index ac05a9c..1168828 100644 --- a/example/use_custom_low_rank_approximation.py +++ b/example/use_custom_low_rank_approximation.py @@ -39,18 +39,8 @@ low_rank_generator = CustomSVD(generator) # Build HMatrix -hmatrix_builder = Htool.HMatrixBuilder( - target_cluster, - source_cluster, - epsilon, - eta, - "N", - "N", - -1, - mpi4py.MPI.COMM_WORLD.rank, - mpi4py.MPI.COMM_WORLD.rank, -) -hmatrix_builder.set_low_rank_generator(low_rank_generator) +hmatrix_builder = Htool.HMatrixBuilder(epsilon, eta, "N", "N") +# or hmatrix_builder.set_low_rank_generator(low_rank_generator) # Build distributed operator distributed_operator_from_hmatrix = Htool.DistributedOperatorFromHMatrix( diff --git a/lib/htool b/lib/htool index 1a3b198..ca72016 160000 --- a/lib/htool +++ b/lib/htool @@ -1 +1 @@ -Subproject commit 1a3b198ffc6f73cd62059094ca7b606d151da976 +Subproject commit ca720167f4b7dc05924e3918338940c7c4bec18f diff --git a/src/Htool.cpython-311-darwin.so b/src/Htool.cpython-311-darwin.so deleted file mode 100755 index df5b427..0000000 Binary files a/src/Htool.cpython-311-darwin.so and /dev/null differ diff --git a/src/Htool.cpython-39-x86_64-linux-gnu.so b/src/Htool.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index 51ac184..0000000 Binary files a/src/Htool.cpython-39-x86_64-linux-gnu.so and /dev/null differ diff --git a/src/htool.egg-info/PKG-INFO b/src/htool.egg-info/PKG-INFO deleted file mode 100644 index 175f116..0000000 --- a/src/htool.egg-info/PKG-INFO +++ /dev/null @@ -1,89 +0,0 @@ -Metadata-Version: 2.1 -Name: htool -Version: 0.1 -Summary: CLI utility to automate asciinema -Author: Pierre Marchand -Author-email: Pierre Marchand -License: MIT License -Project-URL: Homepage, https://github.com/htool-ddm/htool_python -Project-URL: Bug Tracker, https://github.com/htool-ddm/htool_python/issues -Keywords: kernel approximation,hierarchical matrix,domain decomposition method -Classifier: Programming Language :: Python :: 3 -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: MacOS -Classifier: Operating System :: Unix -Requires-Python: >=3.7 -Description-Content-Type: text/markdown -Provides-Extra: dev -Provides-Extra: test -License-File: LICENSE - -# Python interface of Htool [![CI](https://github.com/htool-ddm/htool_python/actions/workflows/CI.yml/badge.svg)](https://github.com/htool-ddm/htool_python/actions/workflows/CI.yml) [![codecov](https://codecov.io/gh/htool-ddm/htool_python/branch/main/graph/badge.svg?token=P3FQNL8E64)](https://codecov.io/gh/htool-ddm/htool_python) - -## What is Htool? - -Htool is an implementation of hierarchical matrices (cf. this [reference](http://www.springer.com/gp/book/9783662473238) or this [one](http://www.springer.com/gp/book/9783540771463)), it was written to test Domain Decomposition Methods (DDM) applied to Boundary Element Method (BEM). It provides: - -* routines to build hierarchical matrix structures (cluster trees, block trees, low-rank matrices and block matrices), -* parallel matrix-vector and matrix-matrix product using MPI and OpenMP, -* preconditioning techniques using domain decomposition methods, -* the possibility to use Htool with any generator of coefficients (e.g., your own BEM library), -* an interface with [HPDDM](https://github.com/hpddm/hpddm) for iterative solvers, -* and several utility functions to display information about matrix structures and timing. - -It is now used in [FreeFEM](https://freefem.org) starting from version 4.5. - -## How to use Htool in Python? - -### Dependencies - -Htool is a header-only library written in C++11 with MPI and OpenMP, but it can be used without the latter if needed. Then, to use Htool, you need to have: - -* BLAS, to perform algebraic operations (dense matrix-matrix or matrix-vector operations). -* LAPACK, to perform SVD compression and to be used in DDM solvers with HPDDM. - -### Installing - -First, you need to clone this repository with its submodules: - -```bash -git clone https://github.com/htool-ddm/htool_python.git && cd htool_python -git submodule update --init -``` - -In the folder of this repository, do: - -```bash -pip install . -``` - -### Embedding Htool in your code - -We mostly refer to `smallest_example.py` in the `examples` folder to see how to use Htool. - -A function that generates the coefficients must be provided to Htool. To do so, a class inheriting from `IMatrix` or `ComplexIMatrix` must be defined with a method `get_coef(i, j)`, where `i` and `j` are integers. This method will return the coefficient (i,j) of the considered problem. A method `get_submatrix` can also be defined to provide a more efficient way to build a sub-block of the matrix. This new class and the geometry will be used to define an object `HMatrix`. - -### Difference with C++ - -**TL;DR** Due to Htool design and Python limitations, there is no shared parallelism for building hierarchical matrices. But shared parallelism is still used in the hierarchical matrix vector/matrix product. - -**Details** One feature of Htool is to take a function from the user to generate a hierarchical matrix. In the case of the Python interface, a Python function. Then, we loop over the blocks to build calling the user's function. In C++, we can use threads to accelerate this loop, but we cannot in Python because of the *Global Interpreter Lock*, which prevents several threads to call the user's function. One way to leverage this issue in terms of scaling is to use threading inside the function provided to Htool. - -## Who is behind Htool? - -If you need help or have questions regarding Htool, feel free to contact [Pierre Marchand](https://www.ljll.math.upmc.fr/marchandp/) and Pierre-Henri Tournier. - -## Acknowledgements - -[ANR NonlocalDD](https://www.ljll.math.upmc.fr/~claeys/nonlocaldd/index.html), (grant ANR-15-CE23-0017-01), France -[Inria](http://www.inria.fr/en/) Paris, France -[Laboratoire Jacques-Louis Lions](https://www.ljll.math.upmc.fr/en/) Paris, France - -## Collaborators/contributors - -[Matthieu Ancellin](https://ancell.in) -[Xavier Claeys](https://www.ljll.math.upmc.fr/~claeys/) -[Pierre Jolivet](http://jolivet.perso.enseeiht.fr/) -[Frédéric Nataf](https://www.ljll.math.upmc.fr/nataf/) - -![ANR NonlocalDD](figures/anr_nonlocaldd.png) diff --git a/src/htool.egg-info/SOURCES.txt b/src/htool.egg-info/SOURCES.txt deleted file mode 100644 index a973cfa..0000000 --- a/src/htool.egg-info/SOURCES.txt +++ /dev/null @@ -1,16 +0,0 @@ -LICENSE -README.md -pyproject.toml -setup.py -src/htool/__init__.py -src/htool.egg-info/PKG-INFO -src/htool.egg-info/SOURCES.txt -src/htool.egg-info/dependency_links.txt -src/htool.egg-info/not-zip-safe -src/htool.egg-info/requires.txt -src/htool.egg-info/top_level.txt -tests/test_cluster.py -tests/test_complex_hmatrix.py -tests/test_ddm_solver.py -tests/test_hmatrix.py -tests/test_imatrix.py \ No newline at end of file diff --git a/src/htool.egg-info/dependency_links.txt b/src/htool.egg-info/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/src/htool.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/htool.egg-info/not-zip-safe b/src/htool.egg-info/not-zip-safe deleted file mode 100644 index 8b13789..0000000 --- a/src/htool.egg-info/not-zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/htool.egg-info/requires.txt b/src/htool.egg-info/requires.txt deleted file mode 100644 index 8019df6..0000000 --- a/src/htool.egg-info/requires.txt +++ /dev/null @@ -1,11 +0,0 @@ -mpi4py -numpy - -[dev] -black -bumpver -isort -pytest - -[test] -pytest diff --git a/src/htool.egg-info/top_level.txt b/src/htool.egg-info/top_level.txt deleted file mode 100644 index 7b281df..0000000 --- a/src/htool.egg-info/top_level.txt +++ /dev/null @@ -1,2 +0,0 @@ -Htool -htool diff --git a/src/htool/hmatrix/hmatrix_builder.hpp b/src/htool/hmatrix/hmatrix_builder.hpp index 613c25c..b21f96c 100644 --- a/src/htool/hmatrix/hmatrix_builder.hpp +++ b/src/htool/hmatrix/hmatrix_builder.hpp @@ -11,17 +11,34 @@ void declare_hmatrix_builder(py::module &m, const std::string &className) { using Class = htool::HMatrixTreeBuilder; py::class_ py_class(m, className.c_str()); - // Constructor - py_class.def(py::init &, const htool::Cluster &, htool::underlying_type, CoordinatePrecision, char, char, int, int, int>()); + // // Constructor + // py_class.def(py::init([](underlying_type epsilon, CoordinatePrecision eta, char symmetry, char UPLO) { + // return std::unique_ptr(new Class(epsilon, eta, symmetry, UPLO)); + // }), + // py::arg("epsilon"), + // py::arg("eta"), + // py::arg("symmetry"), + // py::arg("UPLO")); + + py_class.def(py::init([](underlying_type epsilon, CoordinatePrecision eta, char symmetry, char UPLO, int reqrank, std::shared_ptr> low_rank_strategy) { + std::cout << epsilon << "\n"; + return std::unique_ptr(new Class(epsilon, eta, symmetry, UPLO, reqrank, low_rank_strategy)); + }), + py::arg("epsilon"), + py::arg("eta"), + py::arg("symmetry"), + py::arg("UPLO"), + py::kw_only(), + py::arg("reqrank") = -1, + py::arg("low_rank_strategy") = nullptr); // Build - // py_class.def("build", [](const Class &self, const VirtualGenerator &generator) { return self.build(generator); }); - py_class.def("build", [](const Class &self, const VirtualGenerator &generator) { return self.build(InternalGeneratorWithPermutation(generator, self.get_target_cluster().get_permutation().data(), self.get_source_cluster().get_permutation().data())); }); + py_class.def("build", [](const Class &self, const VirtualGenerator &generator, const Cluster &target_cluster, const Cluster &source_cluster, int target_partition_number, int partition_number_for_symmetry) { return self.build(generator, target_cluster, source_cluster, target_partition_number, partition_number_for_symmetry); }, py::arg("generator"), py::arg("target_cluster"), py::arg("source_cluster"), py::arg("target_partition_number") = -1, py::arg("partition_number_for_symmetry") = -1); // Setters py_class.def("set_minimal_source_depth", &Class::set_minimal_source_depth); py_class.def("set_minimal_target_depth", &Class::set_minimal_target_depth); - py_class.def("set_low_rank_generator", [](Class &self, const std::shared_ptr> &low_rank_generator) { self.set_low_rank_generator(low_rank_generator); }); - py_class.def("set_dense_blocks_generator", [](Class &self, const std::shared_ptr> &dense_blocks_generator) { self.set_dense_blocks_generator(dense_blocks_generator); }); + py_class.def("set_low_rank_generator", [](Class &self, std::shared_ptr> low_rank_generator) { self.set_low_rank_generator(low_rank_generator); }); + py_class.def("set_dense_blocks_generator", [](Class &self, std::shared_ptr> dense_blocks_generator) { self.set_dense_blocks_generator(dense_blocks_generator); }); } #endif diff --git a/src/htool/hmatrix/interfaces/virtual_low_rank_generator.hpp b/src/htool/hmatrix/interfaces/virtual_low_rank_generator.hpp index 732a7ed..c9a722d 100644 --- a/src/htool/hmatrix/interfaces/virtual_low_rank_generator.hpp +++ b/src/htool/hmatrix/interfaces/virtual_low_rank_generator.hpp @@ -21,11 +21,11 @@ class VirtualLowRankGeneratorPython : public VirtualLowRankGenerator &A, const Cluster &target_cluster, const Cluster &source_cluster, underlying_type epsilon, int &rank, Matrix &U, Matrix &V) const override { - py::array_t rows(std::array{target_cluster.get_size()}, target_cluster.get_permutation().data() + target_cluster.get_offset(), py::capsule(target_cluster.get_permutation().data())); - py::array_t cols(std::array{source_cluster.get_size()}, source_cluster.get_permutation().data() + source_cluster.get_offset(), py::capsule(source_cluster.get_permutation().data())); + void copy_low_rank_approximation(const VirtualInternalGenerator &A, int M, int N, const int *const rows, const int *const cols, underlying_type epsilon, int &rank, Matrix &U, Matrix &V) const override { + py::array_t py_rows(std::array{M}, rows, py::capsule(rows)); + py::array_t py_cols(std::array{N}, cols, py::capsule(cols)); - build_low_rank_approximation(rows, cols, epsilon); + build_low_rank_approximation(py_rows, py_cols, epsilon); U.assign(m_mats_U.back().shape()[0], m_mats_U.back().shape()[1], m_mats_U.back().mutable_data(), false); V.assign(m_mats_V.back().shape()[0], m_mats_V.back().shape()[1], m_mats_V.back().mutable_data(), false); } @@ -39,7 +39,6 @@ class VirtualLowRankGeneratorPython : public VirtualLowRankGenerator V0) { m_mats_V.push_back(V0); } - }; template diff --git a/tests/conftest.py b/tests/conftest.py index 1f3f626..3c5c4ce 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -217,15 +217,10 @@ def custom_distributed_operator( ) else: hmatrix_builder = Htool.HMatrixBuilder( - target_cluster, - source_cluster, epsilon, eta, symmetry, UPLO, - -1, - mpi4py.MPI.COMM_WORLD.rank, - mpi4py.MPI.COMM_WORLD.rank, ) if dense_blocks_generator is not None: hmatrix_builder.set_dense_blocks_generator(dense_blocks_generator)