Related
I found a bug in my code and can't figuring out the error. I tried debugging by showing the output of each variable step by step but I can't find my error. Here is what I have and what I want to do:
I have a matrix A:
0000
0101
1010
1111
And I have a matrix B:
10000
21000
30100
41100
20010
21010
40110
41110
30001
41001
30101
41101
40011
41011
40111
41111
The matrix B has 16 rows and 5 coloumns. The matrix A has 4 rows and 4 coloumns. Now I declare a matrix C that has 4 rows and 16 coloumns.
What I want to do is to calculate the inner product of each row from B with a corresponding row from A. With corresponding I mean that the first coloumn of B shoud define the row from A that I want to multiply. So the B matrix has in fact also four-dimensional vectors and the first element corresponds to the row of A. One could say this first coloumn of B is an index for choosing the row of A. Because C++ start counting by zero I substract one for my index. Here is my code:
std::vector< std::vector<int> > C(4, std::vector<int>(16));
std::vector<int> index(4);
std::vector<int> vectorA(4);
std::vector<int> vectorB(4);
for( int y = 0; y < 16; y++)
{
for(int i=0; i<4; ++i){
vectorA[i] = A[ B[y][0]-1 ][i];
}
for( int x = 1; x < 4; x++)
{
vectorB[x -1] = B[y][x];
}
C[ B[y][0] -1][index[ B[y][0] -1] ] = inner_product(vectorA.begin(), vectorA.end(), vectorB.begin(), 0);
index[B[y][0]-1] += 1;
}
This results in my matrix C:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
2 2 3 1 2 1 2 2 3 0 0 0 0 0 0 0
The first two rows are correct but row three and four are false.
The correct solution has to be (maybe except of ordering in row 3 and 4):
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0
4 3 3 2 3 2 3 2 2 0 0 0 0 0 0 0
Where is my problem? Please help, it drives me crazy :( I tried showing each variable by step but can't find why is it false.
Thanks and greetings.
I have to agree with the other comments: Your code is kind of confusing. You should really simplify the access of vectors by index.
First simple thing you should do is to change the first column of B to be zero-based. All stuff in C++ is zero-based. Adopt it. Do not start adjusting it in your code by substracting one. (This does not gain much simplicity, but is is symptomatic for your code.)
Another source of confusion is that you use the first column of B as an index into A. This might be an implication from the problem you'd like to solve, but it makes things unclear: first column of B has a totally different meaning, always code in a way that objects are seperated by their meaning.
For me the most confusing thing is, that I really do not get what you're up to. With inner product you mean dot product, right? You have 2 sets of vectors you want to calculate the dot product of. This should result in a set of scalars, a 1D vector not a 2D matrix. You do some special stuff with this index vector, which makes the result being a 2D matrix. But you haven't explained the purpose/system behind it. Why do you need a vector for index, not just a scalar??
Vector index is the most ugly/complex part of your code. Without having a clue what you are up to, I would still guess that you find out what is going wrong when you start printing out the full vector index on every iteration and check if it is changing the way you expect.
I don't know what's the rationale behind OP choices, so I can't properly comment the design of code provided, but for what I can understand there are some mistakes with the example input too.
Given A and B matrices as presented, the inner product of the lower rows of A with the corresponding in B is always 0:
B[1] { 2, 1, 0, 0, 0 },
row "2" or A[1] is { 0, 1, 0, 1 } <- B[4] { 2, 0, 0, 1, 0 },
B[5] { 2, 1, 0, 1, 0 },
The same for the succesive row. Only if swapped, the expected output can be obtained and so I did in my code.
vectorA and vectorB and the corresponding copy loops aren't really neccessary and probably are the cause of the wrong output:
for( int x = 1; x < 4; x++)
{ // ^^^^^ this should be <= to reach the last element
vectorB[x -1] = B[y][x];
}
My code, with the updated input and the direct use of A and B is:
#include <iostream>
#include <vector>
#include <numeric>
using vec_t = std::vector<int>; // I assume a C++11 compliant compiler
using mat_t = std::vector<vec_t>;
using std::cout;
int main() {
mat_t A{
{ 0, 0, 0, 0 },
{ 1, 0, 1, 0 }, // <-- those lines are swapped
{ 0, 1, 0, 1 }, // <--
{ 1, 1, 1, 1 }
};
mat_t B{
{ 1, 0, 0, 0, 0 },
{ 2, 1, 0, 0, 0 },
{ 3, 0, 1, 0, 0 },
{ 4, 1, 1, 0, 0 },
{ 2, 0, 0, 1, 0 },
{ 2, 1, 0, 1, 0 },
{ 4, 0, 1, 1, 0 },
{ 4, 1, 1, 1, 0 },
{ 3, 0, 0, 0, 1 },
{ 4, 1, 0, 0, 1 },
{ 3, 0, 1, 0, 1 },
{ 4, 1, 1, 0, 1 },
{ 4, 0, 0, 1, 1 },
{ 4, 1, 0, 1, 1 },
{ 4, 0, 1, 1, 1 },
{ 4, 1, 1, 1, 1 }
};
mat_t C(4, vec_t(16));
vec_t pos(4);
for ( int i = 0; i < 16; ++i )
{
int row = B[i][0] - 1;
int col = pos[row];
int prod = std::inner_product( A[row].begin(), A[row].end(),
++(B[i].begin()), 0 );
// ^^^ skip the first element
C[row][col] = prod;
if ( prod )
++pos[row];
}
for ( auto & r : C )
{
for ( int x : r ) {
cout << ' ' << x;
}
cout << '\n';
}
return 0;
}
The output is:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0
2 2 3 2 3 2 3 3 4 0 0 0 0 0 0 0
I don't know if the ordering of the last row is as expected, but it mimics the logic of OP's code.
I have k (0 < k < 8) CSV files containing values all 0 or 1.
My C++ code reads from the file and stores the content of each file into a vector<signed char>.
I wished to merge (concat) then store them in a single vector<signed char>.
File 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Stored in vector1
File 2: 1 1 1 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 Stored in vector2
File 3: 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Stored in vector3
File 4: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Stored in vector4
File 5: 1 1 0 1 1 0 0 0 1 1 1 0 0 0 1 0 0 0 1 0 Stored in vector5
I wished to store them in vector<signed char> vectork:
with vectork[0] stored where each element has bit pattern as [0 0 0 0 1 0 1 1] -- first col
with vectork[1] stored where each element has bit pattern as [0 0 0 0 1 1 0 1] -- second col
with vectork[2] stored where each element has bit pattern as [0 0 0 0 1 0 0 0] -- third col
I tried with
vectork.resize(vector1.size(),0);
for ( int i = 0; i < vector1.size(); i++ ) {
vectork[i] = vectork[i] << 1;
if (vector1[i] == 1) vectork[i] +=1;
vectork[i] << 1;
if (vector2[i] == 1) vectork[i] +=1;
vectork[i] << 1;
if (vector3[i] == 1) vectork[i] +=1;
vectork[i] << 1;
if (vector5[i] == 1) vectork[i] +=1;
}
Is the above correct?
This would be a lot easier done with bitsets, however, if you choose to do it this way, it would look something like this.
I'm still kind of confused as to what exactly you're trying to do, but it seems like you're trying to get all of those vectors into one two dimensional vector (you did as an array of vectors, but I feel as if you intended it like this).
This will get all the vectors, and append them into a new vector of vectors.
// Example program
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<signed char> vector1 = {0,1,0,1,0,1,0,1};
vector<signed char> vector2= {0,0,0,1,0,1,0,1};
vector<signed char> vector3= {0,1,1,1,0,1,0,1};
vector<signed char> vector4= {1,1,0,1,0,1,0,1};
vector<signed char> vector5= {1,0,0,1,0,1,0,1};
vector<vector<signed char>> vectork(5, vector<signed char>(8));
vectork.clear();
vectork.push_back(vector1);
vectork.push_back(vector2);
vectork.push_back(vector3);
vectork.push_back(vector4);
vectork.push_back(vector5);
//to check if it correctly works (it does).
for(vector<signed char> v : vectork) {
for(signed char i : v) {
printf("%d ", i);
}
printf("\n");
}
}
The output would look like this:
0 1 0 1 0 1 0 1
0 0 0 1 0 1 0 1
0 1 1 1 0 1 0 1
1 1 0 1 0 1 0 1
1 0 0 1 0 1 0 1
Let me know if you were trying to do something slightly different and I can tweak it for you, or if you need any explanation on what I wrote, or have any questions in general.
Firstly I would recomend that you use std::vector<bool> instead of std::vector<signed char> This is specifically for performance reasons as your compiler will likely reduce the memory usage by storing 8 Booleans in 1 byte as apposed to storing 1 Boolean in a byte. Secondly I think you have completely misunderstood the process of bit shifting, as far as I am aware from what you have posted you are simply trying to concatenate two STL Vectors this has been asked here. For reference I have included a code snippet from the excellent answer by Robert Gamble. In your
vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
#include <vector>
std::vector<signed char>
merge(const std::vector<signed char>& vector1,
const std::vector<signed char>& vector2,
const std::vector<signed char>& vector3,
const std::vector<signed char>& vector4,
const std::vector<signed char>& vector5)
{
std::vector<signed char> result;
result.reserve(vector1.size());
auto i1 = vector1.begin();
auto i2 = vector2.begin();
auto i3 = vector3.begin();
auto i4 = vector4.begin();
auto i5 = vector5.begin();
while (i1 != vector1.end()) {
int n = 0;
for (auto *v: { &i1, &i2, &i3, &i4, &i5 })
n = n*2 + *(*v)++;
result.push_back(n);
}
return result;
}
// test it:
#include <algorithm>
int main()
{
auto v = merge({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0 });
auto expected = { 0b1011, 0b1101, 0b1000, 0b0001, 0b0001, 0b0000, 0b0000, 0b0000,
0b0001, 0b1001, 0b1001, 0b0000, 0b0000, 0b0000, 0b1001, 0b0000,
0b0000, 0b0000, 0b1001, 0b0000 };
return !std::equal(expected.begin(), expected.end(), v.begin());
}
I am programming a minesweeper game and i have encountered a problem and i can't solve it on my own. I want to change the 0's around the M's to 1 if one M is close to it, a 2 if two mines is close to it and so on. I have written this code:
hiddenfield = [[0, 0, 0, 0, 0, 'M', 0, 0, 0, 'M'],
[0, 0, 0, 'M', 0, 0, 0, 'M', 'M', 'M'],
[0, 0, 'M', 0, 'M', 0, 0, 'M', 0, 'M'],
[0, 0, 0, 0, 'M', 0, 0, 0, 0, 0],
[0, 0, 'M', 0, 'M', 0, 0, 0, 0, 0],
[0, 0, 0, 'M', 0, 'M', 'M', 0, 0, 0],
[0, 0, 0, 'M', 0, 0, 0, 'M', 0, 0],
[0, 0, 0, 'M', 0, 0, 0, 0, 0, 0],
[0, 'M', 'M', 0, 'M', 0, 0, 0, 0, 0],
['M', 0, 0, 'M', 0, 0, 0, 0, 'M', 0]]
for i in range(0,len(hiddenfield)):
for j in range(0,len(hiddenfield)):
try:
if hiddenfield[i][j] == 'M':
hiddenfield[i+1][j] += 1
hiddenfield[i-1][j] += 1
hiddenfield[i][j+1] += 1
hiddenfield[i][j-1] += 1
hiddenfield[i+1][j-1] += 1
hiddenfield[i-1][j+1] += 1
hiddenfield[i+1][j+1] += 1
hiddenfield[i-1][j-1] += 1
except IndexError:
continue
def showMineFieldHidden(hiddenfield):
border = list(range(0,len(hiddenfield)))
row = [' ']+border
i = 0
for rows in [border]+hiddenfield:
print(row[i], end=' ')
i += 1
for lines in rows:
print(lines, end=' ')
print()
but all i get is this:
0 1 2 3 4 5 6 7 8 9
0 0 0 0 1 1 M 1 0 1 M
1 0 0 2 M 2 1 1 M M M
2 0 1 M 2 M 0 0 M 1 M
3 0 1 2 1 M 0 0 1 0 1
4 0 1 M 1 M 1 1 0 0 0
5 0 1 1 M 1 M M 2 1 0
6 0 0 0 M 0 1 2 M 1 0
7 0 1 1 M 1 0 1 1 1 0
8 0 M M 3 M 1 0 0 0 0
9 M 1 1 M 2 1 1 0 M 0
would really appreciate some help.
You have 2 problems:
if there is an index error before the end you skip the rest
you overwrite other mines
for i in range(0, len(hiddenfield)):
for j in range(0, len(hiddenfield)):
if hiddenfield[i][j] == 'M':
if hiddenfield[i + 1][j] != 'M':
try:
hiddenfield[i + 1][j] += 1
except IndexError:
pass
if hiddenfield[i + 1][j] != 'M':
try:
hiddenfield[i - 1][j] += 1
except IndexError:
pass
#and so on ..... :(
This is awful and therefore you should put this into a funtion
def update_cell(x, y):
try:
if hiddenfield[x][y] != 'M':
hiddenfield[x][y] += 1
except IndexError:
pass
for i in range(0, len(hiddenfield)):
for j in range(0, len(hiddenfield)):
if hiddenfield[i][j] == 'M':
update_cell(i - 1, j - 1)
update_cell(i - 1, j)
update_cell(i - 1, j + 1)
update_cell(i, j - 1)
update_cell(i, j + 1)
update_cell(i + 1, j - 1)
update_cell(i + 1, j)
update_cell(i + 1, j + 1)
Now that looks way better :)
I would start by storing the indexes of your bombs in a list. Then I would try using a function to get all neighboring elements given a location.
check out Listing adjacent cells
Then you can update this function to take an additional parameter which would be a function ex increment or decrement to be executed on all adjacent cells found
I have a problem that from a certain number 1 in a 2D matrix with (x, y) coordinates. From this number, it will start spreading out its 4-neighbor which their values will be assigned by (start point + 1)
We start from a coordinate of (3, 3) = 1. Its neighbor's value will be 2. Next step, 4 neighbors of the point having value of 2 will be 3. And so on, until, all 1 numbers in the matrix are infected!
I have resolved this problem by using some loops. However, I'd like to resolve it by another way that is recursion. But I haven't done with it.
Before
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 0 0 0 0 0
0 0 1 1 1 1 1 1 0 0
0 0 1 1 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 1 1 1 0 0 0 0 0
0 0 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
After spreading out
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 3 2 3 0 0 0 0 0
0 0 2 1 2 3 4 5 0 0
0 0 3 2 3 4 0 0 0 0
0 0 0 0 4 5 0 0 0 0
0 0 0 0 5 6 0 0 0 0
0 0 8 7 6 0 0 0 0 0
0 0 9 8 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
Below is my code but I just can spread all 1 numbers with another value but not as I want. So please help me resolve this problem.
#include <iostream>
#define MAX 10
using namespace std;
int data[MAX][MAX] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 1, 1, 1, 1, 0, 0},
{0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 1, 0, 0, 0, 0},
{0, 0, 1, 1, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
};
int mark[MAX][MAX];
void spreading(int x, int y, int v){
if (x < 0 || x == MAX) return;
if (y < 0 || y == MAX) return;
if(data[x][y] == 0 || mark[x][y] != 0)
return;
data[x][y] = v;
mark[x][y] = v;
spreading(x + 1, y, v);
spreading(x, y + 1, v);
spreading(x - 1, y, v);
spreading(x, y - 1, v);
}
void printArr(int a[MAX][MAX]){
for (int i = 0; i < MAX; ++i) {
cout << endl;
for (int j = 0; j < MAX; ++j) {
cout << a[i][j] << " ";
}
}
}
int main(){
spreading(3, 3, 1);
printArr(data);
system("pause");
return 0;
}
Following may solve your issue: (https://ideone.com/VQmBhU)
void spreading(int x, int y, int v){
// Test if x, y is inside the propagation area
if (x < 0 || x == MAX) return;
if (y < 0 || y == MAX) return;
if (data[x][y] == 0) return;
// if already visited with a better path, cancel.
// if not visited, or the previous visit was worst than this try, continue
if (mark[x][y] != 0 && mark[x][y] <= v) return;
data[x][y] = v;
mark[x][y] = v;
spreading(x + 1, y, v + 1);
spreading(x, y + 1, v + 1);
spreading(x - 1, y, v + 1);
spreading(x, y - 1, v + 1);
}
Some example of 're' visit (with the mark array content):
(1) 0 -> 1 (2) -> 1 2 -> 1 2
0 0 0 0 0 (3) (4) 3
1 <= 5, 3 <= 5 : (4) finished
2 <= 4 : (3) finished
1 <= 3 : (2) finished
4 > 2 : we continue propagation from (1)
(1) 2 -> 1 2
4 3 (2) 3
...
I am trying to perform image erosion with OpenCV. I want to do it like this: Suppose I have four different elements
S1 = [ 0 1 0, 0 1 0, 0 1 0 ]
S2 = [ 0 0 0, 1 1 1, 0 0 0 ]
S3 = [ 0 0 1, 0 1 0, 1 0 0 ]
S4 = [ 0 1 0, 1 1 1, 0 1 0 ]
And I want to perform four different erosions with these elements on original image:
E1 = I & S1
E2 = I & S2
E3 = I & S3
E4 = I & S4
where "I" is the original image, and I used "&" to denote erosion for simplicity. Then I want to obtain the final erosion with the addition of these four:
E = E1 + E2 + E3 + E4
But when implementing these with opencv, I've encountered difficulties in early stages. I declared the elements like this:
int S1[3][3] = { { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } };
int S2[3][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 0, 0, 0 } };
int S3[3][3] = { { 0, 0, 1 }, { 0, 1, 0 }, { 1, 0, 0 } };
int S4[3][3] = { { 0, 1, 0 }, { 1, 1, 1 }, { 0, 1, 0 } };
Then for using "cv::erode" I have difficulties with these elements since they are not the acceptable type. How can I use these elements to obtain my desired erosion mentioned above? Thank you in advance.
You'll probably need to create a cv::Mat from your desired kernel shapes, these are known as Structuring elements, and OpenCV provides the getStructuringElement function to create a few common shapes.
Alternatively, you can form your own by creating a new matrix from your data directly using something like:
cv::Mat S1 = (cv::Mat_<uchar>(3,3) << 0, 1, 0, 0, 1, 0, 0, 1, 0);
You can confirm whether this is correct by displaying it in the terminal:
std::cout << S1 << std::endl;
Once you've found your matrices, they can also be easily combined by simple arithmetic operations such as:
cv::Mat E = E1 + E2 + E3 + E4;
Use a Mat-oject as your kernel. InputArray and OutputArray (see the erode docu) can either be Mats or std::vector objects in most cases.
I think you could initialize it like this (not tested):
int S1[3][3] = { { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } };
Mat mat1 = Mat(3, 3, CV_32SC1, S1);