int main(void) { FILE *fin = fopen( "matrix2.in", "r" ); if( fin == NULL ) { printf( "Error: could not open matrix2.in\n" ); exit( EXIT_FAILURE ); } Matrix *a = read_matrix( fin ); Matrix *b = read_matrix( fin ); fclose( fin ); Matrix *c = product_matrix( a, b ); FILE *output = fopen( "matrix2.out", "w" ); if( output == NULL ) { printf( "Error: could not open matrix2.out\n" ); exit( EXIT_FAILURE ); } print_matrix( output, c ); fclose( output ); destroy_matrix( a ); destroy_matrix( b ); destroy_matrix( c ); return 0; }
int main() { int N, size; double *array1, *array2, *array3; printf("Please input the size of the matrix:"); scanf("%d", &N); size=N*N; array1=(double *) malloc(size*sizeof(double)); array2=(double *) malloc(size*sizeof(double)); array3=(double *) malloc(N*sizeof(double)); input_matrix(size, N, array1, array2); output_matrix(size, N, array1, array2); product_matrix(size, N, array1, array2, array3); }
/*!\rst Check that matrix-transpose works. \return number of entries where ``A`` and ``A^T`` do not match \endrst*/ OL_WARN_UNUSED_RESULT int TestMatrixTranspose() noexcept { const int size_m = 3; const int size_n = 5; int total_errors = 0; std::vector<double> matrix(size_m*size_n); std::vector<double> matrix_T(size_m*size_n); std::vector<double> product_matrix(size_n*size_n); UniformRandomGenerator uniform_generator(34187); BuildRandomVector(size_m*size_n, -1.0, 1.0, &uniform_generator, matrix.data()); MatrixTranspose(matrix.data(), size_m, size_n, matrix_T.data()); for (int j = 0; j < size_n; ++j) { for (int i = 0; i < size_m; ++i) { if (CheckDoubleWithin(matrix[j*size_m + i], matrix_T[i*size_n + j], 0.0) == false) { ++total_errors; break; } } } return total_errors; }
/*!\rst Check that ``A * B`` works where ``A, B`` are matrices. Outline: 1. Simple hand-checked test case. 2. Generate a random orthogonal matrix and verify that ``Q * Q^T = I``. 3. Generate a random SPD matrix and guarantee good conditioning: verify ``A * A^-1 = I``. \return number of cases where matrix-matrix multiply failed \endrst*/ OL_WARN_UNUSED_RESULT int TestGeneralMatrixMatrixMultiply() noexcept { int total_errors = 0; // simple, hand-checked problems that are be minimally affected by floating point errors { // hide scope static const int kSize_m = 3; // rows of A, C static const int kSize_k = 5; // cols of A, rows of B static const int kSize_n = 2; // cols of B, C double matrix_A[kSize_m*kSize_k] = {-7.4, 0.1, 9.1, // first COLUMN of A (col-major storage) 1.5, -8.8, -0.3, -2.9, 6.4, -9.7, -9.1, -6.6, 3.1, 4.6, 3.0, -1.0 }; double matrix_B[kSize_k*kSize_n] = {-1.3, -8.1, -7.2, -0.4, -5.5, 7.4, 5.3, -3.1, -2.3, 1.9 }; double matrix_AB_exact[kSize_m*kSize_n] = {-3.309999999999995, 11.210000000000001, 64.700000000000003, -8.150000000000006, -44.860000000000014, 86.789999999999992 }; double matrix_AB_computed[kSize_m*kSize_n]; GeneralMatrixMatrixMultiply(matrix_A, 'N', matrix_B, 1.0, 0.0, kSize_m, kSize_k, kSize_n, matrix_AB_computed); for (int i = 0; i < kSize_m*kSize_n; ++i) { if (!CheckDoubleWithinRelative(matrix_AB_computed[i], matrix_AB_exact[i], 3.0 * std::numeric_limits<double>::epsilon())) { ++total_errors; } } } const int num_tests = 3; const int sizes[num_tests] = {3, 11, 20}; UniformRandomGenerator uniform_generator(34187); // in each iteration, we perform two tests on matrix-matrix multiply. // 1) form a matrix Q such that Q * Q^T = I (orthogonal matrix); nontrivial in that Q != I // Compute Q * Q^T and check the result. // 2) build a random, SPD matrix, A. (ill-conditioned). // Improve A's conditioning: A = A + size*I (condition number near 1 now) // Form A^-1 (this is OK because A is well-conditioned) // Check A * A^-1 is near I. for (int i = 0; i < num_tests; ++i) { std::vector<double> orthog_symm_matrix(sizes[i]*sizes[i]); std::vector<double> orthog_symm_matrix_T(sizes[i]*sizes[i]); std::vector<double> product_matrix(sizes[i]*sizes[i]); std::vector<double> spd_matrix(sizes[i]*sizes[i]); std::vector<double> cholesky_factor(sizes[i]*sizes[i]); std::vector<double> inverse_spd_matrix(sizes[i]*sizes[i]); std::vector<double> identity_matrix(sizes[i]*sizes[i]); BuildIdentityMatrix(sizes[i], identity_matrix.data()); BuildOrthogonalSymmetricMatrix(sizes[i], orthog_symm_matrix.data()); // not technically necessary since this orthog matrix is also symmetric MatrixTranspose(orthog_symm_matrix.data(), sizes[i], sizes[i], orthog_symm_matrix_T.data()); // Q * Q^T = I if Q is orthogonal GeneralMatrixMatrixMultiply(orthog_symm_matrix.data(), 'N', orthog_symm_matrix_T.data(), 1.0, 0.0, sizes[i], sizes[i], sizes[i], product_matrix.data()); VectorAXPY(sizes[i]*sizes[i], -1.0, identity_matrix.data(), product_matrix.data()); for (int j = 0; j < sizes[i]*sizes[i]; ++j) { // do not use relative comparison b/c we're testing against 0 if (!CheckDoubleWithin(product_matrix[j], 0.0, 20*std::numeric_limits<double>::epsilon())) { ++total_errors; } } // and again testing the T version GeneralMatrixMatrixMultiply(orthog_symm_matrix.data(), 'T', orthog_symm_matrix.data(), 1.0, 0.0, sizes[i], sizes[i], sizes[i], product_matrix.data()); VectorAXPY(sizes[i]*sizes[i], -1.0, identity_matrix.data(), product_matrix.data()); for (int j = 0; j < sizes[i]*sizes[i]; ++j) { // do not use relative comparison b/c we're testing against 0 if (!CheckDoubleWithin(product_matrix[j], 0.0, 20*std::numeric_limits<double>::epsilon())) { ++total_errors; } } BuildRandomSPDMatrix(sizes[i], &uniform_generator, spd_matrix.data()); // ensure spd matrix is well-conditioned (or we can't form A^-1 stably) ModifyMatrixDiagonal(sizes[i], static_cast<double>(sizes[i]), spd_matrix.data()); std::copy(spd_matrix.begin(), spd_matrix.end(), cholesky_factor.begin()); if (ComputeCholeskyFactorL(sizes[i], cholesky_factor.data()) != 0) { ++total_errors; } SPDMatrixInverse(cholesky_factor.data(), sizes[i], inverse_spd_matrix.data()); GeneralMatrixMatrixMultiply(spd_matrix.data(), 'N', inverse_spd_matrix.data(), 1.0, 0.0, sizes[i], sizes[i], sizes[i], product_matrix.data()); VectorAXPY(sizes[i]*sizes[i], -1.0, identity_matrix.data(), product_matrix.data()); for (int j = 0; j < sizes[i]*sizes[i]; ++j) { // do not use relative comparison b/c we're testing against 0 if (!CheckDoubleWithin(product_matrix[j], 0.0, 10*std::numeric_limits<double>::epsilon())) { ++total_errors; } } } return total_errors; }