/* Author: Pate Williams (c) 1997 "Algorithm 2.2.2 (Inverse of a Matrix). Let M be an n by n matrix. This algorithm either outputs a message saying that M is not invertible, or outputs inverse of M." -Henri Cohen- See "A Course in Computational Algebraic Number Theory" by Henri Cohen pages 49-50. We specialize to the case where m[i][j] is in field Zp. */ #include #include long **create_square_matrix(long n) { long i, **matrix = calloc(n, sizeof(long *)); if (!matrix) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from create_matrix\n"); exit(1); } for (i = 0; i < n; i++) { matrix[i] = calloc(n, sizeof(long)); if (!matrix[i]) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from create_matrix\n"); exit(1); } } return matrix; } void delete_matrix(long n, long **matrix) { long i; for (i = 0; i < n; i++) free(matrix[i]); free(matrix); } void Euclid_extended(long a, long b, long *u, long *v, long *d) { long q, t1, t3, v1, v3; *u = 1, *d = a; if (b == 0) { *v = 0; return; } v1 = 0, v3 = b; #ifdef DEBUG printf("----------------------------------\n"); printf(" q t3 *u *d t1 v1 v3\n"); printf("----------------------------------\n"); #endif while (v3 != 0) { q = *d / v3; t3 = *d - q * v3; t1 = *u - q * v1; *u = v1, *d = v3; #ifdef DEBUG printf("%4ld %4ld %4ld ", q, t3, *u); printf("%4ld %4ld %4ld %4ld\n", *d, t1, v1, v3); #endif v1 = t1, v3 = t3; } *v = (*d - a * *u) / b; #ifdef DEBUG printf("----------------------------------\n"); #endif } long inv(long number, long modulus) { long d, u, v; Euclid_extended(number, modulus, &u, &v, &d); if (d == 1) return u; return 0; } void inverse(long n, long p, long **m, long **X) { int found; long d, i, j, k, l, sum, temp; long **B = create_square_matrix(n); long *c = calloc(n, sizeof(long)); if (!c) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from inverse\n"); exit(1); } for (i = 0; i < n; i++) B[i][i] = 1; for (j = 0; j < n; j++) { found = 0; for (i = j; i < n && !found;) { found = m[i][j] != 0 && inv(m[i][j], p) != 0; if (!found) i++; } if (!found) { fprintf(stderr, "fatal error\nnon-invertible matrix\n"); fprintf(stderr, "from inverse\n", j); exit(1); } if (i > j) { for (l = j; l < n; l++) { temp = m[i][l]; m[i][l] = m[j][l]; m[j][l] = temp; } for (l = 0; l < n; l++) { temp = B[i][l]; B[i][l] = B[j][l]; B[j][l] = temp; } } d = inv(m[j][j], p); for (k = j + 1; k < n; k++) c[k] = (d * m[k][j]) % p; for (k = j + 1; k < n; k++) { for (l = j + 1; l < n; l++) { m[k][l] -= (c[k] * m[j][l]) % p; m[k][l] %= p; if (m[k][l] < 0) m[k][l] += p; } } for (k = j + 1; k < n; k++) { for (l = 0; l < n; l++) { B[k][l] -= (c[k] * B[j][l]) % p; B[k][l] %= p; if (B[k][l] < 0) B[k][l] += p; } } } for (i = n - 1; i >= 0; i--) { for (j = 0; j < n; j++) { sum = 0; for (k = i + 1; k < n; k++) sum += m[i][k] * X[k][j]; X[i][j] = inv(m[i][i], p) * (B[i][j] - sum); X[i][j] %= p; if (X[i][j] < 0) X[i][j] += p; } } delete_matrix(n, B); free(c); } void print_square_matrix(long n, long **a) { long i, j; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) printf("%ld ", a[i][j]); printf("\n"); } } void square_matrix_multiply(long n, long p, long **a, long **b, long **c) { long i, j, k, sum; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { sum = 0; for (k = 0; k < n; k++) sum += a[i][k] * b[k][j]; c[i][j] = sum % p; } } } int main(void) { long a[5][5] = {{1, 2, 3, 4, 5}, {6, 1, 2, 3, 4}, {5, 6, 1, 2, 3}, {4, 5, 6, 1, 2}, {3, 4, 5, 6, 1}}; long i, j, n = 5, p = 7; long **c = create_square_matrix(5); long **e = create_square_matrix(5); long **m = create_square_matrix(5); long **X = create_square_matrix(5); for (i = 0; i < n; i++) for (j = 0; j < n; j++) c[i][j] = m[i][j] = a[i][j]; printf("the original matrix is as follows:\n"); print_square_matrix(n, c); inverse(n, p, m, X); printf("the inverse of the matrix is as follows:\n"); print_square_matrix(n, X); square_matrix_multiply(n, p, c, X, e); printf("the product of the previous matrices is as follows:\n"); print_square_matrix(n, e); delete_matrix(n, c); delete_matrix(n, e); delete_matrix(n, m); delete_matrix(n, X); return 0; }