matio-cpp
is a C++ wrapper for the matio
library, automatically dealing with memory allocation and deallocation.
It can be used for reading and writing binary MATLAB .mat
files from C++, without the need to access or rely on MATLAB's own shared libraries.
The depencies are CMake
(minimum version 3.10) and matio
. While we suggest to follow the build instructions provided in the matio
home page, it can also installed from common package managers:
- Linux:
sudo apt install libmatio-dev
- Linux, macOS, Windows, via
conda-forge
:conda install -c conda-forge libmatio
Eigen
is an optional dependency. If available, some conversions are defined.
For running the tests, it is necessary to install Catch2
. Where supported, valgrind
can be installed to check for memory leaks.
git clone https://github.com/ami-iit/matio-cpp
cd matio-cpp
mkdir build && cd build
cmake ../
make
[sudo] make install
Notice: sudo
is not necessary if you specify the CMAKE_INSTALL_PREFIX
. In this case it is necessary to add in the .bashrc
or .bash_profile
the following lines:
export matioCpp_DIR=/path/where/you/installed/
With IDE build tool facilities, such as Visual Studio:
git clone https://github.com/ami-iit/matio-cpp
cd matio-cpp
mkdir build && cd build
cmake ..
cmake --build . --target ALL_BUILD --config Release
cmake --build . --target INSTALL --config Release
In order to allow CMake finding matio-cpp
, it is necessary that the installation folder is in the PATH
.
matio-cpp
provides native CMake support which allows the library to be easily used in CMake projects
In order to use matio-cpp
in your project, add the following in your CMakeLists.txt
find_package(matioCpp REQUIRED)
# ...
target_link_libraries(yourTarget PRIVATE matioCpp::matioCpp)
matio-cpp
can handle the following data types:
Element
, likedouble
,int
, ...String
Vector
, i.e. 1-dimensional arrays of primitive typesMultiDimensionalArray
, i.e. n-dimensional arrays of primitive typesCellArray
, i.e. n-dimensional arrays of generic typesStruct
, i.e. a collection of name/variable pairsStructArray
, i.e. n-dimensional arrays ofStructs
All these types can be read/written from/to .mat
files.
Read a .mat
file
#include <matioCpp/matioCpp.h>
// ...
matioCpp::File input("input.mat");
// You can check if input is open with the isOpen() method
matioCpp::CellArray cellArray = input.read("cell_array").asCellArray(); //Read a Cell Array named "cell_array"
matioCpp::Element<double> doubleVar = cellArray({1,2,3}).asElement<double>(); //Get the element in the cell array at position (1,2,3) (0-based), casting it as a double Element
doubleVar = 3.14; //Set the doubleVar to a new value
assert(cellArray({1,2,3}).asElement<double>()() == 3.14); //Also the original cell array is modified, but not in the file.
Write a .mat
file
#include <matioCpp/matioCpp.h>
// ...
matioCpp::File file = matioCpp::File::Create("test.mat"); //If the file already exists, use the same cnstructor as the example above
std::vector<double> in = {2.0,4.0,6.0,8.0};
matioCpp::Vector<double> out("test_vector");
out = in;
file.write(out);
matioCpp::String testString("string_name");
testString = "string content";
file.write(testString);
It is possibile to convert common types to matioCpp
types with the function matioCpp::make_variable
. Examples:
std::vector<double> stdVec = {1.0, 2.0, 3.0, 4.0, 5.0};
auto toMatioVec = matioCpp::make_variable("test", stdVec);
std::array<float,3> array = {1.0, 2.0, 3.0};
auto toMatioArray = matioCpp::make_variable("test", array);
int classicalArray[] = {1, 2, 3};
auto toMatioClassic = matioCpp::make_variable("test", matioCpp::make_span(classicalArray, 3));
std::string string("something");
auto toMatioString = matioCpp::make_variable("name", string);
std::vector<bool> vecOfBool = {true, false, true};
auto toVecofBool = matioCpp::make_variable("vecOfBool", vecOfBool);
auto matioDouble = matioCpp::make_variable("double", 5.0);
auto matioBool = matioCpp::make_variable("bool", true);
auto matioInt = matioCpp::make_variable("int", 2);
auto matioChar = matioCpp::make_variable("char", 'f');
std::vector<std::string> stringVector = {"Huey", "Dewey", "Louie"};
auto matioCell = matioCpp::make_variable("stringVector", stringVector);
If eigen
is available, it is also possible to convert from and to eigen
types:
matioCpp::Vector<double> vector("vector", 5);
Eigen::VectorXd eigenVec = matioCpp::to_eigen(vector);
matioCpp::MultiDimensionalArray<float> matioCppMatrix("matrix");
Eigen::MatrixXf toEigenMatrix = matioCpp::to_eigen(matioCppMatrix);
Eigen::Matrix3f eigenMatrix;
eigenMatrix << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0;
auto toMatioMatrix = matioCpp::make_variable("testMatrix", eigenMatrix);
Eigen::Vector3i eigenVec;
eigenVec << 2, 4, 6;
auto toMatioEigenVec = matioCpp::make_variable("testEigen", eigenVec);
It is also possible to slice a MultiDimensionalArray
into an Eigen matrix:
std::vector<float> tensor(12);
for (size_t i = 0; i < 12; ++i)
{
tensor[i] = i + 1.0;
}
matioCpp::MultiDimensionalArray<float> matioCppMatrix2("matrix", { 2, 2, 3 }, tensor.data());
/*
So we have a tensor of the type
| 1 3 | | 5 7 | | 9 11 |
| 2 4 | | 6 8 | | 10 12 |
*/
Eigen::MatrixXf slice1 = matioCpp::to_eigen(matioCppMatrix2, { -1, -1, 0 }; //Equivalent to the Matlab operation matioCppMatrix2(:,:,1)
/*
Obtain
| 1 3 |
| 2 4 |
*/
Eigen::MatrixXf slice2 = matioCpp::to_eigen(matioCppMatrix2, { 1, -1, -1 }; //Equivalent to the Matlab operation matioCppMatrix2(2,:,:)
/*
Obtain
| 2 6 10|
| 4 8 12|
*/
Eigen::MatrixXf slice3 = matioCpp::to_eigen(matioCppMatrix2, { -1, 0, 0 }; //Equivalent to the Matlab operation matioCppMatrix2(:,1,1)
/*
Obtain
| 1 |
| 2 |
*/
In the slice, the value -1
means that the entire dimension is taken.
matioCpp
also exploits visit_struct
to parse C++ structs into matioCpp
structs. Example:
struct testStruct
{
int i{1};
double d{2.0};
std::string s{"test"};
std::vector<double> stdVec = {1.0, 2.0, 3.0, 4.0, 5.0};
int* notSupported = nullptr;
std::vector<std::string> stringVector = {"Huey", "Dewey", "Louie"};
std::vector<bool> vecOfBool = {true, false, true};
};
VISITABLE_STRUCT(testStruct, i, d, s, stdVec, vecOfBool, stringVector);
//----------
testStruct s;
matioCpp::Struct automaticStruct = matioCpp::make_variable("testStruct", s);
You can check the example in the example
folder on how to include and use matioCpp
.
- Complex arrays are not yet supported
- Cannot read timeseries from a
.mat
file (this is amatio
limitation tbeu/matio#99) - Cannot read string arrays from a
.mat
file (this is amatio
limitation tbeu/matio#98) - Cannot read strings in a
Struct
from a.mat
file (this is amatio
limitation related to tbeu/matio#98)
- Stefano Dafarra (@S-Dafarra)