Exemplo n.º 1
0
 DLLEXPORT lapack_int z_cholesky_factor(lapack_int n, lapack_complex_double a[])
 {
     return cholesky_factor(n, a, LAPACK_zpotrf);
 }
Exemplo n.º 2
0
 DLLEXPORT lapack_int d_cholesky_factor(lapack_int n, double* a)
 {
     return cholesky_factor(n, a, LAPACK_dpotrf);
 }
Exemplo n.º 3
0
 DLLEXPORT lapack_int c_cholesky_factor(lapack_int n, lapack_complex_float a[])
 {
     return cholesky_factor(n, a, LAPACK_cpotrf);
 }
Exemplo n.º 4
0
 DLLEXPORT MKL_INT z_cholesky_factor(MKL_INT n, MKL_Complex16 a[])
 {
     return cholesky_factor(n, a, zpotrf);
 }
Exemplo n.º 5
0
 DLLEXPORT lapack_int s_cholesky_factor(lapack_int n, float a[])
 {
     return cholesky_factor(n, a, LAPACK_spotrf);
 }
Exemplo n.º 6
0
 DLLEXPORT MKL_INT c_cholesky_factor(MKL_INT n, MKL_Complex8 a[])
 {
     return cholesky_factor(n, a, cpotrf);
 }
Exemplo n.º 7
0
 DLLEXPORT MKL_INT d_cholesky_factor(MKL_INT n, double* a)
 {
     return cholesky_factor(n, a, dpotrf);
 }
Exemplo n.º 8
0
 DLLEXPORT MKL_INT s_cholesky_factor(MKL_INT n, float a[])
 {
     return cholesky_factor(n, a, spotrf);
 }
Exemplo n.º 9
0
/*!\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;
}
Exemplo n.º 10
0
/*!\rst
  Test that SPDMatrixInverse and CholeskyFactorLMatrixVectorSolve are  working correctly
  against some especially bad named matrices and some random inputs.
  Outline:

  1. Construct matrices, ``A``
  2. Select a solution, ``x``, randomly.
  3. Construct RHS by doing ``A*x``.
  4. Solve ``Ax = b`` using backsolve and direct-inverse; check the size of ``\|b - Ax\|``.

  \return
    number of test cases where the solver error is too large
\endrst*/
OL_WARN_UNUSED_RESULT int TestSPDLinearSolvers() {
  int total_errors = 0;

  // simple/small case where numerical factors are not present.
  // taken from: http://en.wikipedia.org/wiki/Cholesky_decomposition#Example
  {
    constexpr int size = 3;
    std::vector<double> matrix =
        {  4.0,   12.0, -16.0,
          12.0,   37.0, -43.0,
         -16.0,  -43.0,  98.0};

    const std::vector<double> cholesky_factor_L_truth =
        { 2.0, 6.0, -8.0,
          0.0, 1.0, 5.0,
          0.0, 0.0, 3.0};
    std::vector<double> rhs = {-20.0, -43.0, 192.0};
    std::vector<double> solution_truth = {1.0, 2.0, 3.0};

    int local_errors = 0;
    // check factorization is correct; only check lower-triangle
    if (ComputeCholeskyFactorL(size, matrix.data()) != 0) {
      ++total_errors;
    }
    for (int i = 0; i < size; ++i) {
      for (int j = 0; j < size; ++j) {
        if (j >= i) {
          if (!CheckDoubleWithinRelative(matrix[i*size + j], cholesky_factor_L_truth[i*size + j], 0.0)) {
            ++local_errors;
          }
        }
      }
    }

    // check the solve is correct
    CholeskyFactorLMatrixVectorSolve(matrix.data(), size, rhs.data());
    for (int i = 0; i < size; ++i) {
      if (!CheckDoubleWithinRelative(rhs[i], solution_truth[i], 0.0)) {
        ++local_errors;
      }
    }

    total_errors += local_errors;
  }

  const int num_tests = 10;
  const int num_test_sizes = 3;
  const int sizes[num_test_sizes] = {5, 11, 20};

  // following tolerances are based on numerical experiments and/or computations
  // of the matrix condition numbers (in MATLAB)
  const double tolerance_backsolve_max_list[3][num_test_sizes] =
      { {10*std::numeric_limits<double>::epsilon(), 100*std::numeric_limits<double>::epsilon(), 100*std::numeric_limits<double>::epsilon()},       // prolate
        {100*std::numeric_limits<double>::epsilon(), 1.0e4*std::numeric_limits<double>::epsilon(), 1.0e6*std::numeric_limits<double>::epsilon()},  // moler
        {50*std::numeric_limits<double>::epsilon(), 1.0e3*std::numeric_limits<double>::epsilon(), 5.0e4*std::numeric_limits<double>::epsilon()}    // random
      };
  const double tolerance_inverse_max_list[3][num_test_sizes] =
      { {1.0e-13, 1.0e-9, 1.0e-2},  // prolate
        {5.0e-13, 2.0e-8, 1.0e1},   // moler
        {7.0e-10, 7.0e-6, 1.0e2}    // random
      };

  UniformRandomGenerator uniform_generator(34187);
  // In each iteration, we form some an ill-conditioned SPD matrix.  We are using
  // prolate, moler, and random matrices.
  // Then we compute L * L^T = A.
  // We want to test solutions of A * x = b using two methods:
  //   1) Inverse: using L, we form A^-1 explicitly (ILL-CONDITIONED!)
  //   2) Backsolve: we never form A^-1, but instead backsolve L and L^T against b.
  // The resulting residual norms, ||b - A*x||_2 are computed; we check that
  // backsolve is accurate and inverse is affected strongly by conditioning.
  for (int j = 0; j < num_tests; ++j) {
    for (int i = 0; i < num_test_sizes; ++i) {
      std::vector<double> matrix(sizes[i]*sizes[i]);
      std::vector<double> inverse_matrix(sizes[i]*sizes[i]);
      std::vector<double> cholesky_factor(sizes[i]*sizes[i]);
      std::vector<double> rhs(sizes[i]);
      std::vector<double> solution(2*sizes[i]);

      double tolerance_backsolve_max;
      double tolerance_inverse_max;
      switch (j) {
        case 0: {
          BuildProlateMatrix(kProlateDefaultParameter, sizes[i], matrix.data());
          tolerance_backsolve_max = tolerance_backsolve_max_list[0][i];
          tolerance_inverse_max = tolerance_inverse_max_list[0][i];
          break;
        }
        case 1: {
          BuildMolerMatrix(-1.66666666666, sizes[i], matrix.data());
          tolerance_backsolve_max = tolerance_backsolve_max_list[1][i];
          tolerance_inverse_max = tolerance_inverse_max_list[1][i];
          break;
        }
        default: {
          if (j <= 1 || j > num_tests) {
            OL_THROW_EXCEPTION(BoundsException<int>, "Invalid switch option.", j, 2, num_tests);
          } else {
            BuildRandomSPDMatrix(sizes[i], &uniform_generator, matrix.data());
            tolerance_backsolve_max = tolerance_backsolve_max_list[2][i];
            tolerance_inverse_max = tolerance_inverse_max_list[2][i];
            break;
          }
        }
      }
      // cholesky-factor A, form A^-1
      std::copy(matrix.begin(), matrix.end(), cholesky_factor.begin());
      if (ComputeCholeskyFactorL(sizes[i], cholesky_factor.data()) != 0) {
        ++total_errors;
      }
      SPDMatrixInverse(cholesky_factor.data(), sizes[i], inverse_matrix.data());

      // set b = A*random_vector.  This way we know the solution explicitly.
      // this also allows us to ignore ||A|| in our computations when we
      // normalize the RHS.
      BuildRandomVector(sizes[i], 0.0, 1.0, &uniform_generator, solution.data());
      SymmetricMatrixVectorMultiply(matrix.data(), solution.data(), sizes[i], rhs.data());

      // re-scale the RHS so that its norm can be ignored in later computations
      double rhs_norm = VectorNorm(rhs.data(), sizes[i]);
      VectorScale(sizes[i], 1.0/rhs_norm, rhs.data());
      std::copy(rhs.begin(), rhs.end(), solution.begin());

      // Solve L * L^T * x1 = b (backsolve) and compute x2 = A^-1 * b
      CholeskyFactorLMatrixVectorSolve(cholesky_factor.data(), sizes[i], solution.data());
      SymmetricMatrixVectorMultiply(inverse_matrix.data(), rhs.data(), sizes[i], solution.data() + sizes[i]);

      double norm_residual_via_backsolve = ResidualNorm(matrix.data(), solution.data(), rhs.data(), sizes[i]);
      double norm_residual_via_inverse = ResidualNorm(matrix.data(), solution.data() + sizes[i], rhs.data(), sizes[i]);

      if (norm_residual_via_backsolve > tolerance_backsolve_max) {
        ++total_errors;
        OL_ERROR_PRINTF("experiment %d, size[%d] = %d, norm_backsolve = %.18E > %.18E = tol\n", j, i, sizes[i],
               norm_residual_via_backsolve, tolerance_backsolve_max);
      }

      if (norm_residual_via_inverse > tolerance_inverse_max) {
        ++total_errors;
        OL_ERROR_PRINTF("experiment %d, size[%d] = %d, norm_inverse = %.18E > %.18E = tol\n", j, i, sizes[i],
               norm_residual_via_inverse, tolerance_inverse_max);
      }
    }
  }

  return total_errors;
}