You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C语言中求解大尺寸二进制矩阵的逆矩阵问题

Hey there! Let's break down your problem step by step. The key mistake here is that you're using integer arithmetic to invert a binary matrix, but binary matrix inversion needs to happen in GF(2) (the binary field)—not the integer domain. In GF(2), all operations are modulo 2, which means subtraction becomes XOR (^), multiplication is regular integer multiplication followed by & 1, and there's no such thing as negative numbers. That's why you're seeing -1 in your output—those are just 1 in GF(2) terms, but integer arithmetic is treating them as negatives.


1. Core Concept: GF(2) Matrix Inversion

For binary matrices (elements 0/1), inversion follows these rules:

  • Addition/Subtraction: Equivalent to XOR (^), since 1-1 ≡ 0 mod 2 and 1-0 ≡ 1 mod 2
  • Multiplication: Regular integer multiplication, then take modulo 2 (& 1)
  • Division: Only possible if the divisor is 1 (since 1's inverse in GF(2) is itself), so no actual division—just use the value directly

LU decomposition works in GF(2), but Gaussian elimination is more straightforward for inversion: we augment the original matrix with the identity matrix, then perform row operations to turn the original matrix into the identity. The augmented part will become the inverse.


2. Adapted Implementation for unsigned int

Here's a corrected version of your code using GF(2) arithmetic, with unsigned int and proper binary output:

#include <stdio.h>
#include <stdlib.h>

#define N 3

// Perform Gaussian elimination to invert a binary matrix in GF(2)
int invertBinaryMatrix(unsigned int **mat, unsigned int **inv, int n) {
    // Create augmented matrix: [mat | identity]
    unsigned int **aug = (unsigned int **)malloc(n * sizeof(unsigned int *));
    for (int i = 0; i < n; i++) {
        aug[i] = (unsigned int *)malloc(2 * n * sizeof(unsigned int));
        // Copy original matrix to left half
        for (int j = 0; j < n; j++) {
            aug[i][j] = mat[i][j];
        }
        // Set identity matrix to right half
        for (int j = n; j < 2 * n; j++) {
            aug[i][j] = (i == j - n) ? 1 : 0;
        }
    }

    // Gaussian elimination steps
    for (int col = 0; col < n; col++) {
        // Find pivot row (first row with 1 in current column)
        int pivotRow = -1;
        for (int row = col; row < n; row++) {
            if (aug[row][col] == 1) {
                pivotRow = row;
                break;
            }
        }
        if (pivotRow == -1) {
            // Matrix is singular, no inverse exists
            printf("Matrix is singular, cannot invert.\n");
            return 0;
        }

        // Swap pivot row with current column row
        if (pivotRow != col) {
            unsigned int *temp = aug[col];
            aug[col] = aug[pivotRow];
            aug[pivotRow] = temp;
        }

        // Eliminate all other rows in this column
        for (int row = 0; row < n; row++) {
            if (row != col && aug[row][col] == 1) {
                // XOR pivot row with current row to eliminate the 1
                for (int j = col; j < 2 * n; j++) {
                    aug[row][j] ^= aug[col][j];
                }
            }
        }
    }

    // Extract inverse matrix from the right half of augmented matrix
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            inv[i][j] = aug[i][j + n];
        }
        free(aug[i]);
    }
    free(aug);
    return 1;
}

int main() {
    // Original binary matrix
    unsigned int **D = (unsigned int **)malloc(N * sizeof(unsigned int *));
    for (int i = 0; i < N; i++) {
        D[i] = (unsigned int *)malloc(N * sizeof(unsigned int));
    }
    D[0][0] = 1; D[0][1] = 1; D[0][2] = 0;
    D[1][0] = 0; D[1][1] = 1; D[1][2] = 0;
    D[2][0] = 1; D[2][1] = 1; D[2][2] = 1;

    // Allocate memory for inverse matrix
    unsigned int **inv = (unsigned int **)malloc(N * sizeof(unsigned int *));
    for (int i = 0; i < N; i++) {
        inv[i] = (unsigned int *)malloc(N * sizeof(unsigned int));
    }

    // Invert the matrix
    if (invertBinaryMatrix(D, inv, N)) {
        // Print original matrix
        printf("Original Matrix:\n");
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                printf("%u\t", D[i][j]);
            }
            printf("\n");
        }

        // Print inverse matrix
        printf("\nInverse Matrix (GF(2)):\n");
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                printf("%u\t", inv[i][j]);
            }
            printf("\n");
        }

        // Verify product is identity matrix
        printf("\nProduct of Original and Inverse:\n");
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                unsigned int sum = 0;
                for (int k = 0; k < N; k++) {
                    sum += D[i][k] * inv[k][j];
                }
                printf("%u\t", sum & 1); // Mod 2 to get GF(2) result
            }
            printf("\n");
        }
    }

    // Cleanup memory
    for (int i = 0; i < N; i++) {
        free(D[i]);
        free(inv[i]);
    }
    free(D);
    free(inv);

    return 0;
}

Key Changes:

  • Uses dynamic memory allocation (critical for large matrices later)
  • Implements GF(2) arithmetic with XOR and modulo 2 operations
  • Avoids negative numbers entirely by using unsigned int and proper field operations
  • Checks for singular matrices (no inverse exists)

3. Optimization for Large Matrices (1500-2000)

For matrices of size 1500x1500, a naive 2D array approach will work but can be optimized for speed and memory:

a. Bit Compression

Each unsigned int can store 32 bits, so you can compress each row into n/32 + 1 unsigned int values. This reduces memory usage by 32x and speeds up row operations (you can XOR entire 32-bit blocks at once instead of individual elements).

Example row storage:

typedef struct {
    unsigned int *bits;
    int num_words;
} BitRow;

BitRow createBitRow(int n) {
    BitRow row;
    row.num_words = (n + 31) / 32; // Round up to nearest 32 bits
    row.bits = (unsigned int *)calloc(row.num_words, sizeof(unsigned int));
    return row;
}

Row XOR becomes a loop over the num_words values, using the ^= operator directly on unsigned ints.

b. Memory Efficiency

  • Use 1D arrays instead of 2D arrays to reduce pointer overhead
  • Avoid stack allocation (stack size is limited); always use malloc/calloc for large matrices

c. Pivot Optimization

In GF(2), pivots are always 1, so you don't need to search for the "largest" pivot—just the first row with a 1 in the current column. This saves time compared to integer LU decomposition.

d. Parallelization

If allowed, you can parallelize the row elimination step (each row can be processed independently once the pivot row is found). For C, you can use OpenMP (though it's a library, it's widely available) or manual thread splitting.


4. Notes on MxN Matrices

Matrix inversion is only defined for square, full-rank matrices (in any field, including GF(2)). For non-square MxN matrices, you can only compute a pseudoinverse, but you explicitly stated you need an inverse—so ensure your matrix is square and has full rank (determinant 1 in GF(2)) before attempting inversion.


内容的提问来源于stack exchange,提问作者Cherry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:06:49