#include // Let Armadillo print to Mathematica notebooks by default #define ARMA_COUT_STREAM mma::mout #define ARMA_CERR_STREAM mma::mout #include // We start by defining conversion functions to/from Armadillo's basic datatypes: // matrices, column vectors and sparse matrices. // Armadillo stores matrices in column major order, while Mathematica uses row-major order. // It is thus fastest to convert an MTensor to/from its transposed Armadillo equivalent. // Convert from Mathematica matrix to the transposed Armadillo equivalent without copying any data. template arma::Mat toArmaTransposed(mma::MatrixRef m) { // wrap MTensor with arma::mat without copying // See the "Advanced Constructors" documentation http://arma.sourceforge.net/docs.html#Mat return arma::Mat(m.data(), m.cols(), m.rows(), false /* do not copy */, false /* until resized */); } // Convert from Armadillo matrix to transposed Mathematica matrix. // This time the data must be copied. template mma::TensorRef fromArmaTransposed(const arma::Mat &m) { return mma::makeMatrix(m.n_cols, m.n_rows, m.memptr()); } // Convert from Mathematica vector to Armadillo column vector without copying. template arma::Col toArmaVec(mma::TensorRef v) { return arma::Col(v.data(), v.size(), false /* do not copy */, false /* until resized */); } // Convert from Armadillo column vector to Mathematica vector with copying. template mma::TensorRef fromArmaVec(const arma::Col &v) { return mma::makeVector(v.size(), v.memptr()); } // Convert from Mathematica sparse matrix to Armadillo sparse matrix. template arma::SpMat toArmaSparseTransposed(mma::SparseMatrixRef sm) { return arma::SpMat( // Column indices and row pointers must be explicitly converted // because Armadillo uses unsigned integers while Mathematica uses signed ones. arma::conv_to::from(toArmaVec(sm.columnIndices())) - 1, // convert to 0-based indices; Mathematica uses 1-based ones. arma::conv_to::from(toArmaVec(sm.rowPointers())), toArmaVec(sm.explicitValues()), sm.cols(), sm.rows() ); } // Convert from Armadillo sparse matrix to Mathematica SparseArray. template mma::SparseMatrixRef fromArmaSparse(const arma::SpMat &am) { // there are am.n_nonzero explicitly stored elements in am auto pos = mma::makeMatrix(am.n_nonzero, 2); // positions array auto vals = mma::makeVector(am.n_nonzero); // values array // iterate through all explicitly stored elements in the Armadillo sparse matrix and // fill out the positions and values arrays to be used in the creation of a Mathematica SparseArray mint i = 0; for (typename arma::SpMat::const_iterator it = am.begin(); it != am.end(); ++it, ++i) { vals[i] = *it; pos(i,0) = it.row() + 1; // convert 0-based index to 1-based pos(i,1) = it.col() + 1; } auto mm = mma::makeSparseMatrix(pos, vals, am.n_rows, am.n_cols); pos.free(); vals.free(); return mm; } class Arma { public: // Matrix inverse mma::RealMatrixRef inv(mma::RealMatrixRef mat) { arma::mat m = toArmaTransposed(mat); return fromArmaTransposed(arma::inv(m)); } // The first k complex eigenvalues of a sparse matrix mma::ComplexTensorRef eigs(mma::SparseMatrixRef sm, mint k) { return fromArmaVec(arma::eigs_gen(toArmaSparseTransposed(sm), k)); } // Random sparse matrix mma::SparseMatrixRef sprandu(mint i, mint j, double dens) { return fromArmaSparse(arma::sprandu(i, j, dens)); } // Solve a linear equation mma::RealTensorRef solve(mma::RealMatrixRef mat, mma::RealTensorRef vec) { return fromArmaVec( arma::solve(toArmaTransposed(mat).t(), // transpose back to match mat toArmaVec(vec)) ); } // Print an Armadillo matrix void print(mma::RealMatrixRef mat) { mma::mout << toArmaTransposed(mat).t(); } // Print an Armadillo sparse matrix void printSparse(mma::SparseMatrixRef sm) { mma::mout << toArmaSparseTransposed(sm); } };