Interesting algorithm to compare two matrices? - c++

I have a problem, basically, I have two matrices (vectors), one massive matrix and a smaller matrix. I have an algorithm that splits the massive matrix into blocks (of the size of the small block)
So for example (I am using test data here) so the massive matrix size is: 4x4 and the small matrix is 2x2 and then I pass the particular block (at the current position) to a function that checks to see if the small matrix is equal to the massive block (at that particular position) if it is, then returns true otherwise returns false.
I can output each block like this:
bool compareMatrix(vector<double> &theMatrix1, vector<double> &theMatrix2, int startRow, int startCol)
{
// I can output the matrix blocks like this:
cout << theMatrix1[startRow*2+startCol] << endl;
}
But I don't quite understand how I would compare the block (at the startingRow/Col) to the small matrix..
How it would is this:
Matrix 1: (4x4)
0 1 0 1
1 1 0 1
0 0 1 1
0 1 1 1
Matrix 2: (2x2)
0 1
0 1
I then split the blocks into 2x2:
B1 =
0 1
1 1
is B1 equal to theMatrix2 - No so return false
B2 =
0 1
0 1
is B2 equal to theMatrix2 - Yes so return true
I have really tried to explain things to the best of detail as I possibly can and hope someone can give me some advice because I've been working on it for so long now!
Thanks

If the size of the big matrix is known you can compare small parts of it with your 2x2 matrix like so
int bigMatrixSize=4;
bool compare(...)
{
for (int i=0; i<2; ++i)
for (int k=0; k<2; ++k)
if(bigMatrix[k+startX+(i+staryY)*bigMatrixSize] != smallMatrix[k][i])
return false;
return true;
}
I left out bounds checking and some other stuff, but It should give you an idea.

bool compareMatrix(vector<double> &theMatrix1, int nRow1, int nCol1, vector<double> &theMatrix2, int nRow2, int nCol2, int startRow, int startCol)
{
int p1 = startRow * nCol1 + startCol, p2 = 0;
for (int y = 0; y < nRow2; ++y)
{
for (int x = 0; x < nCol2; ++x)
{
if (theMatrix1[p1 + x] != theMattrix2[p2 + x]) // You can use memcmp here, but it's safer let compiler do the optimization.
{
return false;
}
}
p1 += nCol1;
p2 += nCol2;
}
return true;
}
You want something like this? You can add the columns count to the position to reach the next row.

Related

Finding all possible occurrences of a matrix in a larger one

This question is a general algorithmic question, but I am writing it in C++ as it is the language in which I have faced this problem.
Let's say I have the following function:
using Matrix = std::array<std::array<uint8_t, 3>, 3>;
void findOccurrences(std::vector<Matrix>& output, const std::vector<std::vector<uint8_t>>& pattern);
Assuming that pattern is a certain pattern of numbers from 0 to 255, that can fit in a Matrix as I defined above, and given that 0 means an "empty" slot, I want to be able to generate all the possible occurrences of pattern as a Matrix.
For example, given the following pattern:
{
{ 1, 2 },
{ 3, 4 }
}
I want to recive the following vector of matrixes:
1 | 2 | 0
3 | 4 | 0
0 | 0 | 0
0 | 1 | 2
0 | 3 | 4
0 | 0 | 0
0 | 0 | 0
1 | 2 | 0
3 | 4 | 0
0 | 0 | 0
0 | 1 | 2
0 | 3 | 4
The pattern does not have to be a square, but we assume that it is not larger than a Matrix can contain.
I have thought of some approaches for this problem, and ended up with what I think is the most obvious way to do it, but I am having a hard time trying to figure out the logic for the entire thing.
So far what I have is:
void findOccurrences(std::vector<Matrix>& output, const std::vector<std::vector<uint8_t>>& pattern)
{
Pattern curPattern = {0}; //temporary pattern, to store each time the current we work on
const size_t lineOpts = 3 - pattern.size() + 1; //amount of possible line combinations
for (size_t i = 0; i < lineOpts; i++) //for each possible combination
{
for (size_t j = 0; j < pattern.size(); j++) //for each line in pattern
{
const size_t lineInd = j + i; //index of line in curPattern
const auto& line = pattern[j]; //current line in input pattern
const size_t colOpts = 3 - line.size() + 1; //amount of possible column combinations for this line
for (size_t k = 0; k < colOpts; k++) //for each possible column combination
{
for (size_t l = 0; l < line.size(); l++) //for each column in line
{
const size_t colInd = l + k; //index of column in curPattern
//got stuck here
}
}
}
}
}
The problem I'm having here is that I can't think of a way to continue this algorithm without losing possibilities. For example, getting only options 0 and 2 from the example result vector I gave earlier. Plus, this approach seems like it might be a inefficient.
Is this even the right way to go? And if so, what am I missing?
Edit: We also assume that pattern does not contains 0, as it marks an empty slot.
You were already somehow on the right track.
Logically it is clear what has to be done.
We take the upper left edge of the sub pattern. Then we calculate the resulting upper left edges in the target matrix.
The column offset in the resulting matrix, where we will copy the pattern to, will start at 0 and will be incremented up to the size of the matrix - the size of the pattern + 1.
Same with the row offset.
So, in the above case, with a matrix size of 3,3 and a pattern size, the target position in the resulting matrix will be 0,0, 0,1, 1,0 1,1. And then we copy the complete pattern at these positions.
We need to play a little bit with indices, but that is not that complicated.
I have created a well documented example code. If you will read this, then you will immediately understand. Please see below one of many possible solutions:
#include <iostream>
#include <vector>
#include <array>
#include <cstdint>
constexpr size_t MatrixSize = 3u;
using MyType = uint8_t;
using MatrixRow = std::array<MyType, MatrixSize>;
using Matrix = std::array<MatrixRow, MatrixSize>;
using Pattern = std::vector<std::vector<MyType>>;
using MatrixPattern = std::vector<Matrix>;
MatrixPattern findOccurence(const Pattern& pattern) {
// Here we will store the resulting matrixes
MatrixPattern result{};
// Sanity check 1. Do we have data in the pattern at all
if (pattern.empty() or pattern.front().empty()) {
std::cerr << "\n\n*** Error: At least one dimension of input pattern is empty\n\n";
}
// Sanity check 2. Does pattern fit at all into the matrix
else if ((pattern.size() > MatrixSize) or (pattern.front().size() > MatrixSize)) {
std::cerr << "\n\n*** Error: At least one dimension of input pattern is empty\n\n";
}
else {
// Now, we know that we will have a solution
// Check, how many horizontol fits we can theoretically have
// This will be size of sizeof Matrix - sizeof pattern + 1.
const size_t horizontalFits{ MatrixSize - pattern.front().size() + 1 };
// Same for vertical fits
const size_t verticalFits{ MatrixSize - pattern.size() + 1 };
// We now know the horizontal and vertical fits and can resize the
// Resulting vector accordingly.
result.resize(horizontalFits * verticalFits);
size_t indexInResult{ 0 };
// For all possible positions of the patern in the resulting matrix
for (size_t startRowInResultingMatrix{ 0u }; startRowInResultingMatrix < verticalFits; ++startRowInResultingMatrix)
for (size_t startColumnInMatrix{ 0u }; startColumnInMatrix < horizontalFits; ++startColumnInMatrix) {
// Now we have the upper left edge position of the pattern in the matrix
// Copy pattern to that position
for (size_t rowOfPattern{ 0u }; rowOfPattern < pattern.size(); ++rowOfPattern)
for (size_t colOfPattern{ 0u }; colOfPattern < pattern.front().size(); ++colOfPattern)
// Copy. Calculate the correct indices and copy values from sub pattern to matrix
result[indexInResult][startRowInResultingMatrix + rowOfPattern][startColumnInMatrix + colOfPattern] = pattern[rowOfPattern][colOfPattern];
// Next sub matrix
++indexInResult;
}
}
return result;
}
// Driver/Test code
int main() {
// Pattern to insert
Pattern pattern{
{1,2},
{3,4}
};
// Get the result
MatrixPattern matrixPattern = findOccurence(pattern);
// Show output
for (const Matrix& matrix : matrixPattern) {
for (const MatrixRow& matrixRow : matrix) {
for (const MyType& m : matrixRow)
std::cout << (int)m << ' ';
std::cout << '\n';
}
std::cout << "\n\n";
}
}

Construct mirror vector around the centre element in c++

I have a for-loop that is constructing a vector with 101 elements, using (let's call it equation 1) for the first half of the vector, with the centre element using equation 2, and the latter half being a mirror of the first half.
Like so,
double fc = 0.25
const double PI = 3.1415926
// initialise vectors
int M = 50;
int N = 101;
std::vector<double> fltr;
fltr.resize(N);
std::vector<int> mArr;
mArr.resize(N);
// Creating vector mArr of 101 elements, going from -50 to +50
int count;
for(count = 0; count < N; count++)
mArr[count] = count - M;
// using these elements, enter in to equations to form vector 'fltr'
int n;
for(n = 0; n < M+1; n++)
// for elements 0 to 50 --> use equation 1
fltr[n] = (sin((fc*mArr[n])-M))/((mArr[n]-M)*PI);
// for element 51 --> use equation 2
fltr[M] = fc/PI;
This part of the code works fine and does what I expect, but for elements 52 to 101, I would like to mirror around element 51 (the output value using equation)
For a basic example;
1 2 3 4 5 6 0.2 6 5 4 3 2 1
This is what I have so far, but it just outputs 0's as the elements:
for(n = N; n > M; n--){
for(i = 0; n < M+1; i++)
fltr[n] = fltr[i];
}
I feel like there is an easier way to mirror part of a vector but I'm not sure how.
I would expect the values to plot like this:
After you have inserted the middle element, you can get a reverse iterator to the mid point and copy that range back into the vector through std::back_inserter. The vector is named vec in the example.
auto rbeg = vec.rbegin(), rend = vec.rend();
++rbeg;
copy(rbeg, rend, back_inserter(vec));
Lets look at your code:
for(n = N; n > M; n--)
for(i = 0; n < M+1; i++)
fltr[n] = fltr[i];
And lets make things shorter, N = 5, M = 3,
array is 1 2 3 0 0 and should become 1 2 3 2 1
We start your first outer loop with n = 3, pointing us to the first zero. Then, in the inner loop, we set i to 0 and call fltr[3] = fltr[0], leaving us with the array as
1 2 3 1 0
We could now continue, but it should be obvious that this first assignment was useless.
With this I want to give you a simple way how to go through your code and see what it actually does. You clearly had something different in mind. What should be clear is that we do need to assign every part of the second half once.
What your code does is for each value of n to change the value of fltr[n] M times, ending with setting it to fltr[M] in any case, regardless of what value n has. The result should be that all values in the second half of the array are now the same as the center, in my example it ends with
1 2 3 3 3
Note that there is also a direct error: starting with n = N and then accessing fltr[n]. N is out of bounds for an arry of size N.
To give you a very simple working solution:
for(int i=0; i<M; i++)
{
fltr[N-i-1] = fltr[i];
}
N-i-1 is the mirrored address of i (i = 0 -> N-i-1 = 101-0-1 = 100, last valid address in an array with 101 entries).
Now, I saw several guys answering with a more elaborate code, but I thought that as a beginner, it might be beneficial for you to do this in a very simple manner.
Other than that, as #Pzc already said in the comments, you could do this assignment in the loop where the data is generated.
Another thing, with your code
for(n = 0; n < M+1; n++)
// for elements 0 to 50 --> use equation 1
fltr[n] = (sin((fc*mArr[n])-M))/((mArr[n]-M)*PI);
// for element 51 --> use equation 2
fltr[M] = fc/PI;
I have two issues:
First, the indentation makes it look like fltr[M]=.. would be in the loop. Don't do that, not even if this should have been a mistake when you wrote the question and is not like this in the code. This will lead to errors in the future. Indentation is important. Using the auto-indentation of your IDE is an easy way to go. And try to use brackets, even if it is only one command.
Second, n < M+1 as a condition includes the center. The center is located at adress 50, and 50 < 50+1. You haven't seen any problem as after the loop you overwrite it, but in a different situation, this can easily produce errors.
There are other small things I'd change, and I recommend that, when your code works, you post it on CodeReview.
Let's use std::iota, std::transform, and std::copy instead of raw loops:
const double fc = 0.25;
constexpr double PI = 3.1415926;
const std::size_t M = 50;
const std::size_t N = 2 * M + 1;
std::vector<double> mArr(M);
std::iota(mArr.rbegin(), mArr.rend(), 1.); // = [M, M - 1, ..., 1]
const auto fn = [=](double m) { return std::sin((fc * m) + M) / ((m + M) * PI); };
std::vector<double> fltr(N);
std::transform(mArr.begin(), mArr.end(), fltr.begin(), fn);
fltr[M] = fc / PI;
std::copy(fltr.begin(), fltr.begin() + M, fltr.rbegin());

Matrix vector multiplication CCS c++

I am trying to multiply a matrix and a vector with the matrix in Compressed Column Storage. The matrix is :
0 3 0
4 0 0
2 0 0
here is the CCS form:
[ 4 2 3 ]
[ 2 3 1 ]
[ 1 3 4 4 ]
The vector is:
[ 1 3 4 ]
So the product should be
[ 9 4 2 ]
Here is the function I am trying to create
vector<int> multiply(vector<int> val,vector<int> col,vector<int> row,vector<int> v, int r){
vector<int> x(v.size());
for (int j=0; j<r; j++) {
for (int i=col[j]-1; i<col[j+1]-1; i++) {
cout<<"\n"<<val[i]<<"*"<<v[j]<<"\n";
x[j]+= val[i]*v[j];
}
}
return x;
}
But this returns
[ 6 9 0 ]
This is the closest I've gotten to the real solution, how can I fix this?
I would think about this as driven by the col_ptr vector.
1.) I wasn't sure what value(s) r could take, so I removed it, as we don't need that information to solve the problem
2.) I should note that I have not compiled this, but I believe the algorithm is correct
3.) There are some obvious ways to optimize the memory usage of this code, but I left those variables in to help explain the process.
4.) The main problem with the code you posted is that it doesn't seem to use the row array to tell us which row the value is in!
vector<int> multiply(vector<int> val,vector<int> col,vector<int> row,vector<int> v) {
vector<int> x(v.size());
//we may need to initialize x as all zeroes, I forget
int col_size = col.size();
int column_idx = 0;
for (int j=0; j<col_size-1; j++) {
//j indicates where the columns start going!
//columns end prior to the next column start
//val_index is where we need to start in the val array, for this column
int val_index_start = col[j]-1; //this is redunda
//we keep traversing forward until the next column starts
int next_column_start = col[j+1]-1;
for (int k=val_index_start; k < next_column_start && k < v.size(); k++) {
int row_of_cell = row[k] - 1;
int column_of_cell = column_idx;
int product = v[column_idx]*val[k];
x[row_of_cell] += product;
}
column_idx++;
}
return x;
}

How would one see if an array has consecutive numbers in C++?

This is basically the 8 Queens problem, but solving it with brute force in a 1D array. Say I have an array (named b) of size 8, with elements ranging from 0 to 7.
I initialize each index in the array with 8 for-loops, like this:
int b[8]={0};
int count = 0;
for(b[0] = 0; b[0]<8; b[0]++){
for(b[1] = 0; b[1]<8; b[1]++){
for(b[2] = 0; b[2]<8; b[2]++){
for(b[3] = 0; b[3]<8; b[3]++){
for(b[4] = 0; b[4]<8; b[4]++){
for(b[5] = 0; b[5]<8; b[5]++){
for(b[6] = 0; b[6]<8; b[6]++){
for(b[7] = 0; b[7]<8; b[7]++){
if(check(b))
{
count++;
print(b, count);
}
}}
}}
}}
}}
What this program is supposed to do is check every combination of numbers 0 to 7 and returning true for only certain conditions. There are supposed to be 92 solutions, if this sounds familiar, it should be - it is the 8 Queens problem using brute force. From here, this is what I understand are the conditions:
I want to be able to check if an array has a consecutive string of numbers; such as:
[0|5|7|1|2|3|6|4]
Here, the elements b[3], b[4] and b[5] are consecutive. I don't want that, I want to return false, since there is a consecutive string of numbers (basically queens are attacking)
I also do not want an array that has a string of backwards consecutive numbers like this:
[0|5|7|3|2|1|6|4]
And lastly, I do not want two or more numbers in indexes where it would make them look consecutive if we had simply changed then numbers between them:
[0|2|4|6|1|3|5|7]
Above is not acceptable because b[0] and b[7] are numbers in their "consecutive index" (because at least 2 queens are attacking each other).
[6|1|3|0|4|7|5|2]
Above is also not acceptable because b[1] and b[4] are also in consecutive indexes.
Similarly, when the values are swapped, the arrays
[7|2|4|6|1|3|5|0]
[6|4|3|0|1|7|5|2]
are also not acceptable. I also cannot have 2 or more of the same number.
The problem I am having is in creating the check function. I am told I need to use 1 for loop and 1 if-then statement. Can the check function just take the whole array as is? And if it does, how do look at the right-most element in the array, and check to see if it has consecutive indexes (queens are attacking it)? I've tried this:
bool ok(int board[8]){
for(int c = 7; c >= 0; c--){ //row check
for (int j=0; j<c; j++){
if (board[c]==board[j]){
return false;
}
}
for(int i = 1; i <= c; i++){
// diagonal check from top left to bottom right
if ((board[c]-i >= 0) && (board[c-i] == board[c]-i))
{return false;}
if ((board[c]+i <= 7) && (board[c+i] == board[c]+i))
{return false;}
// diagonal check from bottom left to top right
if ((board[c]-i >= 0) && (board[c-i] == board[c]+i))
{return false;}
if ((board[c]+i <= 7) && (board[c+i] == board[c]-i))
{return false;}
}
}
return true;
}
But not only does this not work (I get 300+ solutions), it is not as small as I am told it should be.
I think there is a little problem with your check of collisions in the diagonals: you've got 15 diagonals going each way (including the very short one-square diagonals in the corners), while your code checks only seven of each due to the board[c]+i <= 7 and board[c]-i >= 0 conditions.
Here is how you can simplify the checks and make them faster with the use of three boolean arrays: you've got 8 rows, 15 ascending diagonals, and 15 descending diagonals:
bool row[8];
bool ascending[15];
bool descending[15];
Initially, there are no queens in any of these rows/diagonals. As you go through the elements of board, do this:
for (int i = 0 ; i != 8 ; i++) {
// Check and mark the row
if (row[board[i]]) return false;
row[board[i]] = true;
// Check and mark the ascending diagonal
int ascIdx = board[i]+i;
if (ascending[ascIdx]) return false;
ascending[ascIdx] = true;
int descIdx = 7+board[i]-i;
if (descending[descIdx]) return false;
descending[descIdx] = true;
}
return true;

Splitting a massive matrix into blocks

I have a problem. I'm working on a task that tries to find a matrix (vector) inside another matrix(vector) and the size of the matrices are:
Massive Matrix: 1024x768
Small Matrix: 36x49
Basically, my theory was to split the massive matrix into blocks that were the size of the small matrix thus meaning I was able to just see whether the small matrix exists in which block and then output the block. However, it just will not split equally but I need a way to determine if the small matrix does actually exist in the massive matrix.
As an example, I'll use test data:
M1 =
0 1 0 0
1 1 1 1
0 0 0 0
1 0 1 1
M2 =
0 1
1 1
And then I would split the matrices into blocks of 2x2 and then check that way. This is simple as I'm only working with a small matrix AND the matrix can be split equally, whereas the problem above is a lot more complex to understand and figure out.
In essence, I need to be able to split the (1024x768) into block sizes of (36x49) so then I can do the check to determine where that particular matrix is. I have been working with this algorithm:
// Assume:
// matrix1ColSize = 768
// matrix2ColSize = 49
const int ROW_BOUNDS = matrix1.size() - matrix2.size();
const int COL_BOUNDS = matrix1ColSize - matrix2ColSize;
bool found = false;
for(int i=0; (i < ROW_BOUNDS); i++)
{
bool matchFound = false;
for(int j=0; (j < COL_BOUNDS); j++) {
// logic here
}
cout << endl;
}
Could anyone offer any advice please? This is really annoying me now :(!
Two matrices are the same if all their elements are the same. So the following pseudo-code compares the small matrix with a block in the large matrix:
Initialize result to "true"
For each position in the small matrix
Read the value from the large matrix; call it x1
Read the value from the small matrix; call it x2
If x1 is not equal to x2, set result to "false"
(Optional) If x1 is not equal to x2, stop looking at other positions
Here, use the result
This logic is going to be inside your 2 nested loops, so you will have 4 nested loops there! If you fear of getting confused, put the implementation inside a function. If you want to use 4 nested loops, good luck.
In c++:
bool is_equal = true;
for (int y = 0; y < 49; ++y)
{
for (int x = 0; x < 36; ++x)
{
if (matrix1.at(j + x, i + y) != matrix2.at(x, y))
{
is_equal = false;
goto DONE; // optional
}
}
}
DONE:;
Edit: this code assumes using a custom class for matrices; after looking again at your code i realize that you probably use a vector of vectors (std::vector<std::vector<int>>), so use matrix2[y][x] instead of matrix2.at(x, y).