I'm trying to implement some elementary linear algebra routines in MEX files in C for practice, and I'm stuck with dot products. Here's what I have so far:
#define char16_t UINT16_T //shenanigans with the compiler
#include "mex.h"
void dotProd(double *a, double *b, double z, mwSize n)
{
mwSize i;
for(i=0;i<n;i++){
z+=a[i] * b[i];
}
}
/* The gateway function */
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
double z=0; //Output scalar
double *b, *a; //Input vectors
int n;
a = mxGetPr(prhs[0]); //pointer to a
b = mxGetPr(prhs[1]); //pointer to b
n = mxGetM(prhs[0]);
// Create output
plhs[0] = mxCreateDoubleScalar(z);
dotProd(a,b,z,(mwSize)n);
}
The problem is that when I test this code:
a=rand(2,1);
b=rand(2,1);
z=dotProd(a,b);
I get:
z=0
even though a and b are not orthogonal. I verified this with the MATLAB dot() function. I've picked over the code and can't quite seem to find where I'm going awry. Some suggestions would be appreciated.
Thank you.
That's because you're not returning the result of the dot product. z makes a local copy of itself in your dotProd function. Even though you are making modifications to z, those changes are not reflected because the scope of z inside dotProd is of local scope. You need to update your function that computes the dot product to return something. In addition, you are setting the output of the function before computing the dot product.
As such, do this:
// Change - Remove z as input
double dotProd(double *a, double *b, mwSize n)
{
mwSize i;
double z = 0.0; // Initialize z to 0.0
for(i=0;i<n;i++){
z+=a[i] * b[i];
}
return z; // Return z
}
Then simply do:
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
double z; //Output scalar - Change - don't need to initialize
double *b, *a; //Input vectors
int n;
a = mxGetPr(prhs[0]); //pointer to a
b = mxGetPr(prhs[1]); //pointer to b
n = mxGetM(prhs[0]);
// Create output
z = dotProd(a,b, (mwSize)n); // Change - returning output
plhs[0] = mxCreateDoubleScalar(z);
}
If you insist on changing z in the function and not letting the function return anything, you'll need to pass a pointer to z and change what z refers to. In other words, you would do this:
// Change - Make z point to a double
void dotProd(double *a, double *b, double *z, mwSize n)
{
mwSize i;
for(i=0;i<n;i++){
*z+=a[i] * b[i]; // Change - Refer to pointer
}
}
Now, do:
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
double z = 0.0;
double *b, *a; //Input vectors
int n;
a = mxGetPr(prhs[0]); //pointer to a
b = mxGetPr(prhs[1]); //pointer to b
n = mxGetM(prhs[0]);
// Create output
dotProd(a,b, &z, (mwSize)n); // Change - Pass pointer of z to function
plhs[0] = mxCreateDoubleScalar(z);
}
BTW, you still need to call dotProd before you set the output. That's why you kept getting 0 because z was 0 before you set the output, then you called dotProd after.
Related
I am a beginner for R extensions. I have problems in understanding the usage of .C interface. Take this code as an example:
void cconv(int *l, double *x, int *n, double *s)
{
double *y = x + (*n - *l), *z = x + *l, *u = x;
while ( u < y)
*s += *u++ * *z++;
}
In this code, I think the arguments should be called as *l and *x probably because l and x are defined in R environment and are transferred to the .C interface, and please correct it if I am wrong. However, inside the function cconv, why double *y are defined rather than double y, and why pointer and int variable are mixed in defining *y. At last, I saw in other codes that if R need call .C(...) to return a vector result s, then double *y is defined as an argument in the C function, but calculated as s inside the C function, like:
void xfunc(int *l, double *x, double *s){
int i,j;
for (i = 0, i < *l, i ++){
s[i] = x;
}
}
The code below uses a recursive function called interp, but I cannot find a way to avoid using global variables for iter and fxInterpolated. The full code listing (that performs N-dimensional linear interpolation) compiles straightforwardly with:
gcc NDimensionalInterpolation.c -o NDimensionalInterpolation -Wall -lm
The output for the example given is 2.05. The code works fine but I want to find alternatives for the global variables. Any help with this would be greatly appreciated. Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int linearInterpolation(double *, double **, double *, int);
double ** allocateDoubleMatrix(int, int);
double * allocateDoubleVector(int);
void interp(int, int, double *, double *, double *);
double mult(int, double, double *, double *);
/* The objectionable global
variables that I want to get rid of! */
int iter=0;
double fxInterpolated=0;
int main(int argc, char *argv[]){
double *fx, **a, *x;
int dims=2;
x=allocateDoubleVector(dims);
a=allocateDoubleMatrix(dims,2);
fx=allocateDoubleVector(dims*2);
x[0]=0.25;
x[1]=0.4;
a[0][0]=0;
a[0][1]=1;
a[1][0]=0;
a[1][1]=1;
fx[0]=1;
fx[1]=3;
fx[2]=2;
fx[3]=4;
linearInterpolation(fx, a, x, dims);
printf("%f\n",fxInterpolated);
return (EXIT_SUCCESS);
}
int linearInterpolation(double *fx, double **a, double *x, int dims){
double *b, *pos;
int i;
b=allocateDoubleVector(dims);
pos=allocateDoubleVector(dims);
for (i=0; i<dims;i++)
b[i] = (x[i] - a[i][0]) / (a[i][1] - a[i][0]);
interp(0,dims,pos,fx,b);
return (EXIT_SUCCESS);
}
void interp(int j, int dims, double *pos, double *fx, double *b) {
int i;
if (j == dims){
fxInterpolated+=mult(dims,fx[iter],pos,b);
iter++;
return;
}
for (i = 0; i < 2; i++){
pos[j]=(double)i;
interp(j+1,dims,pos,fx,b);
}
}
double mult(int dims, double fx, double *pos, double *b){
int i;
double val=1.0;
for (i = 0; i < dims; i++){
val *= fabs(1.0-pos[i]-b[i]);
}
val *= fx;
printf("mult val= %f fx=%f\n",val, fx);
return val;
}
double ** allocateDoubleMatrix(int i, int j){
int k;
double ** matrix;
matrix = (double **) calloc(i, sizeof(double *));
for (k=0; k< i; k++)matrix[k] = allocateDoubleVector(j);
return matrix;
}
double * allocateDoubleVector(int i){
double *vector;
vector = (double *) calloc(i,sizeof(double));
return vector;
}
Thanks for the comments so far. I want to avoid the use of static. I have removed the global variable and as suggested tried parsing with the iter variable. But no joy. In addition I am getting a compile warning: "value computed is not used" with reference to *iter++; What am I doing wrong?
void interp(int j, int dims, double *pos, double *fx, double *b, int *iter) {
int i;
if (j == dims){
fxInterpolated+=mult(dims,fx[*iter],pos,b);
*iter++;
return;
}
for (i = 0; i < 2; i++){
pos[j]=(double)i;
interp(j+1,dims,pos,fx,b,iter);
}
}
There are two approaches I would consider when looking at this problem:
Keep the state in a parameter
You could use one or more variables that you pass to the function (as a pointer, if necessary) to keep the state across function calls.
For instance,
int global = 0;
int recursive(int argument) {
// ... recursive stuff
return recursive(new_argument);
}
could become
int recursive(int argument, int *global) {
// ... recursive stuff
return recursive(new_argument, global);
}
or sometimes even
int recursive(int argument, int global) {
// ... recursive stuff
return recursive(new_argument, global);
}
Use static variables
You can also declare a variable in a function to be preserved across function calls by using the static keyword:
int recursive(int argument) {
static int global = 0;
// ... recursive stuff
return recursive(argument);
}
Note that because of the static keyword, global = 0 is only set when the program starts, not every time the function is called, as it would be without the keyword. This means that if you alter the value of global, it would keep this value the next time the function is called.
This method can be used if you only use your recursive function once during your program; if you need to use it multiple times, I recommend that you use the alternative method above.
A solution is to use statics and then to reset the variables on the first call, via a flag that I call initialise. That way you can choose to have the variables reset or not.
double interp(int j, int dims, double *pos, double *fx, double *b, int initialise) {
static double fxInterpolated = 0.0;
static int iter = 0;
int i;
if (initialise){
fxInterpolated = 0.0;
iter = 0;
}
.....
......
}
The function is cyclic.c.
void cyclic(float a[], float b[], float c[], float alpha, float beta,
float r[], float x[], unsigned long n)
// Solves for a vector x[1..n] the “cyclic” set of linear equations. a,
//b, c, and r are input vectors, all dimensioned as [1..n], while alpha and beta are //the corner
// entries in the matrix.
I am new for the interface between Matlab and C. And I have not use C for several years.
Last night, I finished it and compile. The last thing is to call it.
#include "mex.h"
#include "nrutil.h"
#define FREE_ARG char*
#define NR_END 1
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#define NR_END 1
#define FREE_ARG char*
void nrerror(char error_text[])
/* Numerical Recipes standard error handler */
{fprintf(stderr,"Numerical Recipes run-time error...\n");
fprintf(stderr,"%s\n",error_text);
fprintf(stderr,"...now exiting to system...\n");
exit(1);
}
float *vector(long nl, long nh)
/* allocate a float vector with subscript range v[nl..nh] */
{
float *v;
v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float)));
if (!v) nrerror("allocation failure in vector()");
return v-nl+NR_END;
}
void free_vector(float *v, long nl, long nh)
/* free a float vector allocated with vector() */
{
free((FREE_ARG) (v+nl-NR_END));
}
void tridag(float a[], float b[], float c[], float r[], float u[],
unsigned long n)
{
unsigned long j;
float bet,*gam;
gam=vector(1,n);
if (b[1] == 0.0) nrerror("Error 1 in tridag");
u[1]=r[1]/(bet=b[1]);
for (j=2;j<=n;j++) {
gam[j]=c[j-1]/bet;
bet=b[j]-a[j]*gam[j];
if (bet == 0.0) nrerror("Error 2 in tridag");
u[j]=(r[j]-a[j]*u[j-1])/bet;
}
for (j=(n-1);j>=1;j--)
u[j] -= gam[j+1]*u[j+1];
free_vector(gam,1,n);
}
void cyclic(float a[], float b[], float c[], float alpha, float beta,
float r[], float x[], unsigned long n)
{
void tridag(float a[], float b[], float c[], float r[], float u[],
unsigned long n);
unsigned long i;
float fact,gamma,*bb,*u,*z;
if (n <= 2) nrerror("n too small in cyclic");
bb=vector(1,n);
u=vector(1,n);
z=vector(1,n);
gamma = -b[1]; //Avoid subtraction error in forming bb[1].
bb[1]=b[1]-gamma; //Set up the diagonal of the modified tridiagonal
bb[n]=b[n]-alpha*beta/gamma; //system.
for (i=2;i<n;i++) bb[i]=b[i];
tridag(a,bb,c,r,x,n);// Solve A · x = r.
u[1]=gamma;// Set up the vector u.
u[n]=alpha;
for (i=2;i<n;i++) u[i]=0.0;
tridag(a,bb,c,u,z,n);// Solve A · z = u.
fact=(x[1]+beta*x[n]/gamma)/ //Form v · x/(1 + v · z).
(1.0+z[1]+beta*z[n]/gamma);
for (i=1;i<=n;i++) x[i] -= fact*z[i]; //Nowget the solution vector x.
free_vector(z,1,n);
free_vector(u,1,n);
free_vector(bb,1,n);
}
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
float *a,*b,*c,*x,*r;
float alpha,beta;
unsigned long n = (unsigned long) mxGetScalar(prhs[6]);
// a=mxGetPr(prhs[0]);
// b=mxGetPr(prhs[1]);
// c=mxGetPr(prhs[2]);
// r=mxGetPr(prhs[5]);
a = (float*) mxGetData(prhs[0]);
b = (float*) mxGetData(prhs[1]);
c = (float*) mxGetData(prhs[2]);
r = (float*) mxGetData(prhs[5]);
// alpha=*(mxGetPr(prhs[3]));
// beta=*(mxGetPr(prhs[4]));
alpha = (float) mxGetScalar(prhs[3]);
beta = (float) mxGetScalar(prhs[4]);
plhs[0]= mxCreateDoubleMatrix(n, 1, mxREAL);
x = mxGetPr(plhs[0]);
mexPrintf("%f ",alpha);
mexPrintf("\n");
mexPrintf("%f ",beta);
mexPrintf("\n");
mexPrintf("%d ",n);
mexPrintf("\n");
cyclic(a,b,c, alpha, beta,r,x,n) ;
mexPrintf("%d ",n);
mexPrintf("\n");
}
Finally I successfully compile itcyclic(a,b,c, alpha, beta,r,x,n) ;. But the answer is not right. I thing this is because r is an imaginary vector. So my question is how should I transform r between C and Matlab?
The C function cyclic expects arrays of floats, but mexFunction is passing a double*. Without changing cyclic.c, you have two options:
Convert the data to single in MATLAB and get a float* with mxGetData.
In mexFunction:
float *a = (float*) mxGetData(prhs[0]);
In MATLAB:
mexFunction(single(a),...)
Convert (copy, not cast!) the data in mexFunction.
In mexFunction, allocate new float arrays, and copy each element from the double input array (mxGetPr(prhs[0])) into the temporary float array.
Call mexFunction with a normal double array in MATLAB.
It's probably easier to do the former.
Under no circumstances should you simply cast the pointer, not that you were planning to do that.
Also, the scalars alpha, beta and n need to be read from prhs as scalars and passed to cyclic as scalars. In mexFunction, use:
float alpha = (float) mxGetScalar(prhs[...]);
float beta = (float) mxGetScalar(prhs[...]);
unsigned long n = (unsigned long) mxGetScalar(prhs[...]);
You've entirely forgotten c and r in mexFunction.
I am trying to create a 3d grid for my OpenCl/GL fluid. The problem Im having is that for some reason the my grid initialization function does not work properly. Here is my *.h, *.c setup and (at the end) call in main:
(grid.h):
#if RunGPU
#define make_float3(x,y,z) (float3)(x,y,z)
#define make_int3(i,j,k) (int3)(i,j,k)
#else
typedef struct i3{
int i,j,k;
} int3;
typedef struct f3{
float x,y,z;
} float3;
#define __global
#define make_float3(x,y,z) {x , y , z}
#define make_int3(x,y,z) {x , y ,z}
#endif
typedef struct grid3 * grid3_t; // u,v,w
typedef struct grid * grid_t; // p
struct grid3 {
__global float3* values_;
__global float * H_;
__global float * h_;
int dimx_;
int dimy_;
int dimz_;
} ;
struct grid {
__global float * values_;
int dimx_;
int dimy_;
int dimz_;
};
void grid3_init(grid3_t grid,__global float3* vel,__global float* H,__global float *h, int X, int Y, int Z);
(grid.c):
void grid3_init(grid3_t grid,__global float3* val,__global float* H,__global float *h, int X, int Y, int Z){
grid->values_ = val;
grid->H_ = H;
grid->h_ = h;
grid->dimx_ = X;
grid->dimy_ = Y;
grid->dimz_ = Z;
}
In main im initializing my grid like so:
int main(int argc, char** argv)
{
const int size3d = Bx*(By+2)*Bz;
const int size2d = Bx*Bz;
float3 * velocities = (float3*)malloc(size3d*sizeof(float3));
float * H = (float*)malloc(size2d*sizeof(float));
float * h = (float*)malloc(size2d*sizeof(float));
for(int i = 0; i < size3d; i++){
float3 tmp = make_float3(0.f,0.f,0.f);
velocities[i] = tmp;
if(i < size2d){
H[i] = 1;
h[i] = 2;
}
}
grid3_t theGrid;
grid3_init(theGrid, velocities, H, h, Bx, By, Bz); // <- ERROR OCCURS HERE
}
The error im getting is during runtime - "Run-Time Check Failure #3 - The variable 'theGrid' is being used without being initialized". But thats precisely the job of grid3_init?
As im trying to write code to work for both Host and GPU I have to sacrifice the use of classes and work strictly with structs - which I have less experience with.
At this point I dont really know what to google either, I appriciate any help i can get.
struct grid3 theGrid;
grid3_init(&theGrid, velocities, H, h, Bx, By, Bz);
You need to create grid3 instance and pass its pointer to grid3_init. Your existing code just uses uninitialized pointer.
I've been at this for a couple days now, have tried every variation I can think of, and looked at countless examples. I just can't get it working.
I'm trying to make a mexFunction to call from matlab. This mexFunction calls into another C function I have, lets call it retrieveValues, and returns an array and the length of that array. I need to return both of those back to the matlab function, which as I understand it, means I need to put them in the plhs array.
I call my mexFunction from matlab like this:
[foofooArray, foofooCount] = getFoo();
Which to my understanding, means that nlhs = 2, plhs is an array of length 2, nrhs = 0, and prhs just a pointer.
Here's my code for the mexFunction:
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray* prhs[])
{
foo* fooArray
int fooCount
plhs = mxCreateNumericMatrix(1, 2, mxUINT64_CLASS, mxREAL);
//feels like I shouldn't need this
retrieveValues(&fooArray, &fooCount);
plhs[0] = fooArray;
plhs[1] = fooCount;
}
Running the matlab program gets me One or more output arguments not assigned during call
I've tested and confirmed that the values are being returned from retrieveValues correctly.
You are correct that the plhs = mxCreateNumericMatrix(...) is not needed. Also, note that nlhs is the number of left-hand-sides you supply in MATLAB - so in your case, you're calling it with 2 left-hand-sides. Here's how to return trivial scalar values:
plhs[0] = mxCreateDoubleScalar(2);
plhs[1] = mxCreateDoubleScalar(3);
To handle your actual return values, you'll need to do something to copy the values out of foo and into a newly-created mxArray. For example, if your function returned doubles, you might do this:
double * values;
int numValues;
myFcn(&values, &numValues);
/* Build a 1 x numValues real double matrix for return to MATLAB */
plhs[0] = mxCreateDoubleMatrix(1, numValues, mxREAL);
/* Copy from 'values' into the data part of plhs[0] */
memcpy(mxGetPr(plhs[0]), values, numValues * sizeof(double));
EDIT Of course someone somewhere needs to de-allocate values in both my example and yours.
EDIT 2 Complete executable example code:
#include <string.h>
#include "mex.h"
void doStuff(double ** data, int * numData) {
*numData = 7;
*data = (double *) malloc(*numData * sizeof(data));
for (int idx = 0; idx < *numData; ++idx) {
(*data)[idx] = idx;
}
}
void mexFunction( int nlhs, mxArray * plhs[],
int nrhs, const mxArray * prhs[] ) {
double * data;
int numData;
doStuff(&data, &numData);
plhs[0] = mxCreateDoubleMatrix(1, numData, mxREAL);
memcpy(mxGetPr(plhs[0]), data, numData * sizeof(double));
free(data);
plhs[1] = mxCreateDoubleScalar(numData);
}
Here is an example:
testarr.cpp
#include "mex.h"
#include <stdlib.h>
#include <string.h>
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray* prhs[])
{
// validate number of arguments
if (nrhs != 0 || nlhs > 2) {
mexErrMsgTxt("Wrong number of arguments");
}
// create C-array (or you can recieve this array from a function)
int len = 5;
double *arr = (double*) malloc(len*sizeof(double));
for(int i=0; i<len; i++) {
arr[i] = 10.0 * i;
}
// return outputs from MEX-function
plhs[0] = mxCreateDoubleMatrix(1, len, mxREAL);
memcpy(mxGetPr(plhs[0]), arr, len*sizeof(double));
if (nlhs > 1) {
plhs[1] = mxCreateDoubleScalar(len);
}
// dellocate heap space
free(arr);
}
MATLAB:
>> mex -largeArrayDims testarr.cpp
>> [a,n] = testarr
a =
0 10 20 30 40
n =
5