booldelete_matrix(Matrix **pmat) { if (pmat == NULL) { print_error("NULL pointer exception", "The address of the pointer to the matrix is null, delete process interrupted."); returnfalse; } if ((*pmat) == NULL) { print_error("NULL pointer exception", "The pointer to the matrix is null, delete process interrupted."); returnfalse; } free((*pmat)->data); free(*pmat); *pmat = NULL; returntrue; }
boolcopy_matrix(Matrix **dest, Matrix *src) { if (src == NULL) { print_error("NULL pointer exception", "The pointer to source matrix is null, copy process interrupted."); returnfalse; } if (*dest == NULL) { *dest = create_copy(src); if (*dest == NULL) { returnfalse; } print_warning("Copy into null matrix", "The pointer to destination matrix is null, the pointer will point to a copy matrix of source matrix."); } else { if (((*dest)->row != src->row) || ((*dest)->col != src->col)) { print_warning("Copy into matrix of different sizes", "The sizes of two matrices are different, the data of destination matrix will be covered by source matrix."); } delete_matrix(dest); *dest = create_copy(src); if (*dest == NULL) { returnfalse; } } returntrue; }
boolref_matrix(Matrix **dest, Matrix *src) { if (src == NULL) { print_error("NULL pointer exception", "The pointer to source matrix is null, copy process interrupted."); returnfalse; } if(*dest!=NULL) { delete_matrix(dest); } *dest = src; returntrue; }
TYPE extreme_value(Matrix *src, bool (*cmp)(TYPE, TYPE)) { if (src == NULL) { print_error("NULL pointer exception", "The pointer to source matrix is null, return NaN."); return nanf(""); } TYPE ans = src->data[0]; for (size_t i = 1; i < size_of(src); i++) { if (cmp(src->data[i], ans)) { ans = src->data[i]; } } return ans; }
Matrix *binary_calc(Matrix *first, Matrix *second, TYPE (*fun)(TYPE, TYPE)) { if (first == NULL) { print_error("NULL pointer exception", "The pointer to the first matrix is null, calculation interrupted."); returnNULL; } if (second == NULL) { print_error("NULL pointer exception", "The pointer to the second matrix is null, calculation interrupted."); returnNULL; } if (first->row != second->row || first->col != second->col) { print_error("Illegal matrix shape", "The shape of two matrices are different, calculation process interrupted."); returnNULL; } Matrix *new = create_copy(first);
for (size_t i = 0; i < size_of(new); i++) { new->data[i] = fun(new->data[i], second->data[i]); } return new; }
Matrix *matrix_pow(Matrix *base, int power) { if (base == NULL) { print_error("NULL pointer exception", "The pointer to base matrix is null, power process interrupted."); returnNULL; } if (power == 1) { return create_copy(base); } if (base->row != base->col) { print_error("Illegal matrix shape", "The base matrix should be square matrix."); returnNULL; } if (power == 0) { return create_identity(base->row); } Matrix *new; if (power < 0) { new = create_copy(inverse(base)); if (new == NULL) { print_error("NULL pointer exception", "The source matrix has no inverse, negative power calculation interrupted."); returnNULL; } power = -power; } else { new = create_copy(base); } Matrix *Base = create_copy(base); power--;//因为new本来就是base一次方了所以-1 while (power) { if (power & 1) { multiply_by(&new, Base); } multiply_by(&Base, Base); power >>= 1; } return new; }
实际上,矩阵的幂运算在正整数之外并没有定义,本项目中为了便利,将矩阵的幂的定义进行拓展:
若矩阵为方阵,则其0次幂为单位阵;
若矩阵为方阵且可逆,则其负数次幂为其逆的对应正数次幂。
矩阵变换
1 2 3 4 5 6 7 8
//Functions For Matrix Transformations TYPE determinant(Matrix *pmat);
Matrix *inverse(Matrix *pmat);
Matrix *transpose(Matrix *pmat);
Matrix *Uptriangular(Matrix *pmat);
本节包含矩阵专属的一些常用函数:求行列式、求逆、转置、上三角化,求行列式和求逆均依赖上三角化进行。
矩阵转置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Matrix *transpose(Matrix *pmat) { if (pmat == NULL) { print_error("NULL pointer exception", "The pointer to source matrix is null, transpose process interrupted."); returnNULL; } Matrix *new = create_empty(pmat->col, pmat->row); for (size_t i = 0; i < pmat->row; i++) { for (size_t j = 0; j < pmat->col; j++) { *(new->data + j * new->col + i) = *(pmat->data + i * pmat->col + j); } } return new; }
Matrix *inverse(Matrix *pmat) { if (pmat == NULL) { print_error("NULL pointer exception", "The pointer to source matrix is null, inverse calculation interrupted."); returnNULL; } if (pmat->row != pmat->col) { print_error("Illegal matrix shape", "The matrix should be square to have inverse, inverse calculation interrupted."); } Matrix *new = row_concat(pmat, create_identity(pmat->row)); size_t row = pmat->row; size_t col = row * 2; for (size_t i = 0; i < row; i++) { if (float_equal(new->data[i * col + i], 0.0f)) { for (size_t j = i + 1; j < row; j++) { if (!float_equal(new->data[j * col + i], 0.0f)) { for (size_t k = 0; k < col; k++) { TYPE t = new->data[i * col + k]; new->data[i * col + k] = new->data[j * col + k]; new->data[j * col + k] = t; } break; } } } if (float_equal(new->data[i * col + i], 0.0f)) { print_error("Inverse doesn't exist", "The rank of source matrix is not full, inverse calculation interrupted."); returnNULL; } for (size_t j = i + 1; j < row; j++) { TYPE t = new->data[j * col + i] / new->data[i * col + i]; for (size_t k = 0; k < col; k++) { new->data[j * col + k] -= new->data[i * col + k] * t; } } } for (size_t i = 0; i < row; i++) { TYPE u = new->data[i * col + i]; for (size_t j = 0; j < i; j++) { TYPE v = new->data[j * col + i] / u; for (size_t k = i; k < col; k++) { new->data[j * col + k] -= new->data[i * col + k] * v; } } } for (size_t i = 0; i < row; i++) { TYPE t = new->data[i * col + i]; for (size_t j = row; j < col; j++) { new->data[i * new->col + j] /= t; } } return sub_matrix(new, 1, pmat->col + 1, new->row, new->col); }
voidprint_matrix(Matrix *pmat, int precision) { if (pmat == NULL) { print_error("NULL pointer exception", "The pointer to source matrix is null, print process interrupted."); return; } if (precision < 0) { print_error("Illegal precision", "Precision should be non-negative, print process interrupted."); return; } if (precision > 6) { print_warning("Precision too large", "Float numbers are accurate to at most the 6th decimal place."); precision = 6; } for (size_t i = 0; i < pmat->row; i++) { for (size_t j = 0; j < pmat->col; j++) { if (float_equal(pmat->data[i * pmat->col + j], 0.0f)) { pmat->data[i * pmat->col + j] = 0.0f; } printf("%.*f\t", precision, pmat->data[i * pmat->col + j]); } printf("\n"); } }
boolprint_matrix_to_file(char *filename, Matrix *pmat, int precision) { FILE *file = fopen(filename, "w"); if (file == NULL) { print_error("NULL pointer exception", "The output file is not found, print to file process interrupted."); returnfalse; } if (pmat == NULL) { print_error("NULL pointer exception", "The pointer to source matrix is null, print to file process interrupted."); returnfalse; } if (precision < 0) { print_error("Illegal precision", "Precision should be non-negative, print to file process interrupted."); return; } if (precision > 6) { print_warning("Precision too large", "Float numbers are accurate to at most the 6th decimal place."); precision = 6; } for (size_t i = 0; i < pmat->row; i++) { for (size_t j = 0; j < pmat->col; j++) { if (float_equal(pmat->data[i * pmat->col + j], 0.0f)) { pmat->data[i * pmat->col + j] = 0.0f; } fprintf(file, "%.*f\t", precision, pmat->data[i * pmat->col + j]); } fprintf(file, "\n"); } fclose(file); returntrue; }
//Benchmark.c (customized compare function & main function) boolmycmp(TYPE x,TYPE y) { returnfabs(x-2.1)<fabs(y-2.1); } intmain() { Matrix *mat=create_from_file("matfile",5,5); print_matrix(mat,1); printf("The max value is %.1f\nThe min value is %.1f\n",max(mat),min(mat)); printf("The value closest to 2.1 is %.1f\n",extreme_value(mat,mycmp)); }
//Benchmark.c (main function) intmain() { Matrix *A=create_from_file("matfile",6,6); printf("A:\n"); print_matrix(A,0); Matrix *T=transpose(A); printf("T:\n"); print_matrix(T,0); printf("The rank of A is: %d\nThe rank of T is: %d\n",rank(A),rank(T)); }