MyraMath
rldlt2_schur


Source: tests/multifrontal/rldlt/rldlt2_schur.cpp

1 // ========================================================================= //
2 // This file is part of MyraMath, copyright (c) 2014-2019 by Ryan A Chilton //
3 // and distributed by MyraCore, LLC. See LICENSE.txt for license terms. //
4 // ========================================================================= //
5 
11 // Containers.
14 #include <myramath/dense/Matrix.h>
22 
23 // Algorithms.
26 #include <myramath/dense/dot.h>
27 #include <myramath/dense/gemm.h>
28 #include <myramath/dense/inverse.h>
31 
32 // Solver under test.
34 
35 // Reporting.
36 #include <tests/myratest.h>
37 
38 using namespace myra;
39 
40 namespace {
41 
42 // Generates random row indices.
43 std::vector<int> random_rows(int I, int N)
44  {
45  std::vector<int> answer;
46  for (int n = 0; n < N; ++n)
47  answer.push_back( random_int(0,I) );
48  sortunique(answer);
49  return answer;
50  }
51 
52 // Fills SparseMatrix B from (Bi,Bv) data.
53 template<class Number> SparseMatrix<Number> fill(int I, const std::vector<int>& Bi, const Matrix<Number>& Bv)
54  {
55  int J = Bv.size().second;
56  SparseMatrixBuilder<Number> B_builder(I,J);
57  for (int j = 0; j < J; ++j)
58  for (int i = 0; i < Bi.size(); ++i)
59  B_builder(Bi[i],j) = Bv(i,j);
60  return B_builder.make_SparseMatrix();
61  }
62 
63 // Various schur() tests.
64 template<class Precision> void test(Precision tolerance)
65  {
66  int I = 20;
67  int J = 25;
68  int N = I*J;
69  int K = 23;
70  int K1 = K-1;
71  int K2 = K+1;
72 
73  // Generate A.
74  SparseMatrix<Precision> A = laplacian2<Precision>(I,J);
75  Precision shift = 5.5;
76  for (int n = 0; n < N; ++n)
77  A(n,n) -= shift;
78 
79  // Options related to reordering.
80  typedef multifrontal::Options Options;
81  Options options = Options::create().set_blocksize(4).set_globsize(4).set_nthreads(4);
82 
83  // Reorder A using bisection and factor it.
84  Permutation perm = bisect2(I,J);
85  SparseRLDLTSolver<Precision> solver(A,perm,options);
86 
87  // Testing symmetric sparse schur complement.
88  {
89  // Generate B, generate a schur complement B'*inv(A)*B
90  auto B = SparseMatrix<Precision>::random(N,K,3*N);
91  LowerMatrix<Precision> S1 = solver.schur(B,options);
92  // Compare to reference/dense calculation.
93  Matrix<Precision> S2 = gemm(B.make_Matrix(),'T',gemm(inverse(A.make_Matrix()),B.make_Matrix()));
94  Precision S_error = frobenius(S1.make_Matrix('T')-S2)/frobenius(S2);
95  myra::out() << "|B'*inv(A)*B [dense] - B'*inv(A)*B [sparse]| = " << S_error << std::endl;
96  REQUIRE(S_error < tolerance);
97  }
98 
99  // Testing symmetric restricted schur complement.
100  {
101  // Compute a symmetric schur complement Bv'*Bi'*inv(A)*Bi*Bv
102  auto Bi = random_rows(N,10);
103  auto Bv = Matrix<Precision>::random(ssize(Bi),K);
104  auto B = fill(N,Bi,Bv);
105  auto S1 = solver.schur(Bi,Bv,options);
106  // Compare to reference/dense calculation.
107  auto S2 = gemm(B.make_Matrix(),'T',gemm(inverse(A.make_Matrix()),B.make_Matrix()));
108  Precision S_error = frobenius(S1.make_Matrix('T')-S2)/frobenius(S2);
109  myra::out() << "|schur(B)-schur(BiBv)| = " << S_error << std::endl;
110  REQUIRE(S_error < tolerance);
111  }
112 
113  // Testing symmetric schur complement by a dense Vector, exercises write race resolution.
114  {
115  // Compute a symmetric schur complement Bv'*Bi'*inv(A)*Bi*Bv
116  auto Bi = ilinspace(0,N);
117  auto Bv = Matrix<Precision>::random(N,1);
118  Precision S1 = solver.schur(Bi,Bv,options)(0,0);
119  // Compare to reference/dense calculation.
120  solver.solveL(Bv);
121  auto Cv = Bv;
122  solver.solveD(Bv);
123  Precision S2 = dot(Cv.vector(0),Bv.vector(0));
124  Precision S_error = std::abs(S1-S2)/std::abs(S2);
125  myra::out() << "|schur(Bi,Bv)-dot(L\\Bv,L\\Bv))| = " << S_error << std::endl;
126  REQUIRE(S_error < tolerance);
127  }
128 
129  // Testing nonsymmetric schur complement.
130  {
131  // Generate C/D, compute schur complement C'*inv(A)*D
132  auto C = SparseMatrix<Precision>::random(N,K1,5*N);
133  auto D = SparseMatrix<Precision>::random(N,K2,4*N);
134  Matrix<Precision> S1 = solver.schur(C,D,options);
135  // Compare to reference/dense calculation.
136  Matrix<Precision> S2 = gemm(C.make_Matrix(),'T',gemm(inverse(A.make_Matrix()),D.make_Matrix()));
137  Precision S_error = frobenius(S1-S2)/frobenius(S2);
138  myra::out() << "|C'*inv(A)*D [dense] - C'*inv(A)*D [sparse]| = " << S_error << std::endl;
139  REQUIRE(S_error < tolerance);
140  }
141 
142  // Testing unsymmetric restricted schur complement.
143  {
144  // Compute a symmetric schur complement Bv'*Bi'*inv(A)*Ci*Cv
145  auto Bi = random_rows(N,10);
146  auto Bv = Matrix<Precision>::random(ssize(Bi),K1);
147  auto Ci = random_rows(N,10);
148  auto Cv = Matrix<Precision>::random(ssize(Ci),K2);
149  auto S1 = solver.schur(Bi,Bv,Ci,Cv,options);
150  // Compare to reference/dense calculation.
151  auto B = fill(N,Bi,Bv);
152  auto C = fill(N,Ci,Cv);
153  auto S2 = gemm(B.make_Matrix(),'T',gemm(inverse(A.make_Matrix()),C.make_Matrix()));
154  Precision S_error = frobenius(S1-S2)/frobenius(S2);
155  myra::out() << "|schur(B,C)-schur(BiBv,CiCv)| = " << S_error << std::endl;
156  REQUIRE(S_error < tolerance);
157  }
158 
159  // Testing unsymmetric schur complement by a dense Vector, exercises write race resolution.
160  {
161  auto Bi = ilinspace(0,N);
162  auto Bv = Matrix<Precision>::random(N,1);
163  auto Ci = ilinspace(0,N);
164  auto Cv = Matrix<Precision>::random(N,1);
165  Precision S1 = solver.schur(Bi,Bv,Ci,Cv,options)(0,0);
166  // Compare to reference/dense calculation.
167  solver.solveL(Bv);
168  solver.solveL(Cv);
169  solver.solveD(Cv);
170  Precision S2 = dot(Bv.vector(0),Cv.vector(0));
171  Precision S_error = std::abs(S1-S2)/std::abs(S2);
172  myra::out() << "|schur(Bi,Bv)-dot(L\\Bv,L\\Bv))| = " << S_error << std::endl;
173  REQUIRE(S_error < tolerance);
174  }
175 
176  }
177 
178 } // namespace
179 
180 
181 ADD_TEST("rldlt2_schur","[multifrontal][parallel]")
182  {
183  test<double>(1.0e-8);
184  }
Interface class for representing subranges of dense Matrix&#39;s.
Options pack for routines in /multifrontal.
Definition: Options.h:24
Represents a Permutation matrix, used to reorder rows/columns/etc of various numeric containers...
Definition: Permutation.h:34
Tabulates an IxJ matrix. Allows random access, has column major layout to be compatible with BLAS/LAP...
Definition: bdsqr.h:20
Matrix< Number > make_Matrix(char op='N') const
Accumulates *this onto the lower triangle of a Matrix<Number>
Definition: LowerMatrix.cpp:152
Routines for computing Frobenius norms of various algebraic containers.
static Matrix< Number > random(int I, int J)
Generates a random Matrix of specified size.
Definition: Matrix.cpp:353
Sparse direct solver suitable for real symmetric indefinite systems.
Definition: SparseRLDLTSolver.h:61
static SparseMatrix< Number > random(int I, int J, int N)
Generates a random SparseMatrix with size IxJ and (approximately) N nonzeros.
Definition: SparseMatrix.cpp:493
Reduces a std::vector to its unique entries, and sorts it.
General purpose compressed-sparse-column (CSC) container.
Range construct for a lower triangular matrix stored in rectangular packed format.
void sortunique(std::vector< T > &v)
Reduces a std::vector to its unique entries, and sorts it.
Definition: sortunique.h:20
Definition: syntax.dox:1
Specialized container for a lower triangular matrix, O(N^2/2) storage. Used by symmetry exploiting ma...
Routines for inner products of Vector&#39;s / VectorRange&#39;s.
Various utility functions/classes related to scalar Number types.
Returns a vector of int&#39;s, over [min,max)
General purpose dense matrix container, O(i*j) storage.
Overwrites a LowerMatrix, DiagonalMatrix, or square Matrix with its own inverse. Or, returns it as a copy.
Aggregates a (perm, iperm, swaps) triple into a vocabulary type.
Convenience type for building SparseMatrix&#39;s, uses coordinate/triplet format.
Definition: SparseMatrix.h:32
std::pair< int, int > size() const
Size inspector.
Definition: Matrix.cpp:116
Convenience type for building SparseMatrix&#39;s, uses coordinate/triplet format. Note that SparseMatrixB...
CVectorRange< Number > vector(int j) const
Returns the j&#39;th column as a VectorRange.
Definition: Matrix.cpp:154
Sparse direct solver suitable for real symmetric indefinite systems.
Stores an IxJ matrix A in compressed sparse column format.
Definition: bothcat.h:23
Helper routines for reordering/filling 2D structured grids. Used by many unit tests.
Variety of routines all for dense Matrix*Matrix multiplies. Delegates to the BLAS.
Range/Iterator types associated with SparseMatrix.
Matrix< Number > make_Matrix() const
Accumulates *this onto a Matrix<Number>.
Definition: SparseMatrix.cpp:581
Interface class for representing subranges of contiguous int&#39;s.


Results: [PASS]

|B'*inv(A)*B [dense] - B'*inv(A)*B [sparse]| = 2.47397e-14
|schur(B)-schur(BiBv)| = 2.71079e-14
|schur(Bi,Bv)-dot(L\Bv,L\Bv))| = 1.11263e-14
|C'*inv(A)*D [dense] - C'*inv(A)*D [sparse]| = 2.28618e-14
|schur(B,C)-schur(BiBv,CiCv)| = 2.06378e-14
|schur(Bi,Bv)-dot(L\Bv,L\Bv))| = 1.84857e-16


Go back to Summary of /test programs.