#ifndef __PYARPACKSERVICES_HPP__ #define __PYARPACKSERVICES_HPP__ #include #include #include #include #include // sqrt. #include #include #include namespace bp = boost::python; namespace bn = boost::python::numpy; #define ARPACKSOLVERMEMBER(pyarpackSolver) \ .def_readwrite("symPb", &pyarpackSolver::symPb, \ "symmetric problem - default: true") \ .def_readwrite("nbEV", &pyarpackSolver::nbEV, \ "number of eigen vectors to find - default: 1") \ .def_readwrite("nbCV", &pyarpackSolver::nbCV, \ "number of dimensions of the workspace - default: 3") \ .def_readwrite("tol", &pyarpackSolver::tol, \ "tolerance - default: 1.e-6") \ .def_readwrite("sigmaReal", &pyarpackSolver::sigmaReal, \ "shift over real axis - default: 0.") \ .def_readwrite("sigmaImag", &pyarpackSolver::sigmaImag, \ "shift over imaginary axis - default: 0.") \ .def_readwrite("dumpToFile", &pyarpackSolver::dumpToFile, \ "dump eigen vectors to arpackSolver.*.out files - default: false") \ .def_readwrite("restartFromFile", &pyarpackSolver::restartFromFile, \ "restart from eigen vectors found in arpackSolver.*.out files - default: false") \ .def_readwrite("mag", &pyarpackSolver::mag, \ "magnitude - default: LM") \ .def_readwrite("maxIt", &pyarpackSolver::maxIt, \ "maximum number of arpack iterations - default: 100") \ .def_readwrite("schur", &pyarpackSolver::schur, \ "compute schur vectors - default: false") \ .def_readwrite("verbose", &pyarpackSolver::verbose, \ "verbosity level - default: 0") \ .def_readonly ("stdPb", &pyarpackSolver::stdPb, \ "standard or generalised problem - default: true") \ .def_readonly ("val", &pyarpackSolver::val, \ "eigen values found") \ .def_readonly ("vec", &pyarpackSolver::vec, \ "eigen vectors found") \ .def_readonly ("mode", &pyarpackSolver::mode, \ "selected arpack mode (according to input options: std/gen, shift, ...)") \ .def_readonly ("nbIt", &pyarpackSolver::nbIt, \ "number of arpack iterations") \ .def_readonly ("imsTime", &pyarpackSolver::imsTime, \ "time spent to initialize the mode solver if needed") \ .def_readonly ("rciTime", &pyarpackSolver::rciTime, \ "time spent in Reverse Communication Interface") \ .def_readwrite("debug", &pyarpackSolver::debug, \ "debug traces (up to 3) - default: 0") \ #define ARPACKSOLVERDEBUGSTAT() \ if (debug > 3) debug = 3; \ debug_c(6, -6, debug, debug, debug, debug, debug, debug, debug, debug, debug, debug, debug, \ debug, debug, debug, debug, debug, debug, debug, debug, debug, debug, debug); \ stat_c(nopx, nbx, nrorth, nitref, nrstrt, tsaupd, tsaup2, \ tsaitr, tseigt, tsgets, tsapps, tsconv, tnaupd, tnaup2, \ tnaitr, tneigt, tngets, tnapps, tnconv, tcaupd, tcaup2, \ tcaitr, tceigt, tcgets, tcapps, tcconv, tmvopx, tmvbx, \ tgetv0, titref, trvec); \ void pyarpackThrowError(std::string const & msg) { std::string const info = "Error: " + msg; std::cerr << info << std::endl; PyErr_SetString(PyExc_IndexError, info.c_str()); bp::throw_error_already_set(); }; template class pyarpackServices { // Public methods. public: static int buildSparseMatrice(bp::tuple const & T, Eigen::SparseMatrix & M, a_int const & debug, std::string const & msg) { // Get boost data as C++ data. if (bp::len(T) != 4) {pyarpackThrowError(msg + " must be a 3-tuple"); return 1;} bp::extract nExt(T[0]); bp::extract iExt(T[1]); bp::extract jExt(T[2]); bp::extract mijExt(T[3]); if (! nExt.check()) {pyarpackThrowError(msg + "[0] must be an integer" ); return 1;} if (! iExt.check()) {pyarpackThrowError(msg + "[1] must be numpy.array"); return 1;} if (! jExt.check()) {pyarpackThrowError(msg + "[2] must be numpy.array"); return 1;} if (!mijExt.check()) {pyarpackThrowError(msg + "[3] must be numpy.array"); return 1;} bn::ndarray iArray = iExt(); bn::ndarray jArray = jExt(); bn::ndarray mijArray = mijExt(); if (iArray.get_dtype() != bn::dtype::get_builtin()) {pyarpackThrowError(msg + "[1] type is not consistent"); return 1;} if (jArray.get_dtype() != bn::dtype::get_builtin()) {pyarpackThrowError(msg + "[2] type is not consistent"); return 1;} if (mijArray.get_dtype() != bn::dtype::get_builtin() ) {pyarpackThrowError(msg + "[3] type is not consistent with arpack type"); return 1;} a_int iSz = iArray.shape(0); a_int * iPtr = reinterpret_cast(iArray.get_data()); a_int jSz = jArray.shape(0); a_int * jPtr = reinterpret_cast(jArray.get_data()); a_int mSz = mijArray.shape(0); RC * mPtr = reinterpret_cast(mijArray.get_data()); if (iSz != jSz) {pyarpackThrowError(msg + "[1] and " + msg + "[2] must have same lenght"); return 1;} if (iSz != mSz) {pyarpackThrowError(msg + "[1] and " + msg + "[3] must have same lenght"); return 1;} // Debug on demand: casting value on numpy.append is MANDATORY or C++ won't get the expected type.. for (auto k = 0; debug && k < mSz; k++) { std::cout << "pyarpackServices::buildSparseMatrice - " << msg << "[" << iPtr[k] << ", " << jPtr[k] << "] = " << mPtr[k] << std::endl; }; // Build sparse matrice. a_uint n = nExt(); a_uint iMin = n+1, jMin = n+1; for (auto k = 0; k < mSz; k++) { if (iPtr[k] < iMin) iMin = iPtr[k]; if (jPtr[k] < jMin) jMin = jPtr[k]; }; if (iMin != 0 && iMin != 1) {pyarpackThrowError(msg + ": smallest row indice must be 0 or 1"); return 1;} if (jMin != 0 && jMin != 1) {pyarpackThrowError(msg + ": smallest column indice must be 0 or 1"); return 1;} a_int iBased = 0, jBased = 0; if (iMin == 1) iBased = 1; if (jMin == 1) jBased = 1; M = Eigen::SparseMatrix(n, n); // Set matrice dimensions. std::vector> triplets; a_uint nnz = mSz; triplets.reserve(nnz); for (auto k = 0; k < nnz; k++) triplets.emplace_back(iPtr[k] - iBased, jPtr[k] - jBased, mPtr[k]); M.setFromTriplets(triplets.begin(), triplets.end()); // Set all (i, j, Mij). return 0; }; static int buildDenseMatrice(bp::tuple const & T, Eigen::Matrix & M, a_int const & debug, std::string const & msg) { // Get boost data as C++ data. if (bp::len(T) != 2) {pyarpackThrowError(msg + " must be a 2-tuple"); return 1;} bp::extract mijExt(T[0]); bp::extract oExt(T[1]); if (!mijExt.check()) {pyarpackThrowError(msg + " must be numpy.array"); return 1;} if ( !oExt.check()) {pyarpackThrowError(msg + " must be a boolean"); return 1;} bn::ndarray mijArray = mijExt(); bool rowOrdered = oExt(); if (mijArray.get_dtype() != bn::dtype::get_builtin()) {pyarpackThrowError(msg + " type is not consistent with arpack type"); return 1;} a_int mSz = mijArray.shape(0); RC * mPtr = reinterpret_cast(mijArray.get_data()); a_uint n = std::sqrt(mSz); if (n*n != mSz) {pyarpackThrowError(msg + " must be a squared matrice"); return 1;} // Debug on demand: casting value on numpy.append is MANDATORY or C++ won't get the expected type.. for (auto k = 0; debug && k < mSz; k++) { std::cout << "pyarpackServices::buildDenseMatrice - " << msg << "[" << k << "] = " << mPtr[k] << std::endl; }; // Build dense matrice. M = Eigen::Matrix(n, n); // Set matrice dimensions. M.setZero(n, n); // Avoid spurious/random values which may break solves (LU, QR, ...). if (rowOrdered) { for (size_t k = 0; k < n; k++) { for (size_t l = 0; l < n; l++) M(k, l) = mPtr[l+k*n]; } } else { for (size_t l = 0; l < n; l++) { for (size_t k = 0; k < n; k++) M(k, l) = mPtr[k+l*n]; } } return 0; }; }; #endif // Local Variables: // mode: c++ // c-file-style:"stroustrup" // show-trailing-whitespace: t // End: /* vim: set sw=2 ts=2 et smartindent :*/