I want to find a way to obtain a submatrix from an initial bigger squared matrix in c , more specifically , the bottom right submatrix . Then i want the for cycle to give me all the submatrix that i can obtain from the original squared matrix.
I found some code online :
int initial_matrix[3][3]
int submatrix[2][2];
for( int i = 0; i < R - r + 1; i++){
for(int j = 0; j < C - c + 1; j++){
submatrix[i][j]=initial_matrix[i][j]
}
}
where :
R is the number of rows of the initial matrix (so in this case R=3)
C is the number of columns of the initial matrix (so in this case C=3)
r is the number of rows of the submatrix that i want to obtain (so in this case r=2)
c is the number of columns of the submatrix that i want to obtain (so in this case c=2)
But this cycle only gives me the upper left submatrix , while I want the bottom right and then expand it so that it gives me all the possible submatrix of the initial matrix.
At first your indices in the loops are not correct! You want to fill in your target matrix rows from indices 0 to r and columns from indices 0 to c so your loops need to look like:
for(size_t i = 0; i < r; ++i)
{
for(size_t j = 0; j < c; ++j)
{
// ...
}
}
From here on you now can simply assign your target matrix at indices i and j:
submatrix[i][j] = ...;
Problem is that these are not the same indices as in your source matrix (unless you want to use the top-left corner submatrix), so you need to translate the indices to the appropriate positions within the source matrix. Luckily, this is not difficult; if the top-left corner of the submatrix within the source matrix is at row r0 and column c0 then you simply need to add these to the corresponding loop indices, thus you get:
... = initial_matrix[r0 + i][c0 + j];
In your case this would mean e.g. [1 + i][1 + j] to get the bottom-right submatrix with both i and j counting up from 0 to excluded 2 (i.e. counting 0 and 1).
Related
I have a 2D matrix A[row][col]. Let say it consists only boolean values.
I want to iterate through every element. For each iteration, it will scan the 8 surrounding elements of that element, and count the number of True values. Let just ignore the counter process.
// scanning element A[i][j]
counter = countHowManyTrue(A[i+1][j], A[i-1][j], A[i][j+1], A[i][j-1]... and so on)
Except the first row, the last row, the first column, and the last column, every other elements have 8 surrounding elements. So I have to write if-else statement to check, like this:
for (i = 0; i < m; i++){
for(j = 0; j < n; j++){
if(i == 0 && j == 0){ // first row, first col
// do sth
}
if(i == m && j == 0){
//do sth
}
}
}
and I have to repeat the if-else statement many times to check the edge cases, which is very time-consuming.
Is there a better way to do this?
One of the simplest ways to do this is to add a sentinel rows and columns: row of all zeros above and below the real data. Then you don't need to special-case it.
As other have mentioned you can pad matrix with a border of zeroes so there's no edge cases:
If space is not an issue there's another speedup, instead of looking 8 neighbors for each cell we can actually get sum of neighbors values in fewer operation with some pre-calculation.
Let's in each matrix cell (after adding 0 borders) keep sum of elements from corner 0,0
It's simple to do:
//lets assume matrix was of size n*m before padding with border of zeroes twice
for(int i=2; i<=n+2; i++)
for(int j=2; j<=m+2; j++)
matrix[i][j] += matrix[i-1][j] + matrix[i][j-1] - matrix[i-1][j-1]
Now getting some cells neighbors is just some math, let's say we want neighbors of some cell x,y we can get it by matrix[x+1][y+1] - matrix[x-2][y] - matrix[x][y-2] + matrix[x-2][y-2] - matrix[x][y]
Now it takes only 7 additions/subtractions per cell compared to 8 originally
I'm having trouble figuring out a way to make this algorithm work, as I can't figure out how to do the middle part of the problem. Here's my code so far:
int det(int matrixSize, int matrix[][matrixSize]){
int determinant = 0, matrixValues[matrixSize * matrixSize], matrixFirstRowValues[matrixSize * matrixSize];
for(int i = matrixSize; i > 2; i--){
for(int row = 0; row < matrixSize; row++){
for(int col = 0; col < matrixSize; col++){
matrixFirstRowValues[row + (matrixSize - i)] = matrix[1][col + (matrixSize - i)];
//copies the first row values for an array until we have a 2x2 matrix
}
}
}
//multiply the values in matrix Values by their respective matrix without
//the row and column of these values times -1^row+col
determinant += (matrix[matrixSize-1][matrixSize-1] * matrix[matrixSize-2][matrixSize-2])
- (matrix[matrixSize-1][matrixSize-2] * matrix[matrixSize-2][matrixSize-1]);
return determinant;
}
Being the matrix, a 2-dimensional array with the size of matrixSize, I iterate through it until I'm left with a 2x2 matrix, copying each value of the first row to a new array.
Those values have to be multiplied by the matrix that it's left when I remove the row and column where that value is.
This is the principle of the laplace expansion. The part that's giving me trouble is getting those matrices that are left by removing rows and columns, as I want this to work for a nxn matrix.
Then, in the end the sum that to the det of a 2x2 matrix.
How can I do the middle part (where the comments are) with my current setup?
Those values have to be multiplied by the matrix that it's left when I
remove the row and column where that value is.
You have to multiply with the cofactor matrix whose entries are the determinants of the matrices that are left over when removing the i-th row and j-th column.
Naturally, this is the setup for a recursive algorithm, since the determinant of the bigger matrix is expressed in terms of the determinants of smaller matrices: if A = (a_{ij}) is the matrix, then det(A) = sum j = 1..n: a_{ij} * det(M_{ij}), where M_{ij} is the minor matrix that arises from A when removing the i-th row and j-th column where i is fixed. The base case being the 2-by-2 matrices, maybe also 3-by-3 matrices.
The problem that arises is that an n-by-n matrix produces n matrices M_{ij} of size (n-1)-by-(n-1), each of which produces n-1 matrices of size one less and so on until the base case is reached, at which point you'll have to keep track of n!/2 matrices. (It becomes apparent at this point that Laplace expansion is a rather costly algorithm, any algorithm based on Gauss elimination will be far more efficient. But that is just an aside, since we are discussing Laplace expansion.) If done in an iterative fashion, this has to be done manually, a recursive algorithm will have implicit means of bookkeeping via stack frames.
Your approach
Let's have a look at the piece of code that you have provided. It eludes me what precisely you are trying to achieve. Take for instance the statement in the innermost loop which iterates over col:
matrixFirstRowValues[row + (matrixSize - i)] = matrix[1][col + (matrixSize - i)];
For as long as col changes in the innermost loop, both row and i are fixed, so you are assigning and reassigning from (apparently) the second row in matrix to the same entry in matrixFirstRowValues. Not only that, you assign from an index range (matrixSize-i) .. (2*matrixSize - (i+1)) which exceeds the range of the column unless i == matrixSize, which is only the case for the first value of i.
As I mentioned before, in the end you do not end up with just one 2-by-2 matrix but n!/2.
Copying except i-th row and j-th column
Looking at the matrix with i-th row and j-th column removed, you end up with four submatrices (some of which may be empty). Restricting yourself to expansion along the first row, then you are dealing with just two submatrices (still some of which may be empty). You may use two loops, one for the matrix to the left of the j-th column and to the right - or, as suggested in a previous answer - choose to skip the j-th column using continue to cycle the loop without updating the target column index. If col marks the current colum to remove (the current row is always 0), iterate r over all rows, and c over all columns and break the column loop in two pieces at c == col. Let's say, the target matrix is called minor, then it would look like this:
// expand along first row
for(col = 0; col < matrix_size; col++) {
// copy into minor matrix, left side then right side
for(r = 1; r < matrix_size; r++) {
for(c = 0; c < col; c++) {
minor[r-1][c] = matrix[r][c];
}
for(c = col+1; c < matrix_size; c++) {
minor[r-1][c-1] = matrix[r][c];
}
}
// use "minor" matrix at this point to calculte
// its determinant
}
The index shift r-1 is due to the removal of the first row.
A complete recursive Laplace expansion
As I mentioned before, the Laplace expansion of the determinant lends itself naturally to a recursive algorithm. I will do some changes to your setup, i will not use variable length arrays which are stack allocated, I will instead use heap allocated memory. Since the expansion, if the space is not reused, has an exponential space requirement, the stack might quickly get exhausted already for matrices of moderate size. Consequently, I will need an additional parameter to report back memory allocation failures via an intent out parameter which I call is_valid.
You will recognise the above matrix copy procedure with a little different names and an additional pointer dereference, since I operate with n-by-n matrices on the heap. I hope it will not lead to too much confusion.
#include <stdio.h>
#include <stdlib.h>
#define SQR(x) ((x)*(x))
int laplace_det(int matrix_size, const int (*mat)[][matrix_size], int *is_valid) {
// base cases
if(matrix_size == 1)
return (*mat)[0][0];
if(matrix_size == 2)
return (*mat)[0][0] * (*mat)[1][1] - (*mat)[1][0] * (*mat)[0][1];
// recusive case, matrix_size > 2
// expansion indiscriminately along the first row
//
// minor matrix with i-th row and j-th column
// removed for the purpose of calculating
// the minor.
// r, c row and column index variables
// col current column in expansion
// d determinant accumulator
//
int r, c, col, d = 0;
int (*minor)[matrix_size-1][matrix_size-1] = calloc(SQR(matrix_size-1), sizeof(int));
if(!minor) {
*is_valid = 0;
return 0;
}
// expand along first row
for(col = 0; col < matrix_size; col++) {
// copy into minor matrix, left side then right side
for(r = 1; r < matrix_size; r++) {
for(c = 0; c < col; c++) {
(*minor)[r-1][c] = (*mat)[r][c];
}
for(c = col+1; c < matrix_size; c++) {
(*minor)[r-1][c-1] = (*mat)[r][c];
}
}
// calculate minor
int temp_d = laplace_det(matrix_size-1, minor, is_valid);
if(!is_valid) {
free(minor);
return 0;
}
d += (col & 1 ? -1 : 1) * (*mat)[0][col] * temp_d;
}
// free resources
free(minor);
return d;
}
Example driver program:
int main(void) {
int is_valid = 1;
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int det_m = laplace_det(3, &matrix, &is_valid);
if(is_valid) {
printf("determinant %d\n", det_m);
}
}
An iterative approach
If you wanted to do the same thing iteratively, you will need to provide space for all n-1 submatrices of smaller size. As the recursive case shows, you can reuse the same space for all submatrices of the same size, but you cannot use that space for matrices of smaller size because each matrix has to spawn all submatrices of size one smaller, one for each column.
Since the original size of the matrix is not known beforehand, traversing all these matrices in a general way is difficult to realise and will require a lot of bookkeeping that we get for free keeping these values in their respective stack frames in the recursive case. But I suppose keeping the current column selector in an array of size matrixSize, as well as an array of pointers to the submatrices, it will be possible to rewrite this iteratively.
I tried to solve the laplace expansion using recursion method. May this help you
Code:
#include <stdio.h>
int determinant(int size,int det[][4]) // size & row of the square matrix
{
int temp[4][4],a=0,b=0,i,j,k;
int sum=0,sign; /* sum will hold value of determinant of the current matrix */
if(size==2)
return (det[0][0]*det[1][1]-det[1][0]*det[0][1]);
sign=1;
for(i=0;i<size;i++) // note that 'i' will indicate column no.
{
a=0;
b=0;
// copy into submatrix and recurse
for(j=1;j<size;j++) // should start from the next row !!
{
for(k=0;k<size;k++)
{
if(k==i) continue;
temp[a][b++]=det[j][k];
}
a++;
b=0;
}
sum+=sign*det[0][i]*determinant(size-1,temp); // increnting row & decrementing size
sign*=-1;
}
return sum;
}
//Main function
int main()
{
int i,j;
int det[4][4] = {{1, 0, 2, -1},
{3, 0, 0, 5},
{2, 1, 4, -3},
{1, 0, 5, 0}
};
printf("%d",determinant(4,det));
}
Cheers!
I am stuck at a simple problem, I am looking for a better solution than my.
I have an integers matrix array (tab[N][M]) and integer (k) and I have to find the smallest rectangle (sub matrix array) that has sum of it's elements greater then k
So, my current attempt of a solution is:
Make additional matrix array (sum[N][M]) and integer solution = infinity
For each 1 < i <= N + 1 and 1 < j <= M + 1
sum[ i ][ j ] = sum[ i - 1 ][ j ] + sum [ i ][ j - 1] + tab[ i ] [ j ] - sum[ i - 1] [ j - 1]
Then look on each rectangle f.e rectangle that starts at (x, y) and ends (a, b)
Rectangle_(x,y)_(a,b) = sum[ a ][ b ] - sum[ a - x ] [ b ] - sum[ a ][ b - y ] + sum[ a - x ][ b - y ]
and if Rectangle_(x,y)_(a,b) >= k then solution = minimum of current_solution and (a - x) * (b - y)
But this solution is quite slow (quartic time), is there any possibility to make it faster? I am looking for iterated logarithmic time (or worse/better). I managed to reduce my time , but not substantially.
If the matrix only contains values >= 0, then there is a linear time solution in the 1D case that can be extended to a cubic time solution in the 2D case.
For the 1D case, you do a single pass from left to right, sliding a window across the array, stretching or shrinking it as you go so that the numbers contained in the interval always sum to at least k (or breaking out of the loop if this is not possible).
Initially, set the left index bound of the interval to the first element, and the right index bound to -1, then in a loop:
Increment the right bound by 1, and then keep incrementing it until either the values inside the interval sum to > k, or end of the array is reached.
Increment the left bound to shrink the interval as small as possible without letting the values sum to less than or equal to k.
If the result is a valid interval (meaning the first step did not reach the end of the array without finding a valid interval) then compare it to the smallest so far and update if necessary.
This doesn't work if negative values are allowed, because in the second step you need to be able to assume that shrinking the interval always leads to a smaller sum, so when the sum dips below k you know that's the smallest possible for a given interval endpoint.
For the 2D case, you can iterate over all possible sub-matrix heights, and over each possible starting row for a given height, and perform this horizontal sweep for each row.
In pseudo-code:
Assume you have a function rectangle_sum(x, y, a, b) that returns the sum of the values from (x, y) to (a, b) inclusive and runs in O(1) time used a summed area table.
for(height = 1; height <= M; height++) // iterate over submatrix heights
{
for(row = 0; row <= (M-h); row++) // iterate over all rows
{
start = 0; end = -1; // initialize interval
while(end < N) // iterate across the row
{
valid_interval = false;
// increment end until the interval sums to > k:
while(end < (N-1))
{
end = end + 1;
if(rectangle_sum(start, row, end, row + height) > k)
{
valid_interval = true;
break;
}
}
if(!valid_interval)
break;
// shrink interval by incrementing start:
while((start < end) &&
rectangle_sum(start+1, row, end, row + height) > k))
start = start + 1;
compare (start, row), (end, row + height) with current smallest
submatrix and make it the new current if it is smaller
}
}
}
I have seen a number of answers to matrix rectangle problems here which worked by solving a similar 1-dimensional problem and then applying this to every row of the matrix, every row formed by taking the sum of two adjacent rows, every sum from three adjacent rows, and so on. So here's an attempt at finding the smallest interval in a line which has at least a given sum. (Clearly, if your matrix is tall and thin instead of short and fat you would work with columns instead of rows)
Work from left to right, maintaining the sums of all prefixes of the values seen so far, up to the current position. The value of an interval ending in a position is the sum up to and including that position, minus the sum of a prefix which ends just before the interval starts. So if you keep a list of the prefix sums up to just before the current position you can find, at each point, the shortest interval ending at that point which passes your threshold. I'll explain how to search for this efficiently in the next paragraph.
In fact, you probably don't need a list of all prefix sums. Smaller prefix sums are more valuable, and prefix sums which end further along are more valuable. So any prefix sum which ends before another prefix sum and is also larger than that other prefix sum is pointless. So the prefix sums you want can be arranged into a list which retains the order in which they were calculated but also has the property that each prefix sum is smaller than the prefix sum to the right of it. This means that when you want to find the closest prefix sum which is at most a given value you can do this by binary search. It also means that when you calculate a new prefix sum you can put it into its place in the list by just discarding all prefix sums at the right hand end of the list which are larger than it, or equal to it.
I'm trying to write some code that will locate the elements that are orthogonal to a given entry in a matrix. The output needs to include what the elements are themselves, their indices, and the algorithm needs to work for the edges as well. For example, consider
A = [ 1 2 5 6 7
2 3 1 6 9
3 6 7 8 1 ]
Then if I want the elements adjacent to entry (2,2), the code would return:
[2,2,1,6] %-> these elements are orthogonal to entry (2,2)
[w,x,y,z] %-> where w,x,y,z correspond to the index of the orthogonal entries
%found (they can be linear indices or otherwise).
So I implemented my own function to do this and well, I realized its pretty bad. It doesn't seem to consistently work for the edges (although I could try padding the matrix and see if that fixes it-I haven't had a chance yet), and importantly, my code loops over the entire freaking matrix. And so its very inefficient. I was wondering if someone had a quick, efficient way of doing what I've outlined above? MATLAB doesn't seem to have a function for doing this-I've checked.
I'd appreciate the help.
for(int i = row-1; i <= row+1; i += 2) {
for(int j = col-1; j <= col+1; j += 2) {
if(row>=0 && col>=0 && row < MATRIX_SIZE && col < MATRIX_SIZE)
std::cout << mat[row, col];
}
}
this in a example in c++. the output will not be very clear but this is just an example. in programming its assumed the rows/cols in the matrix starts from 0 (not 1) so in your example, the solution you gave will fit the input (1,1) and not (2,2). the run time is O(1) of course.
row = given row argument (for example 1)
col = given column argument (for example also 1)
MATRIX_SIZE = the size of the matrix: if the matrix is nxn then MATRIX_SIZE = n, and the last index in each row/col of the matrix is n-1.
If your 2D matrix contains Wdt columns and Hgt rows, then indexes of neighbours of k-th element are
top = k - Wdt // if k > Wdt
bottom = k + Wdt // if k <= Wdt * Hgt - Wdt
right = k + 1 // if (k - 1) mod Wdt > 0
left = k - 1 // if (k - 1) mod Wdt < Wdt - 1
if-expressions are intended to exclude off-edge elements
I'm trying to concatenate the same matrix in C, and the only idea that crossed to my mind is addition, but it doesn't work. For example, if I have: {1,1;2,2}, my new matrix should be {1,1,1,1;2,2,2,2}. I want to double the number of rows. I Googled, but I didn't find anything.
Here is my code:
matrix2=realloc(matrix1,sizeof(int*)*(row));
int i,j;
for(i=0;i<row;i++){
for(j=0;j<col;j++){
matrix2[i][j]=matrix1[i][j]+matrix1[i][j];
}
}
Use the psuedocode I provide below. Note that for any C before C99, you cannot instantiate arrays with int matrix[2*W][H] (if W and H are not #defines)
Given matrix1 and matrix 2 of equal W,H
make matrix3 of 2*W,H
for h to H
for i to W
matrix3[h][i] = matrix1[h][i]
matrix3[h][i+W] = matrix2[h][i]
Making the matrix will require 1 malloc per row, plus 1 malloc to store the array of row pointers.
Note how you will need 2 assignments in the loop instead of the one you had before. This is because you are setting in two places.
You sound like you have a background with higher level languages like matlab. In C the plus operator does not concatenate matrices. This will add the values in the matrices and store the new value into the new matrix.
Here we are copying the input matrix into a new matrix twice
for(int i = 0; i < m; i++){for(int j = 0; j < n;j++)
{ mat2[i][j] = mat[i][j];}}
for(int i = 0 ; i < m ; i++){for(int j = n; j < (2*n) ; j++){ mat2[i][j] = mat[i][j-n];}}