I have correlation matrix of a data and i want to use pca to transform them to uncorrelated set.
so i've decided to use matlab engine(c++ mex API) to perform the pca
my question is how to copy the matrix contents to mxArray efficiently
i used loops to allocate each element of matrix...on the other hand i've looked up for memcpy and it seems error prone.
although i've tested the following and it just copies the first column!
memcpy((double *)mxGetPr(T), &rho_mat[0][0], rows * sizeof(double));
what is the best way to copy the data (matrix -> mxArray and mxArray -> matrix) ?
void pca(vector<vector<double>>& rho_mat)
{
Engine *ep;
mxArray *T = NULL, *result = NULL;
if (!(ep = engOpen(""))) {
fprintf(stderr, "\nCan't start MATLAB engine\n");
return;
}
size_t rows = rho_mat.size();
size_t cols = rho_mat[0].size();
T = mxCreateDoubleMatrix(rows, cols, mxREAL);
double * buf = (double *)mxGetPr(T);
for (int i = 0; i<rows; i++) {
for (int j = 0; j<cols; j++) {
buf[i*(cols)+j] = rho_mat[i][j];
}
}
engPutVariable(ep, "T", T);
engEvalString(ep, "PC = pcacov(T);");
result = engGetVariable(ep, "PC");
}
Thanks
Regards
You can try using std::memcpy in a loop for each row.
for (int i = 0; i<rows; i++)
{
std::memcpy(buf + i*cols, &rho_mat[i][0], cols * sizeof(double));
}
Please note you have to use cols in you memcpy to ensure each row is copied. In your example, it might have been coincidental if your matrix was square.
You can refer to this answer on how to copy a 1-d vector using memcpy.
Edit:
To copy from 2-D array to 2-D vector(assuming vector is already of size rows*cols)
for (int i = 0; i<rows; i++)
{
std::memcpy(&rho_mat[i][0], buf + i*cols, cols * sizeof(double));
}
Please note the assumption made
OR
A much cleaner way would be to use std::assign or constructor to std::vector
if(rho_mat.size() == 0)
{
for (int i = 0; i<rows; i++)
{
rho_mat.push_back(vector<int>(buf + i*cols, buf + i*cols + cols));
//OR
//rho_mat.push_back(vector<int>());
//rho_mat[i].assign(buf + i*cols, buf + i*cols + cols);
}
}
Related
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.
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.
If I define an array as follows:
int rows = 10;
int cols = 10;
double **mat;
mat = new double*[rows];
mat[0] = new double[rows*cols];
for(int r=1; r<10; r++)
mat[r] = &(mat[0][r*cols]);
How do I iterate over this array via 1-dimension?
E.g. I'd like to do the following:
mat[10] = 1;
to achieve the same thing as
mat[1][0] = 1;
Is there a way to dereference the double** array to do this?
With your definition of mat, you can do this:
double* v = mat[0]; 'use v a uni-dimensional vector
for(int i =0; i< rows* cols; i++) v[i] = 1;
Alternatively,if what you wanted was to define mat itself as a uni-dimensional vector and use it as bi-dimensional in a tricky way:
double mat[rows * cols];
#define MAT(i, j) mat[i*cols + j]
MAT(1, 0) = 1;
<=>
mat[10] = 1
now you have the options to span the matrix in one-dimension using mat or bi-dimension using the MAT macro
mat[row * cols + column]
where row is the row you want to access and column is the column you want to access.
Of course an iteration over the array would just involve some kind of loop (best suited would be for) and just applying the pattern every time.
How to make a 2d pointer like **check point a 2d array like
mycheck[][]?
How to convert a 1d like check[16], to 2d array like mycheck[4][4]?
My attempt
float (*mycheck)[4] = (float (*)[4]) check;
But if second time I want to use mycheck again for some other 1d array, how can I do? My attempt:
float (*mycheck)[4] = (float (*)[4]) other1darray;
this will definitely give a re-declaration error.
The answer to the first question is that you cannot do that. All you can do is allocate some memory and copy the data over.
The answer to the second question is very simple
mycheck = (float (*)[4]) other1darray;
You only have to declare variables once, after that just use the variable name.
Array a[] decays to a pointer to the first element when you drop the []. This does not happen recursively, in other words, it doesn't work for a[][].
Secondly, you can't assign arrays in C. You can ONLY initialize them. You will have to set each member yourself.
You can create a 2D array in C like this.
Use a typedef to make it easier.
typedef int **matrix;
matrix create2Darray(int row, int col)
{
int idx;
matrix m = malloc(row * sizeof(int*));
for (idx = 0; idx < row; ++idx)
{
m[idx] = malloc(col * sizeof(int));
}
return m;
}
And then call this in another function;
matrix check = create2Darray(2, 2);
To assign a 1D array to a 2D array you can assign the pointers to the right position in the array. An example below. It also show how to create a 2D array dynamically, but I commented it out, since it is not needed for the example.
#include <stdio.h>
#include <stdlib.h>
int main()
{
float **matrix;
float *array;
array = (float *) malloc(16 * sizeof(float));
for (size_t idx = 0; idx != 16; ++idx)
{
array[idx] = idx;
}
matrix = (float **) malloc(4 * sizeof(float *));
for (size_t idx = 0; idx != 4; ++idx)
{
// matrix[idx] = malloc(4 * sizeof(int));
matrix[idx] = &array[idx * 4];
}
for (size_t row = 0; row != 4; ++row)
{
for (size_t col = 0; col != 4; ++col)
{
printf("%.1f ", matrix[row][col]);
}
printf("\n");
}
}
Note: this makes the 1D array and 2D array point to the same memory. If you change something in the 1D it also changes in the 2D and vice-versa. If you don't want this, first copy the array.
Is there a possibility to copy data strided by a constant (or even non-constant) value to and from the CUDA device efficiently?
I want to diagonalize a large symmetric matrix.
Using the jacobi algorithm there is a bunch of operations using two rows and two columns within each iteration.
Since the Matrix itself is too big to be copied to the device entirely i am looking for a way to copy the two rows and columns to the device.
It would be nice to use the triangular matrix form to store the data but additional downsides like
non-constant row-length [not that Kind of a Problem]
non-constant stride of the column values [the stride increases by 1 for each row.]
arise.
[edit: Even using triangular form it is still impossible to store the whole Matrix on the GPU.]
I looked at some timings and recognized that copying strided values one by one is very slow (synchronous as well as async.).
// edit: removed solution - added an answer
Thanks to Robert Crovella for giving the right hint to use cudamemcpy2d.
I'll append my test code to give everyone the possibility to comprehend...
If anyone Comes up with suggestions for solving the copy problem using row-major-ordered triangular matrices - feel free to write another answer please.
__global__ void setValues (double *arr, double value)
{
arr[blockIdx.x] = value;
}
int main( void )
{
// define consts
static size_t const R = 10, C = 10, RC = R*C;
// create matrices and initialize
double * matrix = (double*) malloc(RC*sizeof(double)),
*final_matrix = (double*) malloc(RC*sizeof(double));
for (size_t i=0; i<RC; ++i) matrix[i] = rand()%R+10;
memcpy(final_matrix, matrix, RC*sizeof(double));
// create vectors on the device
double *dev_col, *dev_row,
*h_row = (double*) malloc(C*sizeof(double)),
*h_col = (double*) malloc(R*sizeof(double));
cudaMalloc((void**)&dev_row, C * sizeof(double));
cudaMalloc((void**)&dev_col, R * sizeof(double));
// choose row / col to copy
size_t selected_row = 7, selected_col = 3;
// since we are in row-major order we can copy the row at once
cudaMemcpy(dev_row, &matrix[selected_row*C],
C * sizeof(double), cudaMemcpyHostToDevice);
// the colum needs to be copied using cudaMemcpy2D
// with Columnsize*sizeof(type) as source pitch
cudaMemcpy2D(dev_col, sizeof(double), &matrix[selected_col],
C*sizeof(double), sizeof(double), R, cudaMemcpyHostToDevice);
// copy back to host to check whether we got the right column and row
cudaMemcpy(h_row, dev_row, C * sizeof(double), cudaMemcpyDeviceToHost);
cudaMemcpy(h_col, dev_col, R * sizeof(double), cudaMemcpyDeviceToHost);
// change values to evaluate backcopy
setValues<<<R, 1>>>(dev_col, 88.0); // column should be 88
setValues<<<C, 1>>>(dev_row, 99.0); // row should be 99
// backcopy
cudaMemcpy(&final_matrix[selected_row*C], dev_row,
C * sizeof(double), cudaMemcpyDeviceToHost);
cudaMemcpy2D(&final_matrix[selected_col], C*sizeof(double), dev_col,
sizeof(double), sizeof(double), R, cudaMemcpyDeviceToHost);
cudaDeviceSynchronize();
// output for checking functionality
printf("Initial Matrix:\n");
for (size_t i=0; i<R; ++i)
{
for (size_t j=0; j<C; ++j) printf(" %lf", matrix[i*C+j]);
printf("\n");
}
printf("\nRow %u values: ", selected_row);
for (size_t i=0; i<C; ++i) printf(" %lf", h_row[i]);
printf("\nCol %u values: ", selected_col);
for (size_t i=0; i<R; ++i) printf(" %lf", h_col[i]);
printf("\n\n");
printf("Final Matrix:\n");
for (size_t i=0; i<R; ++i)
{
for (size_t j=0; j<C; ++j) printf(" %lf", final_matrix[i*C+j]);
printf("\n");
}
cudaFree(dev_col);
cudaFree(dev_row);
free(matrix);
free(final_matrix);
free(h_row);
free(h_col);
cudaDeviceReset();
return 0;
}