3

I am trying to create a function that basically copy's the matlab command: [z;-z] where z = randn(m,n) which returns an m-by-n matrix of random entries. I was able to create a function in C++ for the randn function which is below:

MatrixXd generateGaussianNoise(int n, int m){
MatrixXd M(n,m);
normal_distribution<double> nd(0.0, 1.0);
random_device rd;
mt19937 gen(rd());
for(int i = 0; i < n; i++){
    for(int j = 0; j < m; j++){
        M(i,j) = nd(gen);
    }
}
return M;

}

Now I need to create the [z;-z] function. For example let's say z = randn(2,2) then the output will be:

   -2.2588    0.3188
    0.8622   -1.3077

Now when I write [z;-z] we get:

   -2.2588    0.3188
    0.8622   -1.3077
    2.2588   -0.3188
   -0.8622    1.3077

What I am thinking is creating a function that taken in the matrix or vector z store those entries in another matrix or vector and then create a new matrix or vector that is doubled in size to place the associated entries in the correct (i,j) positions.

I am not sure if this is how I should proceed. Any comments or suggestions are greatly appreciated. As a side note, I am still a bit of a novice in C++.

3 Answers3

2

You should first initialize your output matrix to the correct size by using the rows and cols in your matrix. You can then use the comma initializer syntax to fill this matrix by vertically concatenating one matrix with the negative of the same matrix

MatrixXd A(n, m);

normal_distribution<double> nd(0.0, 1.0);
random_device rd;
mt19937 gen(rd());

// Fill up the matrix
for(int i = 0; i < n; i++){
    for(int j = 0; j < m; j++){
        A(i, j) = nd(gen);
    }
}

// Vertically concatenate the matrix with the negative version
MatrixXd B(A.rows() * 2, A.cols());
B << A, -A;

return B;
Suever
  • 64,497
  • 14
  • 82
  • 101
  • The code there seems the same as in my answer. It calculates the output directly, without concatenation, so it doesn't fit in your answer. You should use the code from the original post when concatenating it to itself. – anatolyg Jan 24 '17 at 21:01
  • @anatolyg Whoops, forgot to remove that one line. I simply borrowed that to populate the data as a complete example. Updated now – Suever Jan 24 '17 at 21:02
  • I am a little confused with the second part (vertically conatenate the matrix), why are rows doubled and the columns are not? In my example a 2 by 2 matrix becomes a 4 by 4 so it seems that both rows and columns would be doubled –  Jan 24 '17 at 22:17
  • @mweiss1 Ummm go look at your example again, it's 4 x 2. And the syntax `[z; z]` in MATLAB will give you a 4 x 2 as well – Suever Jan 24 '17 at 22:18
  • Doh! Sorry bone head mistake. So, what I am thinking is making a function that takes in the matrix z and then I will apply the vertical concatenate that you mentioned. Does that seem like a decent approach? The reason I am making a new function is because I need the original matrix z later on in the algorithm. –  Jan 24 '17 at 22:25
  • @mweiss1 Yes if you do what's in the last three lines of my code then it will create a new matrix that is simply the concatenation of the values in `z` and `-z` and leave `z` unchanged. – Suever Jan 24 '17 at 22:30
  • Quick slightly unrelated question but lets pretend I want to take the exponential of z using the math.h function exp(z), do I need to create a for loop for the so I take the exponential of each variable in the matrix or can one simply write exp(z)? Seems to me that when I try that my Ecclipse IDE says no matching function for call to 'exp(Eigen::MatrixXd&)' –  Jan 24 '17 at 23:26
  • For some reason I cant make a new question because it says I need to post one question every 90 mins, which it has been. My question is how to use the mod operator with the Eigen libary, I have tried fmod() and % but nothing seems to work... Any ideas? –  Jan 28 '17 at 22:41
  • @Scooby I'm not sure why you can't post a new question. You may try again. But in the meantime, [this post](http://stackoverflow.com/questions/35798698/eigen-matrix-library-coefficient-wise-modulo-operation) may be relevant – Suever Jan 28 '17 at 23:57
  • http://stackoverflow.com/questions/41916430/implement-randu-multiple-recursive-generator-in-c –  Jan 29 '17 at 00:34
0

I think this should be enough?

MatrixXd generateGaussianNoise(int n, int m){
MatrixXd M(2*n,m);
normal_distribution<double> nd(0.0, 1.0);
random_device rd;
mt19937 gen(rd());
for(int i = 0; i < n; i++){
    for(int j = 0; j < m; j++){
        double r = nd(gen);
        M(i,j) = r;
        M(n+i,j) = -r;
    }
}
return M;
xosp7tom
  • 2,131
  • 1
  • 17
  • 26
0

You could use your code that fills a m-by-n matrix, and add another piece of code that "doubles" this matrix into a 2m-by-n matrix.

However, in C++ you are usually supposed to allocate the proper dimensions immediately, and do it only once.

That is:

MatrixXd M(2 * n, m);

(as a side-note, please decide whether your matrix is m-by-n or n-by-m; this is very important to prevent confusion)

Then, while filling your matrix, write two elements at each iteration:

for(int i = 0; i < n; i++){
    for(int j = 0; j < m; j++){
        double element = nd(gen);
        M(i, j) = element;
        M(i + n, j) = -element;
    }
}

If you are going to work with large matrices, you should remember that elements are stored in memory in column-major order (unless you decide to override this choice). This order is also used by Matlab. So, for better performance with large matrices, you should fill them so each column is filled before the other column. So you should switch the nesting order of your loops:

for(int j = 0; j < m; j++){
    for(int i = 0; i < n; i++){
        double element = nd(gen);
        M(i, j) = element;
        M(i + n, j) = -element;
    }
}

Here, two successive iterations will write to neighboring addresses in memory, which will most likely have better performance.

anatolyg
  • 26,506
  • 9
  • 60
  • 134
  • I may be missing what you are trying to say by switching the ordering which starts with 'j' instead of 'i'. Are you saying that for my function that generates the normally distributed random numbers that if I am going to have large matrices then I need to start with 'j' in the first for loop? Apologies for my confusion –  Jan 24 '17 at 21:22
  • Also, why are the columns doubled and not the rows as well? In my example a 2 by 2 matrix becomes a 4 by 4 matrix –  Jan 24 '17 at 22:19