Skip to content

Instantly share code, notes, and snippets.

@Hs293Go
Last active November 2, 2020 12:53
Show Gist options
  • Save Hs293Go/50ced79c1a64cf96379892b49c918c5d to your computer and use it in GitHub Desktop.
Save Hs293Go/50ced79c1a64cf96379892b49c918c5d to your computer and use it in GitHub Desktop.
Reading MATLAB .mat file in C++, storing data in a std::map keyed by variable names
/* MATLAB API Libraries
*
* The headers are typically located in ${MATLAB_ROOT}/extern/include
* where ${MATLAB_ROOT} is the directory of your matlab installation.
*
* To use these libraries, your program must link against libmx.so and libmat.so
* The shared libraries are typically located in ${MATLAB_ROOT}/bin/glnxa64
*
* CMake users add the following lines to your CMakeLists.txt
* find_package(Matlab REQUIRED)
* set(MATLAB_ROOT /fill/this/path/with/output/of/matlabroot/inside/MATLAB)
* target_link_libraries(${Project} ${MATLAB_ROOT}/bin/glnxa64/libmx.so
* ${MATLAB_ROOT}/bin/glnxa64/libmat.so)
*/
extern "C" {
#include "mat.h"
#include "matrix.h"
}
// STL libraries
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <vector>
/**
* @brief Read in data from the .mat file
*
* @param file A std::string of the .mat file name
* @returns A std::map with the names of variables as key and a tuple of: a
* std::vector<double> containing the elements, the number of rows, and the
* humber of columns, as values. i.e.
* { name of variable, {values, number of rows, number of columns}}
*
* A struct will be much cleaner, but in this demonstration library types
* are preferred over introducing new data types
*/
std::map<std::string, std::tuple<std::vector<double>, int, int>>
read_mat_file(const std::string &file) {
std::map<std::string, std::tuple<std::vector<double>, int, int>> matlab_data;
// Open the .mat file
MATFile *file_ptr = matOpen(file.c_str(), "r");
if (!file_ptr)
return matlab_data;
int variable_num = 0;
// Get the names and number of variables inside the .mat file
char **variable_names = matGetDir(file_ptr, &variable_num);
for (int i = 0; i < variable_num; ++i) {
const std::string name(variable_names[i]);
// mxArray is the C type for MATLAB array. It allocates dynamic memory, so
// wrap it inside a shared_ptr
std::shared_ptr<mxArray> pa(matGetVariable(file_ptr, variable_names[i]),
mxDestroyArray);
bool is_numeric = mxIsNumeric(pa.get());
bool is_nonempty = !mxIsEmpty(pa.get());
// Only proceed to read data if the variable is numeric and nonempty, and
// the mxArray is not null
if (pa && is_numeric && is_nonempty) {
// Get the number of data elements in the variable
const int size = mxGetNumberOfElements(pa.get());
// Get the data elements in the variable casted to a double array
const double *value_ptr = static_cast<double *>(mxGetDoubles(pa.get()));
const int ndim = mxGetNumberOfDimensions(pa.get());
// Only proceed if to read data if the variable is a 2D matrix.
if (value_ptr && ndim <= 2) {
// Construct a std::vector<double> from the data elements
const std::vector<double> value(value_ptr, value_ptr + size);
// Get number of rows and columns
const int M = mxGetM(pa.get());
const int N = mxGetN(pa.get());
// Exploit C++11 braced init-list to construct the map of tuple of
// vector and ints at the same time as insertion
matlab_data.insert({name, {value, M, N}});
}
}
}
// Close the .mat file and return
matClose(file_ptr);
return matlab_data;
}
/** Example usage:
*
* // matlab_data is a std::map keyed by variable names
* auto matlab_data = read_mat_file("matrix.mat");
*
* // mtrx is a tuple of {std::vector<double>, int, int}
* auto mtrx = matlab_data["mtrx"];
*
* std::vector<double> elements = std::get<0>(mtrx); // Extract elements
* const int rows = std::get<1>(mtrx); // Extract rows
* const int cols = std::get<2>(mtrx); // Extract cols
*
* { // C++17 only: structured binding
* auto& [elements, rows, cols] = mtrx; // Extract everything in one line
* }
*
* // Move to Eigen data structure
* const Eigen::Map<const Eigen::MatrixXd> eigen_mtrx(elements.data(), rows, cols);
*
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment