Home > Enterprise >  Finding all possible occurrences of a matrix in a larger one
Finding all possible occurrences of a matrix in a larger one

Time:12-21

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.

CodePudding user response:

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";
    }
}
  • Related