1

I have a vector (1D array) of double values, say X. I need to copy this vector of values into a matrix (2D array), say Y, such that the first row of Y is the same as X transposed, the second row is the same as X shifted one value to the left, the third row of Y is the same as X shifted two values to the left and so on.

For example,

X = { 1.0, 2.0. 3.0, 4.0, 5.0 }

and I need

Y =  1.0  2.0  3.0  4.0  5.0
     2.0  3.0  4.0  5.0  0.0
     3.0  4.0  5.0  0.0  0.0
     4.0  5.0  0.0  0.0  0.0
     5.0  0.0  0.0  0.0  0.0

Some time ago Mathew Finlay posted code for copying 1D array to a 2D array for value types. I have modified the code as follows:

for (int targetRow = 0; targetRow < N; targetRow++)
{
    Buffer.BlockCopy
    (
        X,                                                    // 1D source array
        0,                                                    // source array offset
        Y,                                                    // 2D target (destination) array
        targetRow * Y.GetLength(targetRow) * sizeof(double),  // target array offset
        X.Length * sizeof(double)                             // count
    );
}

I am not sure if this will do the trick and more importantly, whether this is the best way of doing this. This is part of a larger code and this part needs to be fast and efficient as the vector X and the matrix Y can get very large.

Also, to complicate things a bit more, I may sometines not require the full length (all the values) of vector X but only part of it so the matrix Y could be N x M where M <= N. I am not sure how to handle this in the code above.

Thank you in advance for any help or suggestions you may be able to provide.

EDIT: For those interested, here are some performance results.

I ran some speed tests on the two types of code suggested here (looping and Buffer.BlockCopy) and the results surprised me. I will designate the Buffer.BlockCopy as BC and looping as L. For 10x10 matrix BC = 00:00:00.0000017 and L = 00:00:00.0000030. For 100x100 matrix BC = 00:00:00.0000293 and L = 00:00:00.0000710. Finally, for 1000x1000 matrix BC = 00:00:00.0065340 and L = 00:00:00.0138396. So the Buffer.Block copy seems to outperform looping even for small matrices. I ran this on a Win 7 Ultimate (64) machine.

2 Answers 2

1

What about?

       double[] X = new double[]{ 1.0, 2.0, 3.0, 4.0, 5.0 };

        var lbound = X.GetLowerBound(0);
        var ubound = X.GetUpperBound(0);

       double[,] Y = new double[ubound + 1, ubound + 1];

       for (var i = lbound; i <= ubound; i++)
       {
           for (var j = lbound ; j <= ubound ; j++)
           {
               Y[i, j] = (i + j) > ubound ? 0.0 : X[i +j];
           }  
       }

Edit

This works:

 for (int targetRow = 0; targetRow <= ubound; targetRow++)
  {
    Buffer.BlockCopy
    (
        X,                                        // 1D source array
        targetRow * sizeof(double),               // source array offset
        Y,                                        // 2D target (destination) array
        (targetRow * X.Length) * sizeof(double),  // target array offset
        (X.Length - targetRow) * sizeof(double)  // count
    );
}


for (var i = 0; i <= ubound; i++)
{
    for (var j = 0; j <= ubound; j++)
    {
        Console.Write(Y[i, j] + " ");
    }
    Console.WriteLine();
}

Console.ReadKey();

Array Offset


2nd Edit

To deal with your other requirement of changing 2nd dimension of the destination array, you need to change some of the BlockCopy parameters targetArrayOffset and count, you can map them to the dimension of the destination array as below.

        double[] X = new double[] { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 };

        var lbound = X.GetLowerBound(0);
        var ubound = X.GetUpperBound(0);

       double[,] Y = new double[X.Length, 3];

        int yLen = Y.GetUpperBound(1) + 1;

for (int targetRow = 0; targetRow <= ubound; targetRow++)
{
    Buffer.BlockCopy
    (
        X,                                      // 1D source array
        (targetRow * sizeof(double)),             // source array offset
        Y,                                        // 2D target (destination) array
        ((targetRow * yLen) * sizeof(double)),// target array offset
        ((X.Length - targetRow) > yLen ? yLen : (X.Length - targetRow))  * sizeof(double)  // count
    );
}

output:

ScreenPrint

Sign up to request clarification or add additional context in comments.

15 Comments

Thank you for your reply. I am trying to stay away from looping for speed purposes. I thought I could simply adjust the offsets in the Buffer.BlockCopy to get this done efficiently.
@PBrenek I found a way of using Buffer.BlockCopy to achieve what you want. I don't know how practical it is though....
Thank you for your efforts. I really do appreciate it. This is actually quite interesting. Unfortunately, as pointed out by Jeppe Stig Nielsen below, there is a 2GB limit on the size of an array and your approach of using Buffer.BlockCopy would require the array size to be doubled - due to the zero padding. This would effectively reduce the number of values to analyze by half. It appears I may need to use looping rather than Buffer.BlockCopy. Thank you very much anyways.
@PBrenek I updated my answer and figured out how to do it without doubling the array size :-)
This is fantastic! Thank you very much. There is unfortunately one glitch. This method works to create a square matrix. There are times, however, where the matrix is not square. So using your example, I need the 10 rows but only a variable number of columns, less than or equal 10. So imagine that the output is as above but only with say 6 or 7 columns. I will try adjusting the ubound in the for loop.
|
0

Assuming x is of type double[], use:

var y = new double[x.Length, x.Length];
for (int row = 0; row < x.Length; ++row)
{
  for (int col = 0; col < x.Length - row; ++col)
  {
    y[row, col] = x[col - row];
  }
}

or similar.

5 Comments

I will check this out. Thank you. I was under the impression that Buffer.BlockCopy was much faster than looping so I was hoping to use it instead of looping and just adjust the offsets.
@PBrenek Looping is extremely fast. Memory access should be extremely fast as well. How huge are your arrays?
It is hard to say because there is no upper limit and the size is determined by the user but it could easily be 1,000,000 x 1,000,000.
@PBrenek That's one million million entries. Each double is eight bytes. So it would be eight terabytes in total. Sure you have enough memory? (Actually no array can be over two gigabytes in .NET.)
Hmm. I did not think of that. I may need to put in an upper limit. However, the point I was hoping to convey is that the matrices could be large enough for Memory copy to perform significantly better than looping. Thanks for the heads up on the memory size issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.