#include // PyErr_SetString. #include #include #include #include #include #include #include // ostringstream. #include #include namespace bp = boost::python; namespace bn = boost::python::numpy; template void exportArpackSparseItr(bp::scope& pySlv, std::string const& dtype) { // Created nested namespace in module. pySlv.attr(dtype.c_str()) = bp::class_>( dtype.c_str(), "arpack data type (must be consistent with numpy dtype)") .def("solve", &pyarpackSparseItrSolver::solve, (bp::arg("A"), bp::arg("B") = bp::tuple()), "solve standard or generalised eigen problem where A and B must " "be sparse and provided in coo format: (dimension, row-indice " "array, column-indice array, matrice-value array) tuple") .def("checkEigVec", &pyarpackSparseItrSolver::checkEigVec, (bp::arg("A"), bp::arg("B") = bp::tuple(), bp::arg("diffTol") = 1.e-3), "check eigen vectors accuracy where A and B must be sparse and " "provided in coo format: (dimension, row-indice array, " "column-indice array, matrice-value array) tuple") ARPACKSOLVERMEMBER(pyarpackSparseItrSolver) .def_readwrite( "slvTol", &pyarpackSparseItrSolver::slvTol, "tolerance of the iterative mode solver - default: 1.e-6") .def_readwrite("slvMaxIt", &pyarpackSparseItrSolver::slvMaxIt, "maximum number of iterations of the iterative mode " "solver - default: 100") .def_readwrite( "slvILUDropTol", &pyarpackSparseItrSolver::slvILUDropTol, "drop tolerance of the ILU preconditioner (if any) of the " "iterative mode solver - default: 1") .def_readwrite( "slvILUFillFactor", &pyarpackSparseItrSolver::slvILUFillFactor, "fill factor of the ILU preconditioner (if any) of the iterative " "mode solver - default: 2"); }; template void exportArpackSparseDrt(bp::scope& pySlv, std::string const& dtype) { // Created nested namespace in module. pySlv.attr(dtype.c_str()) = bp::class_>( dtype.c_str(), "arpack data type (must be consistent with numpy dtype)") .def("solve", &pyarpackSparseDrtSolver::solve, (bp::arg("A"), bp::arg("B") = bp::tuple()), "solve standard or generalised eigen problem where A and B must " "be sparse and provided in coo format: (dimension, row-indice " "array, column-indice array, matrice-value array) tuple") .def("checkEigVec", &pyarpackSparseDrtSolver::checkEigVec, (bp::arg("A"), bp::arg("B") = bp::tuple(), bp::arg("diffTol") = 1.e-3), "check eigen vectors accuracy where A and B must be sparse and " "provided in coo format: (dimension, row-indice array, " "column-indice array, matrice-value array) tuple") ARPACKSOLVERMEMBER(pyarpackSparseDrtSolver) .def_readwrite( "slvPvtThd", &pyarpackSparseDrtSolver::slvPvtThd, "pivoting tolerance of the direct mode solver - default: 1.e-6") .def_readwrite("slvOffset", &pyarpackSparseDrtSolver::slvOffset, "cholesky offset (LLT, LDLT) of the direct mode " "solver - default: 0.") .def_readwrite("slvScale", &pyarpackSparseDrtSolver::slvScale, "cholesky scale (LLT, LDLT) of the direct mode solver " "- default: 1."); }; template void exportArpackDenseDrt(bp::scope& pySlv, std::string const& dtype) { // Created nested namespace in module. pySlv.attr(dtype.c_str()) = bp::class_>( dtype.c_str(), "arpack data type (must be consistent with numpy dtype)") .def("solve", &pyarpackDenseDrtSolver::solve, (bp::arg("A"), bp::arg("B") = bp::tuple()), "solve standard or generalised eigen problem where A and B must " "be dense and provided in raw format: (n-squared matrice-value " "array, row or column ordered boolean)") .def("checkEigVec", &pyarpackDenseDrtSolver::checkEigVec, (bp::arg("A"), bp::arg("B") = bp::tuple(), bp::arg("diffTol") = 1.e-3), "check eigen vectors accuracy where A and B must be dense and " "provided in raw format: (n-squared matrice-value array, row or " "column ordered boolean)") ARPACKSOLVERMEMBER(pyarpackDenseDrtSolver) .def_readwrite( "slvPvtThd", &pyarpackDenseDrtSolver::slvPvtThd, "pivoting tolerance of the direct mode solver - default: 1.e-6") .def_readwrite("slvOffset", &pyarpackDenseDrtSolver::slvOffset, "cholesky offset (LLT, LDLT) of the direct mode " "solver - default: 0.") .def_readwrite("slvScale", &pyarpackDenseDrtSolver::slvScale, "cholesky scale (LLT, LDLT) of the direct mode solver " "- default: 1."); }; class sparseBiCGDiag {}; class sparseBiCGILU {}; class sparseCGDiag {}; class sparseCGILU {}; class sparseLLT {}; class sparseLDLT {}; class sparseLU {}; class sparseQR {}; class denseLLT {}; class denseLDLT {}; class denseLURR {}; class denseQRRR {}; class denseLUPP {}; class denseQRPP {}; std::complex EigVecZGetItem( Eigen::Matrix, Eigen::Dynamic, 1>& M, int idx) { if (idx < 0 || idx >= M.size()) { pyarpackThrowError("index out of range"); return std::complex(); } return M[idx]; }; std::string EigVecZToString(EigVecZ const& vec) { std::ostringstream s; s << vec; return s.str(); }; BOOST_PYTHON_MODULE(pyarpack) { // Initialize. bn::initialize(); bp::class_>>("StdVecZ").def( bp::vector_indexing_suite>>()); bp::class_, Eigen::Dynamic, 1>>("EigVecZ") .def("__getitem__", &EigVecZGetItem) .def("__str__", &EigVecZToString); bp::class_>("StdVecEVZ") .def("__iter__", bp::iterator>()) .def(bp::vector_indexing_suite>()); // Documentation of the python module. std::ostringstream doc; doc << "You can use sparse or dense matrices, and, play with iterative or direct mode solvers (CG, LU, ...):" << std::endl; doc << "1. choose arpack solver with a given mode solver" << std::endl; doc << " 1.1. if you need to handle sparse matrices" << std::endl; doc << " >> from pyarpack import sparseBiCG as pyarpackSlv" << std::endl; doc << " 1.2. if you need to handle dense matrices" << std::endl; doc << " >> from pyarpack import denseBiCG as pyarpackSlv" << std::endl; doc << "2. choose arpack data type (float, double, ...)" << std::endl; doc << " >> arpackSlv = pyarpackSlv.double()" << std::endl; doc << "3. solve the eigen problem" << std::endl; doc << " >> arpackSlv.solve(A, B)" << std::endl; doc << "4. get eigen values and vectors" << std::endl; doc << " >> print(arpackSlv.vec)" << std::endl; doc << " >> print(arpackSlv.val)" << std::endl; doc << std::endl; doc << "Notes:" << std::endl; doc << "1. arpack data type (float, double, ...) must be consistent with A/B numpy dtypes (float32, float64, ...)." << std::endl; doc << " at python side, the data MUST be casted in the EXACT expected type (int32, int64, float, double, ...)." << std::endl; doc << " otherwise, C++ may not get the data the way it expects them: C++ will not know how to read python data." << std::endl; doc << " if you are not sure how data have been passed from python to C++, set arpackSlv.debug = 1 and check out debug traces." << std::endl; doc << " in other words, pyarpack users MUST :" << std::endl; doc << " 1.1. create numpy arrays specifying explicitly the type:" << std::endl; doc << " >> Aij = np.array([], dtype='complex128')" << std::endl; doc << " 1.2. filling numpy arrays casting value on append:" << std::endl; doc << " >> Aij = np.append(Aij, np.complex128(np.complex( 200., 200.))) # Casting value on append is MANDATORY or C++ won't get the expected type." << std::endl; doc << " 1.3. calling the solver flavor which is consistent with the numpy array data type:" << std::endl; doc << " >> arpackSlv = pyarpackSlv.complexDouble() # Caution: complexDouble <=> np.array(..., dtype='complex128')" << std::endl; doc << " note: NO data type check can be done at C++ side, the pyarpack user MUST insure data consistency." << std::endl; doc << "2. sparse matrices must be provided in coo format (n, i, j, Mij), that is, as a tuple where:" << std::endl; doc << " 2.1. n is an integer." << std::endl; doc << " 2.2. i, j, Mij are 1 x nnz numpy arrays." << std::endl; doc << "3. dense matrices must be provided in raw format (Mij, rowOrdered), that is, as a tuple where:" << std::endl; doc << " 3.1. Mij is an n x n numpy array." << std::endl; doc << " 3.2. rowOrdered is a boolean (column ordered if False)." << std::endl; doc << "4. arpack mode solver are provided by eigen:" << std::endl; doc << " 4.1. when solver is iterative, A and B can be sparse only." << std::endl; doc << " 4.2. when solver is direct, A and B can be sparse or dense." << std::endl; bp::scope().attr("__doc__") = doc.str().c_str(); // Specify that this module is actually a package. bp::object package = bp::scope(); package.attr("__path__") = "pyarpack"; // Create python module. std::string module = "pyarpack"; bp::object pyModule( bp::handle<>(bp::borrowed(PyImport_AddModule(module.c_str())))); // Create modules. { std::string slv = "sparseBiCGDiag"; std::string slvHelp = "arpack internal mode solver (mode > 1): BiCG with diagonal (Jacobi) " "preconditioner"; bp::scope pySlvBiCGDiag = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackSparseItr(pySlvBiCGDiag, "float"); exportArpackSparseItr(pySlvBiCGDiag, "double"); exportArpackSparseItr, float, EigSMxC, EigSBiCGC>( pySlvBiCGDiag, "complexFloat"); exportArpackSparseItr, double, EigSMxZ, EigSBiCGZ>( pySlvBiCGDiag, "complexDouble"); } { std::string slv = "sparseBiCGILU"; std::string slvHelp = "arpack internal mode solver (mode > 1): BiCG with ILU preconditioner"; bp::scope pySlvBiCGILU = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackSparseItr(pySlvBiCGILU, "float"); exportArpackSparseItr(pySlvBiCGILU, "double"); exportArpackSparseItr, float, EigSMxC, EigSBiCGILUC>( pySlvBiCGILU, "complexFloat"); exportArpackSparseItr, double, EigSMxZ, EigSBiCGILUZ>( pySlvBiCGILU, "complexDouble"); } { std::string slv = "sparseCGDiag"; std::string slvHelp = "arpack internal mode solver (mode > 1): CG with diagonal (Jacobi) " "preconditioner"; bp::scope pySlvCGDiag = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackSparseItr(pySlvCGDiag, "float"); exportArpackSparseItr(pySlvCGDiag, "double"); exportArpackSparseItr, float, EigSMxC, EigSCGC>( pySlvCGDiag, "complexFloat"); exportArpackSparseItr, double, EigSMxZ, EigSCGZ>( pySlvCGDiag, "complexDouble"); } { std::string slv = "sparseCGILU"; std::string slvHelp = "arpack internal mode solver (mode > 1): CG with ILU preconditioner"; bp::scope pySlvCGILU = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackSparseItr(pySlvCGILU, "float"); exportArpackSparseItr(pySlvCGILU, "double"); exportArpackSparseItr, float, EigSMxC, EigSCGILUC>( pySlvCGILU, "complexFloat"); exportArpackSparseItr, double, EigSMxZ, EigSCGILUZ>( pySlvCGILU, "complexDouble"); } { std::string slv = "sparseLLT"; std::string slvHelp = "arpack internal mode solver (mode > 1): LLT"; bp::scope pySlvLLT = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackSparseDrt(pySlvLLT, "float"); exportArpackSparseDrt(pySlvLLT, "double"); exportArpackSparseDrt, float, EigSMxC, EigSLLTC>( pySlvLLT, "complexFloat"); exportArpackSparseDrt, double, EigSMxZ, EigSLLTZ>( pySlvLLT, "complexDouble"); } { std::string slv = "sparseLDLT"; std::string slvHelp = "arpack internal mode solver (mode > 1): LDLT"; bp::scope pySlvLDLT = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackSparseDrt(pySlvLDLT, "float"); exportArpackSparseDrt(pySlvLDLT, "double"); exportArpackSparseDrt, float, EigSMxC, EigSLDLTC>( pySlvLDLT, "complexFloat"); exportArpackSparseDrt, double, EigSMxZ, EigSLDLTZ>( pySlvLDLT, "complexDouble"); } { std::string slv = "sparseLU"; std::string slvHelp = "arpack internal mode solver (mode > 1): LU"; bp::scope pySlvLU = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackSparseDrt(pySlvLU, "float"); exportArpackSparseDrt(pySlvLU, "double"); exportArpackSparseDrt, float, EigSMxC, EigSLUC>( pySlvLU, "complexFloat"); exportArpackSparseDrt, double, EigSMxZ, EigSLUZ>( pySlvLU, "complexDouble"); } { std::string slv = "sparseQR"; std::string slvHelp = "arpack internal mode solver (mode > 1): QR"; bp::scope pySlvQR = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackSparseDrt(pySlvQR, "float"); exportArpackSparseDrt(pySlvQR, "double"); exportArpackSparseDrt, float, EigSMxC, EigSQRC>( pySlvQR, "complexFloat"); exportArpackSparseDrt, double, EigSMxZ, EigSQRZ>( pySlvQR, "complexDouble"); } { std::string slv = "denseLLT"; std::string slvHelp = "arpack internal mode solver (mode > 1): LLT"; bp::scope pySlvLLT = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackDenseDrt(pySlvLLT, "float"); exportArpackDenseDrt(pySlvLLT, "double"); exportArpackDenseDrt, float, EigDMxC, EigDLLTC>( pySlvLLT, "complexFloat"); exportArpackDenseDrt, double, EigDMxZ, EigDLLTZ>( pySlvLLT, "complexDouble"); } { std::string slv = "denseLDLT"; std::string slvHelp = "arpack internal mode solver (mode > 1): LDLT"; bp::scope pySlvLDLT = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackDenseDrt(pySlvLDLT, "float"); exportArpackDenseDrt(pySlvLDLT, "double"); exportArpackDenseDrt, float, EigDMxC, EigDLDLTC>( pySlvLDLT, "complexFloat"); exportArpackDenseDrt, double, EigDMxZ, EigDLDLTZ>( pySlvLDLT, "complexDouble"); } { std::string slv = "denseLURR"; std::string slvHelp = "arpack internal mode solver (mode > 1): LU Rank Revealing (slower, " "more stable)"; bp::scope pySlvLURR = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackDenseDrt(pySlvLURR, "float"); exportArpackDenseDrt(pySlvLURR, "double"); exportArpackDenseDrt, float, EigDMxC, EigDFLUC>( pySlvLURR, "complexFloat"); exportArpackDenseDrt, double, EigDMxZ, EigDFLUZ>( pySlvLURR, "complexDouble"); } { std::string slv = "denseQRRR"; std::string slvHelp = "arpack internal mode solver (mode > 1): QR Rank Revealing (slower, " "more stable)"; bp::scope pySlvQRRR = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackDenseDrt(pySlvQRRR, "float"); exportArpackDenseDrt(pySlvQRRR, "double"); exportArpackDenseDrt, float, EigDMxC, EigDFQRC>( pySlvQRRR, "complexFloat"); exportArpackDenseDrt, double, EigDMxZ, EigDFQRZ>( pySlvQRRR, "complexDouble"); } { std::string slv = "denseLUPP"; std::string slvHelp = "arpack internal mode solver (mode > 1): LU Partial Pivoting (faster, " "less stable)"; bp::scope pySlvLUPP = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackDenseDrt(pySlvLUPP, "float"); exportArpackDenseDrt(pySlvLUPP, "double"); exportArpackDenseDrt, float, EigDMxC, EigDPLUC>( pySlvLUPP, "complexFloat"); exportArpackDenseDrt, double, EigDMxZ, EigDPLUZ>( pySlvLUPP, "complexDouble"); } { std::string slv = "denseQRPP"; std::string slvHelp = "arpack internal mode solver (mode > 1): QR Partial Pivoting (faster, " "less stable)"; bp::scope pySlvQPPR = bp::class_(slv.c_str(), slvHelp.c_str()); exportArpackDenseDrt(pySlvQPPR, "float"); exportArpackDenseDrt(pySlvQPPR, "double"); exportArpackDenseDrt, float, EigDMxC, EigDPQRC>( pySlvQPPR, "complexFloat"); exportArpackDenseDrt, double, EigDMxZ, EigDPQRZ>( pySlvQPPR, "complexDouble"); } } // Local Variables: // mode: c++ // c-file-style:"stroustrup" // show-trailing-whitespace: t // End: /* vim: set sw=2 ts=2 et smartindent :*/