MATLAB Tensor Indexing in C++ - c++

I am attempting to load in a .mat file containing a tensor of known dimensions in C++; 144x192x256.
I have adjusted the linear index for the read operation to be column major as in MATLAB. However I am still getting memory access issues.
void FeatureLoader::readMat(const std::string &fname, Image< std::vector<float> > *out) {
//Read MAT file.
const char mode = 'r';
MATFile *matFile = matOpen(fname.c_str(), &mode);
if (matFile == NULL) {
throw std::runtime_error("Cannot read MAT file.");
}
//Copy the data from column major to row major storage.
float *newData = newImage->GetData();
const mxArray *arr = matGetVariable(matFile, "map");
if (arr == NULL) {
throw std::runtime_error("Cannot read variable.");
}
double *arrData = (double*)mxGetPr(arr);
#pragma omp parallel for
for (int i = 0; i < 144; i++) {
#pragma omp parallel for
for (int j = 0; j < 192; j++) {
for (int k = 0; k < 256; k++) {
int rowMajIdx = (i * 192 + j) * 256 + k;
int colMajIdx = (j * 144 + i) * 256 + k;
newData[rowMajIdx] = static_cast<float>(arrData[colMajIdx]);
}
}
}
}
In the above snippet, am I right to be accessing the data linearly as with a flattened 3D array in C++? For example:-
idx_row_major = (x*WIDTH + y)*DEPTH + z
idx_col_major = (y*HEIGHT + x)*DEPTH + z
Is this the underlying representation that MATLAB uses?

You have some errors in the indexing of the row mayor and column mayor Idx. Additionally, naively accessing the data can lead to very slow times due to random memory access (memory latency is key! Read more here).
The best way to pass from MATLAB to C++ types (From 3D to 1D) is following the example below.
In this example we illustrate how to take a double real-type 3D matrix from MATLAB, and pass it to a C double* array.
The main objectives of this example are showing how to obtain data from MATLAB MEX arrays and to highlight some small details in matrix storage and handling.
matrixIn.cpp
#include "mex.h"
void mexFunction(int nlhs , mxArray *plhs[],
int nrhs, mxArray const *prhs[]){
// check amount of inputs
if (nrhs!=1) {
mexErrMsgIdAndTxt("matrixIn:InvalidInput", "Invalid number of inputs to MEX file.");
}
// check type of input
if( !mxIsDouble(prhs[0]) || mxIsComplex(prhs[0])){
mexErrMsgIdAndTxt("matrixIn:InvalidType", "Input matrix must be a double, non-complex array.");
}
// extract the data
double const * const matrixAux= static_cast<double const *>(mxGetData(prhs[0]));
// Get matrix size
const mwSize *sizeInputMatrix= mxGetDimensions(prhs[0]);
// allocate array in C. Note: its 1D array, not 3D even if our input is 3D
double* matrixInC= (double*)malloc(sizeInputMatrix[0] *sizeInputMatrix[1] *sizeInputMatrix[2]* sizeof(double));
// MATLAB is column major, not row major (as C). We need to reorder the numbers
// Basically permutes dimensions
// NOTE: the ordering of the loops is optimized for fastest memory access!
// This improves the speed in about 300%
const int size0 = sizeInputMatrix[0]; // Const makes compiler optimization kick in
const int size1 = sizeInputMatrix[1];
const int size2 = sizeInputMatrix[2];
for (int j = 0; j < size2; j++)
{
int jOffset = j*size0*size1; // this saves re-computation time
for (int k = 0; k < size0; k++)
{
int kOffset = k*size1; // this saves re-computation time
for (int i = 0; i < size1; i++)
{
int iOffset = i*size0;
matrixInC[i + jOffset + kOffset] = matrixAux[iOffset + jOffset + k];
}
}
}
// we are done!
// Use your C matrix here
// free memory
free(matrixInC);
return;
}
The relevant concepts to be aware of:
MATLAB matrices are all 1D in memory, no matter how many dimensions they have when used in MATLAB. This is also true for most (if not all) main matrix representation in C/C++ libraries, as allows optimization and faster execution.
You need to explicitly copy matrices from MATLAB to C in a loop.
MATLAB matrices are stored in column major order, as in Fortran, but C/C++ and most modern languages are row major. It is important to permute the input matrix , or else the data will look completely different.
The relevant function in this example are:
mxIsDouble checks if input is double type.
mxIsComplex checks if input is real or imaginary.
mxGetData returns a pointer to the real data in the input array. NULL if there is no real data.
mxGetDimensions returns an pointer to a mwSize array, with the size of the dimension in each index.

Related

Objective-C to C++ reading binary file into multidimensional array of float

I want to convert the following code from objective C to C++.
In the class myClass, I have this attribute:
float tab[dim1][dim2][dim3];
In an objective-C file, the multidimensional array is filled from a binary file:
NSData *dataTab=[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"pathOfMyTab" ofType:#""]];
[dataTab getBytes:myClass -> tab length:[dataTab length]];
How could I translate this part into C++ ?
I am assuming that your file contains the byte-representation of the array. If this is the case, then to mimic the behaviour of your Objective-C code using only C++ (the only thing that makes this C++ is the reinterpret_cast<>, otherwise it is just straight C), you could use the following code. I have not added any error checking, but left some comments where you might want to perform some.
float tab[dim1][dim2][dim3];
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef dataTabURL = CFBundleCopyResourceURL(mainBundle, CFSTR("pathOfMyTab"), NULL, NULL);
CFReadStreamRef stream = CFReadStreamCreateWithFile(NULL, dataTabURL); // check for NULL return value
CFReadStreamOpen(stream); // check for errors here
CFReadStreamRead(stream, reinterpret_cast<UInt8 *>(tab), sizeof tab); // check that this function returns the number of bytes you were expecting (sizeof tab)
CFReadStreamClose(stream);
// we own "stream" and "dataTabURL" because we obtained these through functions
// with "create" in the name, therefore we must relinquish ownership with CFRelease
CFRelease(stream);
CFRelease(dataTabURL); // ditto
If you already have the path available in a std::string, then you can use the following C++ code to mimic the behaviour of your Objective-C code:
// make sure to include this header
#include <fstream>
// ... then elsewhere in your .cpp file ...
float tab[dim1][dim2][dim3];
std::string path = "path/to/mytab"; // obtain from somewhere
std::ifstream input(path, std::ios::binary); // check that the file was successfully opened
input.read(reinterpret_cast<char *>(tab), sizeof tab); // check that input.gcount() is the number of bytes you expected
I believe in this case we have to use reinterpret_cast<> because the file contains the actual representation of the array (assuming it was previously written to the file in a similar manner).
You can use a hybrid approach, once you have the CFURLRef containing the path to the resource, you can obtain a file system representation of the URL using this function (providing a suitably sized output buffer to store the result), and from there you should be able to pass that to one of std::ifstream's constructors (although, you may need to cast to the appropriate type).
C++ doesn't support variable-length arrays (the size of arrays must be known at compile time). There is also no matrix type provided by the standard library, so if the dimensions of your table vary at run time, then you will need a completely separate approach to the one in my answer. You could consider serialising the output from Objective-C (using e.g. JSON or another format) such that the dimensions of the matrix are also written to the output, making it easier to parse the file in C++.
Take a look at fstream, fread and read, all read binary files, pick the approach that suits.
On my mind the simplest and fastest way is to use memcpy() to copy NSData' bytes into target array with same structure (dimensions) as a source one. See, for example:
https://github.com/Voldemarus/MultiDimensionalArrayDemo/tree/master
#import "DemoClass.h"
#define DIM1 3
#define DIM2 4
#define DIM3 2
#interface DemoClass() {
int src[DIM1][DIM2][DIM3]; // source (initial) array
int dst[DIM1][DIM2][DIM3]; // destination array
}
#end
#implementation DemoClass
- (instancetype) init
{
if (self = [super init]) {
for (int i = 0; i < DIM1; i++) {
for (int j = 0; j < DIM2; j++) {
for (int k = 0; k < DIM3; k++) {
int value = i*100 + j*10 + k;
src[i][j][k] = value;
}
}
}
}
return self;
}
int getIntFromArray(int *array, int i, int j, int k) {
int offset = j*DIM3 + i*DIM2*DIM3;
return array[offset];
}
void putIntToArray(int *array, int i, int j, int k, int value) {
int offset = j*DIM3 + i*DIM2*DIM3;
array[offset] = value;
}
- (void) run
{
// Step 1. Save array into NSData
NSInteger s = sizeof(int)*DIM1*DIM2*DIM3;
NSData *data = [[NSData alloc] initWithBytes:src length:s];
NSAssert(data, #"NSData should be created");
//Step2 - Create new array
int *bytes = (int *)[data bytes];
memcpy(dst,bytes,s);
// Step 3. Compare src and dst
for (int i = 0; i < DIM1; i++) {
for (int j = 0; j < DIM2; j++) {
for (int k = 0; k < DIM3; k++) {
int template = i*100 + j*10 + k;
int s = src[i][j][k];
int d = dst[i][j][k];
// NSLog(#"i %d j %d k %d -->s = %d d = %d",i,j,k,s,d);
NSAssert(s == template, #"Source array should have value from template");
NSAssert(d == s, #"Destination array should be identical to the source");
}
}
}
}
#end
float tab[dim1][dim2][dim3] looks like a three-dimensional array. The standard implementation is with three nested FOR loops.
So your C++ implementation can look like this:
read dim1, dim2, dim3 from somewhere, usually the first values in the file (for example 12 bytes, 4 bytes for each number)
read the rest of the file in three nested FOR loops
Something like:
for (size_t i = 0; i < dim1; ++i)
for (size_t j = 0; j < dim2; ++j)
for (size_t k = 0; k < dim3; ++k)
tab[i][j][k] = read_float_value(inputFile);
In Objective-C you can write the file in a similar way.
Here are some examples to get you started:
Three dimensional arrays of integers in C++
3D array C++ using int [] operator

return value of mxGetPr() -- equivalent looping

I am trying to implement a mexFunction() into "pure" C++ (OpenCV), but the returned value by mxGetPr() is not clear at all for me.
The following code is aimed to be implemented:
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int *D = new int[N*L];
// where N and L are dimensions (cols and rows) of matrix prhs[3]
// prhs[3] is a NxL matrix containing floating point value
for (int i=0; i<N*L; i++)
D[i] = mxGetPr(prhs[3])[i];
}
My question is, what kind of value is given by mxGetPr(prhs[3])[i] and mxGetPr(prhs[4])[i]? And how is it looping through matrix?
I tried to do something like this:
for (int i=0; i<l; i++)
{
for(int j=0; j<n; j++)
{
D[iCounter] = (int)d.at<uchar>(i,j);
iCounter++;
}
}
Looping through d matrix which is the same as input value prhs[3], but apparently it is not correct.
I guess the order/type of the returned value is not the same as in the original mexFunction.
EDIT
Now I have cv::Mat d; instead of prhs[3] and try to do the same as in mexfunction.
int *D = new int[N*L];
int iCounter = 0;
for (int i=0; i<L; i++)
{
for(int j=0; j<N; j++)
{
D[iCounter] = (int)d.at<uchar>(i,j);
iCounter++;
}
}
But here (int)d.at(i,j) returns value of the "d" matrix...where in the roiginal code a pointer was returned by mxGetPr().
mxGetPr returns a pointer of type double so you can access your data using pointer arithmetic. Also, you must remember that the pointer returned to you has the data in column-major order. This means that you must traverse your data row-wise instead of column-wise like in traditional C order.
In column-major order, you access location (i, j) with the following linear index:
j * rows + i
rows is the number of rows in your matrix, with i and j being the row and column you want to access. In row-major or C order, the way you access data is:
i * cols + j
Here cols is the number of columns in your matrix. I'm assuming you want to lay out your data in row-major format rather than column major. Therefore if you want to loop through the data using two for loops, do something like this:
double *ptr = mxGetPr(prhs[3]);
// A L x N matrix - L rows, N columns
for (int i = 0; i < L; i++)
{
for (int j = 0; j < N; j++)
{
D[i * N + j] = (int) ptr[j * L + i];
}
}
Here D is a pointer pointing to integer data. You have to cast the data in order to do this as the pointer to the data from MATLAB is already double. It's nasty but that's what you have to do. You can use D in row-major order so it's compatible with the rest of your code. I'm assuming that you are using MATLAB MEX as way of making pre-written C++ code to be interfaced with MATLAB.

Speeding up access to a array with pointers in C++

I am trying to make a fast image threshold function. Currently what I do is:
void threshold(const cv::Mat &input, cv::Mat &output, uchar threshold) {
int rows = input.rows;
int cols = input.cols;
// cv::Mat for result
output.create(rows, cols, CV_8U);
if(input.isContinuous()) { //we have to make sure that we are dealing with a continues memory chunk
const uchar* p;
for (int r = 0; r < rows; ++r) {
p = input.ptr<uchar>(r);
for (int c = 0; c < cols; ++c) {
if(p[c] >= threshold)
//how to access output faster??
output.at<uchar>(r,c) = 255;
else
output.at<uchar>(r,c) = 0;
}
}
}
}
I know that the at() function is quite slow. How can I set the output faster, or in other words how to relate the pointer which I get from the input to the output?
You are thinking of at as the C++ standard library documents it for a few containers, performing a range check and throwing if out of bounds, however this is not the standard library but OpenCV.
According to the cv::Mat::at documentation:
The template methods return a reference to the specified array element. For the sake of higher performance, the index range checks are only performed in the Debug configuration.
So there's no range check as you may be thinking.
Comparing both cv::Mat::at and cv::Mat::ptr in the source code we can see they are almost identical.
So cv::Mat::ptr<>(row) is as expensive as
return (_Tp*)(data + step.p[0] * y);
While cv::Mat::at<>(row, column) is as expensive as:
return ((_Tp*)(data + step.p[0] * i0))[i1];
You might want to take cv::Mat::ptr directly instead of calling cv::Mat::at every column to avoid further repetition of the data + step.p[0] * i0 operation, doing [i1] by yourself.
So you would do:
/* output.create and stuff */
const uchar* p, o;
for (int r = 0; r < rows; ++r) {
p = input.ptr<uchar>(r);
o = output.ptr<uchar>(r); // <-----
for (int c = 0; c < cols; ++c) {
if(p[c] >= threshold)
o[c] = 255;
else
o[c] = 0;
}
}
As a side note you don't and shouldn't check for cv::Mat::isContinuous here, the gaps are from one row to another, you are taking pointers to a single row, so you don't need to deal with the matrix gaps.

Error: cannot convert 'int (*)[(((sizetype)(((ssizetype)n) + -1)) + 1)]' to 'int (*)[100]' for argument '1' to 'int determ(int (*)[100], int)'|

I have that error but I'm sure I have the same data type and I didn't do anything wrong I suppose. It's for calculating the determinant of a matrix. Someone help. I really can't think of why I have this error :(
#include <iostream>
#include <stdio.h>
#include <cmath>
using namespace std;
double determinant(double matrix[100][100], int order)
{
double det, temp[100][100]; int row, col;
if (order == 1)
return matrix[0][0];
else if (order == 2)
return ((matrix[0][0] * matrix[1][1]) - (matrix[0][1] * matrix[1][0]));
else
{
for (int r = 0; r < order; r++)
{
row = 0;
col = 0;
for (int i = 1; i < order; i++)
{
for (int j = 0; j < order; j++)
{
if (j == r)
continue;
temp[row][col] = matrix[i][j];
col++;
}
row++;
}
det += (matrix[0][r] * pow(-1, r) * determinant(temp, order - 1));
}
return det;
}
}
int main()
{
int n;
cout << "Enter the dimension: ";
cin >> n;
double elem[n][n];
for (int i = 0; i < n; i++)
{
cout << "Enter row " << i << ": ";
for (int j = 0; j < n; j++)
{
cin >> elem[i][j];
}
cout << endl;
}
cout << determinant(elem, n);
return 0;
}
your prototype is
double determinant(double matrix[100][100], int order)
and you call it with
determinant(elem, n);
when
double elem[n][n]; that is a "dynamic" array size so not 100x100
it seam compiler assumes n is 1 at compile time so
obviously double array [1][1] can't be converted to [100][100]
as you wrote it even if your input matrix data is 1x1 you have to store it in 100x100 array.
just declare double elem[100][100];
finally at run time ensure user input n < 100 to avoid a bug
You have three problems.
First, the size of elem is unknown at compile time. You should use elem[100][100] if you really want the variable on the stack and the size of the matrix really is 100x100.
Second, your determinant function creates a 10 thousand element matrix on the stack and it is recursive, which means you'll get a lot of them and likely run out stack space. You should consider using a single temp matrix and reusing this for each recursive step.
Third, since you need the matrix size it to be dynamic, declare it on the heap. Something like:
double* elem = new double[n * n];
Strictly speaking you do not need to do this, but it will not waste as much memory as a 100x100 matrix if you are calculating the determinant of small matrices.
If you use a one dimensional array, you can pass in an array of any size to determinant (the determinant function should also take a one-dimensional array or double* instead of double[100][100]). You will have to calculate the index yourself using matrix[order*j+i].
double elem[n][n]; is illegal in C++. Arrays must have dimensions known at compiletime.
Your bizarre error message is a result of a compiler attempting to support double elem[n][n] as an extension, but not doing a very good job of it.
One way to fix this would be to change your code to be double elem[100][100]; .
To fix it without wasting memory and sticking to Standard C++, you should use std::vector instead of a C-style array. It is simpler to code to use a vector of vectors, although for performance reasons you may want to use a 1-D vector.
Also, you would need to refactor determinant slightly as you don't really want to be allocating new memory each time you do another step of the recursion. The determinant function needs to know what dimension of memory is allocated, as well as what dimension you want to calculate the determinant on.

Array passed by reference in recursive function - last column reinitialized

I have a rather unexpected issue with one of my functions. Let me explain.
I'm writing a calibration algorithm and since I want to do some grid search (non-continuous optimization), I'm creating my own mesh - different combinations of probabilities.
The size of the grid and the grid itself are computed recursively (I know...).
So in order:
Get variables
Compute corresponding size recursively
Allocate memory for the grid
Pass the empty grid by reference and fill it recursively
The problem I have is after step 4 once I try to retrieve this grid. During step 4, I 'print' on the console the results to check them and everything is fine. I computed several grids with several variables and they all match the results I'm expecting. However, as soon as the grid is taken out of the recursive function, the last column is filled with 0 (all the values from before are replace in this column only).
I tried allocating one extra column for the grid in step 3 but this only made the problem worse (-3e303 etc. values). Also I have the error no matter what size I compute it with (very small to very large), so I assume it isn't a memory error (or at least a 'lack of memory' error). Finally the two functions used and their call have been listed below, this has been quickly programmed, so some variables might seem kind of useless - I know. However I'm always open to your comments (plus I'm no expert in C++ - hence this thread).
void size_Grid_Computation(int nVars, int endPoint, int consideredVariable, int * indexes, int &sum, int nChoices)
{
/** Remember to initialize r at 1 !! - we exclude var_0 and var_(m-1) (first and last variables) in this algorithm **/
int endPoint2 = 0;
if (consideredVariable < nVars - 2)
{
for (indexes[consideredVariable] = 0; indexes[consideredVariable] < endPoint; indexes[consideredVariable] ++)
{
endPoint2 = endPoint - indexes[consideredVariable];
size_Grid_Computation(nVars, endPoint2, consideredVariable + 1, indexes, sum, nChoices);
}
}
else
{
for (int i = 0; i < nVars - 2; i++)
{
sum -= indexes[i];
}
sum += nChoices;
return;
}
}
The above function is for the grid size. Below for the grid itself -
void grid_Creation(double* choicesVector, double** varVector, int consideredVariable, int * indexes, int endPoint, int nVars, int &r)
{
if (consideredVariable > nVars-1)
return;
for (indexes[consideredVariable] = 0; indexes[consideredVariable] < endPoint; indexes[consideredVariable]++)
{
if (consideredVariable == nVars - 1)
{
double sum = 0.0;
for (int j = 0; j <= consideredVariable; j++)
{
varVector[r][j] = choicesVector[indexes[j]];
sum += varVector[r][j];
printf("%lf\t", varVector[r][j]);
}
varVector[r][nVars - 1] = 1 - sum;
printf("%lf row %d\n", varVector[r][nVars - 1],r+1);
r += 1;
}
grid_Creation(choicesVector, varVector, consideredVariable + 1, indexes, endPoint - indexes[consideredVariable], nVars, r);
}
}
Finally the call
#include <stdio.h>
#include <stdlib.h>
int main()
{
int nVars = 5;
int gridPrecision = 3;
int sum1 = 0;
int r = 0;
int size = 0;
int * index, * indexes;
index = (int *) calloc(nVars - 1, sizeof(int));
indexes = (int *) calloc(nVars, sizeof(int));
for (index[0] = 0; index[0] < gridPrecision + 1; index[0] ++)
{
size_Grid_Computation(nVars, gridPrecision + 1 - index[0], 1, index, size, gridPrecision + 1);
}
double * Y;
Y = (double *) calloc(gridPrecision + 1, sizeof(double));
for (int i = 0; i <= gridPrecision; i++)
{
Y[i] = (double) i/ (double) gridPrecision;
}
double ** varVector;
varVector = (double **) calloc(size, sizeof(double *));
for (int i = 0; i < size; i++)
{
varVector[i] = (double *) calloc(nVars, sizeof(double *));
}
grid_Creation(Y, varVector, 0, indexes, gridPrecision + 1, nVars - 1, r);
for (int i = 0; i < size; i++)
{
printf("%lf\n", varVector[i][nVars - 1]);
}
}
I left my barbarian 'printf', they help narrow down the problem. Most likely, I have forgotten or butchered one memory allocation. But I can't see which one. Anyway, thanks for the help!
It seems to me that you have a principal mis-design, namely your 2D array. What you are programming here is not a 2D array but an emulation of it. It only makes sense if you want to have a sort of sparse data structure where you may leave out parts. In your case it looks as if it is just a plain old matrix that you need.
Nowadays it is neither appropriate in C nor in C++ to program like this.
In C, since that seems what you are after, inside functions you declare matrices even with dynamic bounds as
double A[n][m];
If you fear that this could smash your "stack", you may allocate it dynamically
double (*B)[m] = malloc(sizeof(double[n][m]));
You pass such beasts to functions by putting the bounds first in the parameter list
void toto(size_t n, size_t m, double X[n][m]) {
...
}
Once you have clean and readable code, you will find your bug much easier.