0

I am generating hadamard matrices where for any 2d matrix "M" the next matrix is:

M, M
M,-M

e.g.

Matrix starts with a 1x1 matrix with value "1", such that:

1 (x) 1, 1 = 1, 1
      1,-1   1,-1

1, 1 (x) 1, 1 = 1, 1, 1, 1
1,-1     1,-1   1,-1, 1,-1
                1, 1,-1,-1
                1,-1,-1, 1

And so on... see here

So I have a type:

typedef std::vector<std::vector<char>> matrix_t;

In my constructor I set the matrix to the start value:

hadamard::hadamard() :
    m_matrix{{1}}
{
}

So to make the next matrix I decided I could copy the rows (a repeat copy) and then copy the complete matrix (again a repeat copy):

void hadamard::generate_next(matrix_t& matrix, size_t size)
{
    if (matrix.size() < size)
    {
        hadamard::print_matrix(matrix, "before");

        // Copy the matrix into 4: M1 | M2
        //                         ---+---
        //                         M3 | M4

        // For each inner vector - copy it (double up)
        for(auto& row : matrix)
        {
            // Double up the row
            row.insert(row.end(), row.begin(), row.end());
        }
        // For the outer vector - copy it (double up)
        matrix.insert(matrix.end(), matrix.begin(), matrix.end());

        // Invert chars in M4 (see diagram above)
        TODO

        hadamard::print_matrix(matrix, "after");        

        // Ok, feeling brave, now call recursively...
        generate_next(matrix, size);
    }
}

Just for completeness here is my print function:

static void print_matrix(matrix_t& matrix, const char * title)
{
    printf("%s\r\n", title);
    printf("Dimensions - rows: %d, cols: %d\r\n", matrix.size(), matrix[0].size());

    int row = 1;
    for(auto& line : matrix)
    {
        printf("NEW LINE\r\n");
        int col = 1;
        for (auto& item : line)
        {
            printf("item(%d, %d): %d\r\n", row, col, item);
            ++col;
        }
        ++row;
    }   
}

The output I get is like this:

before
Dimensions - rows: 1, cols: 1
NEW LINE
item(1, 1): 1

after
Dimensions - rows: 2, cols: 2
NEW LINE
item(1, 1): 1
item(1, 2): 1
NEW LINE
<HERE SHOULD BE A COPY OF THE PREVIOUS "LINE">

You can see from the output that the inner copy works ok - I guess this is because I am working on std::vector so the inner data is chars.

But the outer copy does not work, I think this is something this vector being a "vector of vectors" (the full type is std::vector<std::vector<char>>).

So basically the line:

        // For the outer vector - copy it (double up)
        matrix.insert(matrix.end(), matrix.begin(), matrix.end());

does appear to double the size of matrix but it does not copy the data.

Why does it not copy the data? - is it because a deep copy is needed? Also, what is an efficient way to do this?

In the mean time I am going to manually copy the data across from each row... just to prove to myself that I can do it!

UPDATE

Ok, I "think" I have a really simple fix.... may not be the best way?

for(auto& row : matrix)
{
    // Double up the row
    row.insert(row.end(), row.begin(), row.end());
    // Now copy the row down as well
    matrix.insert(matrix.end(), row);
}

But my previous questions still stand!

UPDATE 2

No, the last code change "seemed" to work, at least for the first iteration... but once I start re-cursing through it breaks down... I have updated the "recursion" so it re-curses, I had not written that code properly... now I get the output:

HADAMARD MATRIX GENERATOR
Generating HM for index 2 - dimensions: 4x4, size: 16
before
Dimensions - rows: 1, cols: 1
1 
after
Dimensions - rows: 2, cols: 2
1 1 
1 1 
before
Dimensions - rows: 2, cols: 2
1 1 
1 1 
after
Dimensions - rows: 4, cols: 4
1 1 1 1 
1 1 
1 1 1 1 

before
Dimensions - rows: 4, cols: 4
1 1 1 1 
1 1 
1 1 1 1 

after
Dimensions - rows: 8, cols: 8
1 1 1 1 1 1 1 1 
1 1 
1 1 1 1 

1 1 1 1 1 1 1 1 

So, its not going well at all! - I am thinking the concatenation of my vectors is all wrong?...

code_fodder
  • 15,263
  • 17
  • 90
  • 167
  • 1
    `for(auto& row : matrix)` -- It is undefined behavior to be changing the size of your container in a ranged-based `for` loop. [Possible duplicate](https://stackoverflow.com/questions/17076672/add-elements-to-a-vector-during-range-based-loop-c11) – PaulMcKenzie Dec 14 '17 at 14:28
  • @PaulMcKenzie hmm.. in this case I am only modifying the contents of the vector "row", not the vector "matrix" itself.... is that still undefined? – code_fodder Dec 14 '17 at 14:30
  • `row` is a reference to one of those rows in the matrix. You are adjusting the matrix. – PaulMcKenzie Dec 14 '17 at 14:32
  • 1
    I suggest you rewrite that loop using "traditional" methods, i.e. indices (something like `size_t last = matrix.size(); for (size_t i = 0; i < last; ++i)`, not iterators and not using a range-based `for`. – PaulMcKenzie Dec 14 '17 at 14:38
  • @PaulMcKenzie ok, I can see how there is some duplication, but my question also asks about how to fix this. The other question does not appear to have all the answer I need - so probably not a complete dup.. I assume I need to use a `for(it = vect.begin(); it != vect.end(); it++)` kind of loop to get around this issue? **EDIT** - ah, just saw your last update... – code_fodder Dec 14 '17 at 14:39
  • 1
    Generally, it is better to store multidinemsional arrays as a flat single-dimension - a vector of vectors is a rather inconvenient construct also for compiler optimizations. I'd suggest to create a wrapper class around a single-dim vector of size n*m (n, m, being dimensions of the matrix), with convenience methods to access and add elements and/or rows – Chaosit Dec 14 '17 at 14:43
  • @Chaosit that would probably save me a lot of headache!... I'll do that, but I am first determined to crack it with vect_of_vects, if for no other reason then to learn more - then after for efficiency change to a single dimension : )) – code_fodder Dec 14 '17 at 14:46
  • 1
    As noted by @PaulMcKenzie using iterators doesn't work here. Every time `std::vector` resizes all iterators get invalidated. So somewhere e.g. halfway through your loop `std::vector` will resize due to an insertion, iterators get invalidated and then you do `it++` on an invalid iterator, leading to undefined behavior. Using e.g. `vect.at(3)` side-steps the issue, because it does not require iterators. – AVH Dec 14 '17 at 15:15

0 Answers0