C中的填充矩阵

Padding matrix in C

我尝试使用 SSE 转置我的矩阵。但它只能适合N可以被4整除的矩阵。所以我想填充矩阵来重新格式化它。

比如3*3的矩阵,应该填充成4*4的矩阵:

1 2 3    1 2 3 0 
4 5 6 => 4 5 6 0
7 8 9    7 8 9 0
         0 0 0 0

有什么有效的方法吗?而且我不确定是否需要花费时间来填充它,SSE 转置是否会比循环每个索引更慢...

增加数组或矩阵的大小是一个有趣的问题。我们可以创建一个新的数组或矩阵来填充并将所有内容复制到新的。

#include <stdio.h>
#include <stdlib.h>
#include <histedit.h>
#define MATRIX_SIZE 3 /* use some size */

/* returns an array of arrays of int*, all of which NULL */
int ***alloc_matrix(unsigned rows, unsigned columns) {
    int ***matrix = malloc(rows * sizeof(int **));
    if (!matrix) abort();
    for (unsigned row = 0; row < rows; row++) {
        matrix[row] = malloc(columns * sizeof(int *));
        if (!matrix[row]) abort();
        for (unsigned column = 0; column < columns; column++) {
            matrix[row][column] = NULL;
        }
    }
    return matrix;
}

/* deallocates an array of arrays of int*, calling free() on each */
void free_matrix(int ***matrix, unsigned rows, unsigned columns) {
    for (unsigned row = 0; row < rows; row++) {
        for (unsigned column = 0; column < columns; column++) {
            //    printf("column %d row %d\n", column, row);
            free(matrix[row][column]);
        }
        free(matrix[row]);
    }
    free(matrix);
}

int *** padding_matrix(int ***matrix, unsigned size, unsigned padding) {
    int ***padded_matrix = alloc_matrix(padding, padding);
    for (unsigned row = 0 ; row < size; row++) {
        for (unsigned column = 0 ; column < size; column++) {
            printf("copying column %d row %d %d\n", column, row,  * matrix[row][column]);
            padded_matrix[row][column] =  matrix[row][column];
            printf("copied column %d row %d %d\n", column, row,  * padded_matrix[row][column]);
        }
    }

    for (unsigned row = size ; row < padding; row++) {
        for (unsigned column = 0 ; column < padding; column++) {
            int i = 0;
            padded_matrix[row][column] = &i;
            printf("padded column %d row %d\n", column, row);
        }
    }

    for (unsigned row = 0 ; row < padding; row++) {
            int i = 0;
            padded_matrix[row][3] = &i;
            printf("padded column %d row %d\n", 3, row);
        }
    return padded_matrix;
}

int main(int argc, char *argv[]) {
    int ***matrix = alloc_matrix(MATRIX_SIZE, MATRIX_SIZE);
    int x = 1;
    int y = 2;
    int z = 3;
    int u = 4;
    int w = 5;
    int a = 6;
    int b = 7;
    int c = 8;
    int d = 9;

    matrix[0][0] = &x;
    matrix[0][1] = &y;
    matrix[0][2] = &z;
    matrix[1][0] = &u;
    matrix[1][1] = &a;
    matrix[1][2] = &w;
    matrix[2][0] = &b;
    matrix[2][1] = &c;
    matrix[2][2] = &d;
    for (unsigned row = 0 ; row < MATRIX_SIZE; row++) {
        for (unsigned column = 0 ; column < MATRIX_SIZE; column++) {
            printf("matrix column %d row %d=%d\n", column, row , * matrix[row][column]);
        }
    }


    int ***matrix2  = padding_matrix(matrix, MATRIX_SIZE, MATRIX_SIZE + 1);
    for (unsigned row = 0 ; row < MATRIX_SIZE+1; row++) {
        for (unsigned column = 0 ; column < MATRIX_SIZE+1; column++) {
            printf("padded matrix column %d row %d=%d\n", column, row , * matrix2[row][column]);
        }
    }
}

测试

padmatrix
matrix column 0 row 0=1
matrix column 1 row 0=2
matrix column 2 row 0=3
matrix column 0 row 1=4
matrix column 1 row 1=6
matrix column 2 row 1=5
matrix column 0 row 2=7
matrix column 1 row 2=8
matrix column 2 row 2=9
copying column 0 row 0 1
copied column 0 row 0 1
copying column 1 row 0 2
copied column 1 row 0 2
copying column 2 row 0 3
copied column 2 row 0 3
copying column 0 row 1 4
copied column 0 row 1 4
copying column 1 row 1 6
copied column 1 row 1 6
copying column 2 row 1 5
copied column 2 row 1 5
copying column 0 row 2 7
copied column 0 row 2 7
copying column 1 row 2 8
copied column 1 row 2 8
copying column 2 row 2 9
copied column 2 row 2 9
padded column 0 row 3
padded column 1 row 3
padded column 2 row 3
padded column 3 row 3
padded column 3 row 0
padded column 3 row 1
padded column 3 row 2
padded column 3 row 3
padded matrix column 0 row 0=1
padded matrix column 1 row 0=2
padded matrix column 2 row 0=3
padded matrix column 3 row 0=0
padded matrix column 0 row 1=4
padded matrix column 1 row 1=6
padded matrix column 2 row 1=5
padded matrix column 3 row 1=0
padded matrix column 0 row 2=7
padded matrix column 1 row 2=8
padded matrix column 2 row 2=9
padded matrix column 3 row 2=0
padded matrix column 0 row 3=0
padded matrix column 1 row 3=0
padded matrix column 2 row 3=0
padded matrix column 3 row 3=0

Process finished with exit code 0

您在上面的输出中看到填充后的矩阵更大,我们插入了填充。

你实际上不需要垫,是吗?您只是建议将其作为一种使用您已有的 4x4 SSE 转置例程的方法,对吗?

矩阵转置不移动对角线元素(包括第一个和最后一个)。 3x3 转置的数据移动要少得多:只需要 7 个元素 loaded/stored.

1 2 3    1 4 7
4 5 6 => 2 5 8
7 8 9    3 6 9

AVX2:

如果您的元素是 4B(intfloat,而不是 double),则前 8 个元素适合单个 AVX 向量。 AVX2 有一个完整的交叉车道洗牌,vpermps。所以整个转置可以通过一次加载/_mm256_permutevar8x32_ps/存储来完成。它在 Intel Haswell 上具有每时钟一个吞吐量和三个周期延迟。

由于最后一个元素不需要移动,所以您根本不需要触摸它,除非您没有就地移调,只需复制它即可。


仅使用 SSE,您可以加载两个包含前八个元素的向量,并使用 shufps 或其他方法将它们相互打乱,以组合每个向量中的元素。

或者可以随机创建一个 { 1 4 3 2 } 向量和一个 { 5 8 7 6 } 向量,然后将元素 7 混合到第一个,将元素 3 混合到第二个。

无论如何,3x3 比 4x4 更容易转置,所以如果以后不需要在整行上使用 SSE,请不要填充到 4x4。

不,您不能有效地填充矩阵。假设平面数组,您需要创建另一个内存区域,然后将值复制到左上角,然后将其余值设置为零。所以本质上是对每个值的操作。

您可以做的是从填充矩阵开始并对它们执行所有操作,或者使用稀疏矩阵表示。但由于目标是快速移调,您很可能会在摇摆上获胜而在环形交叉路口上失败。