// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code // availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the // terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. #include "mfem.hpp" #include "catch.hpp" using namespace mfem; TEST_CASE("DenseMatrix LinearSolve methods", "[DenseMatrix]") { SECTION("singular_system") { constexpr int N = 3; DenseMatrix A(N); A.SetRow(0, 0.0); A.SetRow(1, 0.0); A.SetRow(2, 0.0); double X[3]; REQUIRE_FALSE(LinearSolve(A,X)); } SECTION("1x1_system") { constexpr int N = 1; DenseMatrix A(N); A(0,0) = 2; double X[1] = { 12 }; REQUIRE(LinearSolve(A,X)); REQUIRE(X[0] == Approx(6)); } SECTION("2x2_system") { constexpr int N = 2; DenseMatrix A(N); A(0,0) = 2.0; A(0,1) = 1.0; A(1,0) = 3.0; A(1,1) = 4.0; double X[2] = { 1, 14 }; REQUIRE(LinearSolve(A,X)); REQUIRE(X[0] == Approx(-2)); REQUIRE(X[1] == Approx(5)); } SECTION("3x3_system") { constexpr int N = 3; DenseMatrix A(N); A(0,0) = 4; A(0,1) = 5; A(0,2) = -2; A(1,0) = 7; A(1,1) = -1; A(1,2) = 2; A(2,0) = 3; A(2,1) = 1; A(2,2) = 4; double X[3] = { -14, 42, 28 }; REQUIRE(LinearSolve(A,X)); REQUIRE(X[0] == Approx(4)); REQUIRE(X[1] == Approx(-4)); REQUIRE(X[2] == Approx(5)); } } TEST_CASE("DenseMatrix A*B^T methods", "[DenseMatrix]") { double tol = 1e-12; double AtData[6] = {6.0, 5.0, 4.0, 3.0, 2.0, 1.0 }; double BtData[12] = {1.0, 3.0, 5.0, 7.0, 2.0, 4.0, 6.0, 8.0, 1.0, 2.0, 3.0, 5.0 }; DenseMatrix A(AtData, 2, 3); DenseMatrix B(BtData, 4, 3); DenseMatrix C(2,4); SECTION("MultABt") { double BData[12] = {1.0, 2.0, 1.0, 3.0, 4.0, 2.0, 5.0, 6.0, 3.0, 7.0, 8.0, 5.0 }; DenseMatrix Bt(BData, 3, 4); double CtData[8] = {16.0, 12.0, 38.0, 29.0, 60.0, 46.0, 84.0, 64.0 }; DenseMatrix Cexact(CtData, 2, 4); MultABt(A, B, C); C.Add(-1.0, Cexact); REQUIRE(C.MaxMaxNorm() < tol); Mult(A, Bt, Cexact); MultABt(A, B, C); C.Add(-1.0, Cexact); REQUIRE(C.MaxMaxNorm() < tol); } SECTION("MultADBt") { double DData[3] = {11.0, 7.0, 5.0}; Vector D(DData, 3); double CtData[8] = {132.0, 102.0, 330.0, 259.0, 528.0, 416.0, 736.0, 578.0 }; DenseMatrix Cexact(CtData, 2, 4); MultADBt(A, D, B, C); C.Add(-1.0, Cexact); REQUIRE(C.MaxMaxNorm() < tol); } SECTION("AddMultABt") { double CtData[8] = {17.0, 17.0, 40.0, 35.0, 63.0, 53.0, 88.0, 72.0 }; DenseMatrix Cexact(CtData, 2, 4); C(0, 0) = 1.0; C(0, 1) = 2.0; C(0, 2) = 3.0; C(0, 3) = 4.0; C(1, 0) = 5.0; C(1, 1) = 6.0; C(1, 2) = 7.0; C(1, 3) = 8.0; AddMultABt(A, B, C); C.Add(-1.0, Cexact); REQUIRE(C.MaxMaxNorm() < tol); MultABt(A, B, C); C *= -1.0; AddMultABt(A, B, C); REQUIRE(C.MaxMaxNorm() < tol); } SECTION("AddMultADBt") { double DData[3] = {11.0, 7.0, 5.0}; Vector D(DData, 3); double CtData[8] = {133.0, 107.0, 332.0, 265.0, 531.0, 423.0, 740.0, 586.0 }; DenseMatrix Cexact(CtData, 2, 4); C(0, 0) = 1.0; C(0, 1) = 2.0; C(0, 2) = 3.0; C(0, 3) = 4.0; C(1, 0) = 5.0; C(1, 1) = 6.0; C(1, 2) = 7.0; C(1, 3) = 8.0; AddMultADBt(A, D, B, C); C.Add(-1.0, Cexact); REQUIRE(C.MaxMaxNorm() < tol); MultADBt(A, D, B, C); C *= -1.0; AddMultADBt(A, D, B, C); REQUIRE(C.MaxMaxNorm() < tol); DData[0] = 1.0; DData[1] = 1.0; DData[2] = 1.0; MultABt(A, B, C); C *= -1.0; AddMultADBt(A, D, B, C); REQUIRE(C.MaxMaxNorm() < tol); } SECTION("AddMult_a_ABt") { double a = 3.0; double CtData[8] = { 49.0, 41.0, 116.0, 93.0, 183.0, 145.0, 256.0, 200.0 }; DenseMatrix Cexact(CtData, 2, 4); C(0, 0) = 1.0; C(0, 1) = 2.0; C(0, 2) = 3.0; C(0, 3) = 4.0; C(1, 0) = 5.0; C(1, 1) = 6.0; C(1, 2) = 7.0; C(1, 3) = 8.0; AddMult_a_ABt(a, A, B, C); C.Add(-1.0, Cexact); REQUIRE(C.MaxMaxNorm() < tol); MultABt(A, B, C); AddMult_a_ABt(-1.0, A, B, C); REQUIRE(C.MaxMaxNorm() < tol); } } TEST_CASE("LUFactors RightSolve", "[DenseMatrix]") { double tol = 1e-12; // Zero on diagonal forces non-trivial pivot double AData[9] = { 0.0, 0.0, 3.0, 2.0, 2.0, 2.0, 2.0, 0.0, 4.0 }; double BData[6] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 }; int ipiv[3]; DenseMatrix A(AData, 3, 3); DenseMatrix B(BData, 2, 3); DenseMatrixInverse Af1(A); DenseMatrix Ainv; Af1.GetInverseMatrix(Ainv); LUFactors Af2(AData, ipiv); Af2.Factor(3); DenseMatrix C(2,3); Mult(B, Ainv, C); Af2.RightSolve(3, 2, B.GetData()); C -= B; REQUIRE(C.MaxMaxNorm() < tol); }