Submatrix extraction from matrix with loop tiling - c

I have the following matrix 4x4:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
and I want extract and store (in some news variables) the four following submatrix 2x2:
[1 2
5 6]
[3 4
7 8]
[9 10
13 14]
[11 12
15 16]
It's like the "Rect" (http://docs.opencv.org/java/org/opencv/core/Rect.html) function of openCV, but I don'want to use OpenCV.
I have to use a parallelizing compiler and so I would like to do the extraction of the submatrix with a famous loop transformation present in literature: "loop tiling" (also knows as "loop blocking" or "loop unroll and jam" or "loop stripmine and interchange"). - (http://en.wikipedia.org/wiki/Loop_tiling)
Is it possible?

Is it possible?
Of course …
int n = 4;
int matrix[4][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
int submatrixes[n/2*n/2][2][2];
int i, j, x, y, z;
for (z = i = 0; i < n; i += 2)
for (j = 0; j < n; j += 2, ++z)
for (x = 0; x < 2; x++)
for (y = 0; y < 2; y++)
submatrixes[z][x][y] = matrix[i+x][j+y];

Related

Populating and array in a matrix style

I want to populate an array in a matrix style, on columns. So for example, if I had an array input:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Then the matrix would be (for numRows = 3, numCols=5):
1 4 7 10 13
2 5 8 11 14
3 6 9 12 15
This means the real array would be:
1 4 7 10 13 2 5 8 11 14 3 6 9 12 15
How would I do that?
Here is my take:
int v[15] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
int matrix[15];
int row = 0, col = 0;
for (int i = 0; i < 15; ++i) {
matrix[col * 5 + row] = v[i];
printf("row = %d col = %d\n", row, col);
row++;
if (row == 3) {
row = 0;
col++;
}
}
```
You were very close in your last code example. The short answer is that rather than this:
matrix[col * 5 + row] = v[i];
You want:
matrix[row * 5 + col] = v[i];
In other words, 'row' and 'col' need to be the other way around.
Here's your example with that change made, and the results printed at the end:
int main(int argc, const char * argv[]) {
int v[15] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
int matrix[15];
int row = 0, col = 0;
for (int i = 0; i < 15; ++i) {
matrix[row * 5 + col] = v[i];
printf("row = %d col = %d\n", row, col);
row++;
if (row == 3) {
row = 0;
col++;
}
}
for (int i = 0; i < 15; ++i) {
printf("%d ", matrix[i]);
}
printf("\n");
}
The output at the end for me is:
1 4 7 10 13 2 5 8 11 14 3 6 9 12 15
Which appears to match the output you were after in your post.
There are multiple conversions that can be made here: from 2-d row/column indices to 1-d indices in row- or column-major order, and from 1-d indices in row- or column-major order to 2-d row/column indices. The math is fairly simple for all the conversions (converting from 1-d to 2-d indices involves integer division and modulus). Once you figure out the conversions you need, I suggest creating a little library of functions for performing the conversions so that you have the functionality available when you need it.
Lastly, a couple general suggestions. Your original code wrote outside array bounds, which wasn't checked for, at least in what you posted. For exploratory work like this, I'd suggest using bounds checking so that you can detect errors more easily. (For example, in this case you could use std::array and the at() function.) This will help you catch a certain class of mistakes early.
I'd also suggest using named constants, even in a small example like this, e.g. 'numRows' and 'numCols' instead of 3 and 5, and 'numElements' as the product of those instead of 15. This will also help avoid errors, and will also make the code easier to read and understand (both for you and others).

Printing 2D array diagonally right-down

Trying to print a 2D array diagonally, going right to down, other solutions I've found are going in the opposite direction
Example of what I'm trying to achieve:
Input:
0 1 2 3
1 2 3 4
2 3 4 5
3 4 5 6
Intended Output:
0 2 4 6
1 3 5
2 4
3
(and other side 1 3 5, 2 4, 3)
Managed to print a diagonal with
for (x=0; x<12; x++) {
printf("%d ", arr[x][x])
}
But unsure how to replicate it for multiple, following attempt is incorrect
for (x=0; x<12; x++) {
for (y=0;y<x+1;y++) {
printf("%d ", arr[x][y]);
}
printf("\n");
}
The following C program meets your requirements. Try to understand the indexing.
int n, i, j, k;
int arr[5][5] = {
0, 1, 2, 3, 4,
1, 2, 3, 4, 5,
2, 3, 4, 5, 6,
3, 4, 5, 6, 7,
4, 5, 6, 7, 8
};
n = 5;
for (k = 0; k < n; k++) {
int ind = 0;
for (i = k; i < n; i++) {
printf("%d ", arr[i][ind++]);
}
printf("\n");
}
Output of the following program:
0 2 4 6 8
1 3 5 7
2 4 6
3 5
4
You can change the size of the array and change the value of n, it will work for your desired n*n array.

How to make parameter of double dimension arrangement to use in function

#include <stdio.h>
void Turn(int(*ptr)[4], int length, int vertical)
{
int arr[100][100] = { 0, };
for (int i = 0; i < vertical; i++)
{
for (int j = 0; j < length; j++)
{
arr[i][j] = *(*(ptr + (vertical - j - 1)) + i);
}
}
for (int i = 0; i < vertical; i++)
{
for (int j = 0; j < length; j++)
{
*(*(ptr + i) + j) = arr[i][j];
}
}
}
int main(void)
{
int BY[4][4] = {
1,2,3,4,
5,6,7,8,
9,10,11,12,
13,14,15,16,
};
int length = sizeof(BY[0]) / sizeof(int);
int vertical = (sizeof(BY) / sizeof(int)) / length;
Turn(BY, length, vertical);
for (int i = 0; i < vertical; i++)
{
for (int j = 0; j < length; j++)
{
printf("%d ", BY[i][j]);
}
printf("\n");
}
return 0;
}
I wrote a function named Turn to rotate a 2D array right (a 90 degree rotation). I wanted to make this function to turn every array that has same vertical range and length. But I can't hand over
(I used google translate, I don't know how to describe it) parameter of a 2D array.
I first used void Turn(int(*ptr)[] ....)
but it didn't work. So I couldn't help using
int (*ptr)[4] in this function.
How can I make a parameter of a 2D array that can be used with any 2D array?
Using the C99 variable length array (VLA) feature make the problem easy. C11 makes support for VLAs optional, but the implementation must define __STDC_NO_VLA__ to show that it doesn't support VLAs.
Here's one version of the code. I've renamed your Turn() function (which turns the matrix 90° right into TurnR() and added a TurnL() function which turns the matrix 90° left. Because the code handles non-square matrices, the output matrix is separate from the input matrix. (You can simplify the code slightly if you only want to work with square matrices.)
#include <stdio.h>
static void TurnR(size_t rows, size_t cols, int matrix[rows][cols], int result[cols][rows])
{
for (size_t r = 0; r < rows; r++)
{
for (size_t c = 0; c < cols; c++)
result[c][rows - 1 - r] = matrix[r][c];
}
}
static void TurnL(size_t rows, size_t cols, int matrix[rows][cols], int result[cols][rows])
{
for (size_t r = 0; r < rows; r++)
{
for (size_t c = 0; c < cols; c++)
result[cols - 1 - c][r] = matrix[r][c];
}
}
static void Print(const char *tag, size_t rows, size_t cols, int matrix[rows][cols])
{
printf("%s (%zux%zu):\n", tag, rows, cols);
for (size_t r = 0; r < rows; r++)
{
const char *pad = "";
for (size_t c = 0; c < cols; c++)
{
printf("%s%3d", pad, matrix[r][c]);
pad = " ";
}
putchar('\n');
}
}
int main(void)
{
int BY[4][4] = {
{ 1, 2, 3, 4, },
{ 5, 6, 7, 8, },
{ 9, 10, 11, 12, },
{ 13, 14, 15, 16, },
};
int out[4][4];
Print("before", 4, 4, BY);
TurnR(4, 4, BY, out);
Print("right", 4, 4, out);
TurnL(4, 4, BY, out);
Print("left", 4, 4, out);
int m4x6[4][6] =
{
{ 1, 2, 3, 4, 5, 6, },
{ 7, 8, 9, 10, 11, 12, },
{ 13, 14, 15, 16, 17, 18, },
{ 19, 20, 21, 22, 23, 24, },
};
int m6x4[6][4];
Print("before", 4, 6, m4x6);
TurnR(4, 6, m4x6, m6x4);
Print("right", 6, 4, m6x4);
TurnL(4, 6, m4x6, m6x4);
Print("left", 6, 4, m6x4);
int m5x3[5][3] =
{
{ 1, 2, 3, },
{ 4, 5, 6, },
{ 7, 8, 9, },
{ 10, 11, 12, },
{ 13, 14, 15, },
};
int m3x5[3][5];
Print("before", 5, 3, m5x3);
TurnR(5, 3, m5x3, m3x5);
Print("right", 3, 5, m3x5);
TurnL(5, 3, m5x3, m3x5);
Print("left", 3, 5, m3x5);
TurnL(3, 5, m3x5, m5x3);
Print("doubleL", 5, 3, m5x3);
return 0;
}
And sample output is:
before (4x4):
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
right (4x4):
13 9 5 1
14 10 6 2
15 11 7 3
16 12 8 4
left (4x4):
4 8 12 16
3 7 11 15
2 6 10 14
1 5 9 13
before (4x6):
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
right (6x4):
19 13 7 1
20 14 8 2
21 15 9 3
22 16 10 4
23 17 11 5
24 18 12 6
left (6x4):
6 12 18 24
5 11 17 23
4 10 16 22
3 9 15 21
2 8 14 20
1 7 13 19
before (5x3):
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
right (3x5):
13 10 7 4 1
14 11 8 5 2
15 12 9 6 3
left (3x5):
3 6 9 12 15
2 5 8 11 14
1 4 7 10 13
doubleL (5x3):
15 14 13
12 11 10
9 8 7
6 5 4
3 2 1
I wouldn't dream of writing the code using the *(ptr + index) notation, especially with the double subscripts; it is just too error prone and hard to read (a nightmare, indeed!).

shifting a sequence of numbers in C?

I have a question about some trying to wrap around a sequence of numbers that I'm trying to shift in the C programming language. The first value that is found in the sequence of numbers I calculate via a loop gets thrown out in the end. Here is what the code looks like right now:
numbers[d] = numbers[x];
for (d = y-1; d >=0; d --){
numbers[d] = numbers[(d - 1) % y];
printf(" numbers[d] = %d \n", numbers[d]);
}
Here are the numbers[x] I calculated from my previous loop:
1, 17, 3, 15, 14, 6, 12, 8, 10
Here is what the numbers[d] currently looks like:
17, 3, 15, 14, 6, 12, 8, 10, 10
...and here is what it should look like:
17, 3, 15, 14, 6, 12, 8, 10, 1
It seems like it doesn't wrap the 1 around to the end. Is there a conditional that I am missing in my loop? Thanks!
Let's analyze your for loop, minus the printf statement.
for (d = y-1; d >=0; d --){
numbers[d] = numbers[(d - 1) % y];
}
Before you start the loop, you have the following values in numbers.
1, 17, 3, 15, 14, 6, 12, 8, 10
The value of y is 9.
In the first iteration of the loop, d = 8. (d-1)%y = 7. You replace the value of number[8] by number[7]. The array becomes:
1, 17, 3, 15, 14, 6, 12, 8, 8
In the next iteration of the loop, d = 7. (d-1)%y = 6. You replace the value of number[7] by number[6]. The array becomes:
1, 17, 3, 15, 14, 6, 12, 12, 8
When you reach the iteration where d=1, (d-1)%y = 0. You replace the value of number[1] by number[0]. The array becomes:
1, 1, 17, 3, 15, 14, 6, 12, 8
In the next iteration, d=0, (d-1)%y = -1. The statement
numbers[d] = numbers[(d - 1) % y];
is equivalent to
numbers[0] = numbers[-1];
This certainly leads to undefined behavior but it doesn't explain the other numbers in your output. Maybe the output that you posted corresponds to a different block of code.
I think the answer by #JonathanLeffler gives a solution to your algorithmic problem. I won't repeat that here.
Code
#include <stdio.h>
static const int debug = 0;
static void dump_array(const char *tag, int n, const int array[n])
{
printf("%s (%d)", tag, n);
for (int i = 0; i < n; i++)
printf("%3d", array[i]);
putchar('\n');
}
static void rot1u(int n, int numbers[n])
{
int v = numbers[n-1];
for (int d = n - 1; d >= 0; d--)
{
numbers[d] = numbers[(n + d - 1) % n];
if (debug)
printf(" numbers[%d] = %d\n", d, numbers[d]);
}
numbers[0] = v;
dump_array("Up After: ", n, numbers);
}
static void rot1d(int n, int numbers[n])
{
int v = numbers[0];
for (int d = 0; d < n; d++)
{
numbers[d] = numbers[(d + 1) % n];
if (debug)
printf(" numbers[%d] = %d\n", d, numbers[d]);
}
numbers[n-1] = v;
dump_array("Dn After: ", n, numbers);
}
int main(void)
{
int numbers[] = { 1, 17, 3, 15, 14, 6, 12, 8, 10 };
enum { N_NUMBERS = sizeof(numbers) / sizeof(numbers[0]) };
dump_array("-- Before:", N_NUMBERS, numbers);
rot1u(N_NUMBERS, numbers);
rot1d(N_NUMBERS, numbers);
rot1d(N_NUMBERS, numbers);
rot1d(N_NUMBERS, numbers);
rot1u(N_NUMBERS, numbers);
rot1u(N_NUMBERS, numbers);
return 0;
}
Example output
-- Before: (9) 1 17 3 15 14 6 12 8 10
Up After: (9) 10 1 17 3 15 14 6 12 8
Dn After: (9) 1 17 3 15 14 6 12 8 10
Dn After: (9) 17 3 15 14 6 12 8 10 1
Dn After: (9) 3 15 14 6 12 8 10 1 17
Up After: (9) 17 3 15 14 6 12 8 10 1
Up After: (9) 1 17 3 15 14 6 12 8 10
You need to save the element(s) which should be rotated to the the other side before the loop, and only put it into its proper place (theem into their proper places) afterwards.
#include <stdio.h>
#include <time.h>
#define METHOD 2
#define MAX_SKIERS 20
int starting_lineup[MAX_SKIERS+1];
int main(void)
{
int i, num_skiers = 20;
srand(time(NULL));
int pos1, pos2, temp;
for (i = 0; i <= num_skiers; i++)
starting_lineup[i] = i;
for (i = 0; i < num_skiers*2; i++) {
// Generate two random positions
pos1 = rand() % num_skiers + 1;
pos2 = rand() % num_skiers + 1;
// Swap the skiers at the two positions
temp = starting_lineup[pos1];
starting_lineup[pos1] = starting_lineup[pos2];
starting_lineup[pos2] = temp;
}
printf("The starting lineup (first to last):\n");
for (i = 1; i <= num_skiers; i++)
printf("%s%d", (i == 1 ? "" : ", "), starting_lineup[i]);
putchar('\n');
return 0;
}

Replace number by sum of other numbers in a list without subtraction

I was asked:
Replace each number in a list by sum of remaining elements, the list is not sorted.
So suppose if we have a list of numbers like {2, 7, 1, 3, 8}, now we are to replace each element with sum of rest of elements. The output should be:
{(7 + 1 + 3 + 8), (2 + 1 + 3 + 8), (2 + 7 + 3 + 8), (2 + 7 + 1 + 8), (2 + 7 + 1 + 3)}
== {19, 14, 20, 18, 13}
I answered an obvious solution:
First evaluate sum of all numbers then subtract each element from sum.
So for above list sum is 2 + 7 + 1 + 3 + 8 = 21, then for output do like:
{sum - 2, sum - 7, sum - 1, sum - 3, sum - 8}
{21 - 2, 21 - 7, 21 - 1, 21 - 3, 21 - 8}
== {19, 14, 20, 18, 13}
It needs only two iterations of list.
Then Interviewer asked me: Now do it without subtraction? and I couldn't answer :(
Is other solution possible? Can some share any other trick? A better trick is possible?
Lets extra memory space can be used (I asked after a few minutes of try, even then I couldn't answer).
One possibility would be to compute prefix and suffix sums of your array and then combine the appropriate entries. This would still be O(n) but needs more memory space so I think your original method is better.
In other words, from {2, 7, 1, 3, 8} compute {2, 2+7, 2+7+1, 2+7+1+3, 2+7+1+3+8} and {2+7+1+3+8, 7+1+3+8, 1+3+8, 3+8, 8} and then add the appropriate entries.
The solution is to sum everything but the element. Then you don't have to subtract after the fact. You just skip adding the element at the current index.
Alternatively, you could get a subset of the list that excludes the element at the current index, then just sum the subset together. Pretty much the same thing as my first suggestion with more implementation detail.
C++ implementation. O(n) and done by keeping sums of all elements before and after a certain index.
#include <iostream>
int main() {
int a[] = {2,7,1,3,8};
int prefix[5]; // Sum of all values before current index
int suffix[5]; // Sum of all values after current index
prefix[0] = 0;
suffix[4] = 0;
for(int i = 1; i < 5; i++) {
prefix[i] = prefix[i-1] + a[i-1];
suffix[4 - i] = suffix[4 - i + 1] + a[4 - i + 1];
}
// Print result
for (int i = 0; i < 5; i++) {
std::cout << prefix[i] + suffix[i] << " ";
}
std::cout << std::endl;
}
I can't think anything better than yours.
But how about this :
Create a (n-1)xn matrix:
[ 2, 7, 1, 3, 8 ]
| 7, 1, 3, 8, 2 | rotate by 1
| 1, 3, 8, 2, 7 | by 2
| 3, 8, 2, 7, 1 | by 3
| 8, 2, 7, 1, 3 | by 4
Then Sum up the columns
C++'s std::rotate_copy can be used to create matrix
std::vector<int> v1 {2, 7, 1, 3, 8 };
std::vector<int> v2 (v1.size());
int i,j;
std::vector< std::vector<int> > mat;
for (int i=1; i<v1.size();++i){
std::rotate_copy(v1.begin(),v1.begin()+i,v1.end(),v2.begin());
mat.push_back(v2);
}
for(j=0;j<v1.size();++j)
for(i=0;i<v1.size()-2;++i)
v2[j]+=mat[i][j];
for(i=0;i<v2.size();++i)
std::cout<<v2[i]<<" ";
#include <iostream.h>
#include <stdio.h>
int main() {
int a[] = {2,7,1,3,8};
int sum[5]={0};
for(int j = 0; j < 5; j++){
for(int i = 1; i < 5; i++) {
sum[j]=sum[j]+a[(j+i+5)%5];
}
printf("%d ", sum[j]); }
}
Instead of subtracting the element you can add the element multiplied by -1. Multiplication and addition are allowed operations, I guess.

Resources