MyraMath
rcholesky2_schur


Source: tests/multifrontal/rcholesky/rcholesky2_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/Vector.h>
16 #include <myramath/dense/Matrix.h>
25 
26 // Algorithms.
29 #include <myramath/dense/dot.h>
30 #include <myramath/dense/gemm.h>
31 #include <myramath/dense/inverse.h>
34 
35 // Solver under test.
37 
38 // Reporting.
39 #include <tests/myratest.h>
40 
41 using namespace myra;
42 
43 namespace {
44 
45 // Generates random row indices.
46 std::vector<int> random_rows(int I, int N)
47  {
48  std::vector<int> answer;
49  for (int n = 0; n < N; ++n)
50  answer.push_back( random_int(0,I) );
51  sortunique(answer);
52  return answer;
53  }
54 
55 // Fills SparseMatrix B from (Bi,Bv) data.
56 template<class Number> SparseMatrix<Number> fill(int I, const std::vector<int>& Bi, const Matrix<Number>& Bv)
57  {
58  int J = Bv.size().second;
59  SparseMatrixBuilder<Number> B_builder(I,J);
60  for (int j = 0; j < J; ++j)
61  for (int i = 0; i < Bi.size(); ++i)
62  B_builder(Bi[i],j) = Bv(i,j);
63  return B_builder.make_SparseMatrix();
64  }
65 
66 // Various schur() tests.
67 template<class Precision> void test(Precision tolerance)
68  {
69  int I = 20;
70  int J = 25;
71  int N = I*J;
72  int K = 23;
73  int K1 = K-1;
74  int K2 = K+1;
75 
76  // Generate A.
77  auto A = laplacian2<Precision>(I,J);
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  SparseRCholeskySolver<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  Precision S2 = dot(Bv.vector(0),Bv.vector(0));
122  Precision S_error = std::abs(S1-S2)/std::abs(S2);
123  myra::out() << "|schur(Bi,Bv)-dot(L\\Bv,L\\Bv))| = " << S_error << std::endl;
124  REQUIRE(S_error < tolerance);
125  }
126 
127  // Testing nonsymmetric schur complement.
128  {
129  // Generate C/D, compute schur complement C'*inv(A)*D
130  auto C = SparseMatrix<Precision>::random(N,K1,5*N);
131  auto D = SparseMatrix<Precision>::random(N,K2,4*N);
132  Matrix<Precision> S1 = solver.schur(C,D,options);
133  // Compare to reference/dense calculation.
134  Matrix<Precision> S2 = gemm(C.make_Matrix(),'T',gemm(inverse(A.make_Matrix()),D.make_Matrix()));
135  Precision S_error = frobenius(S1-S2)/frobenius(S2);
136  myra::out() << "|C'*inv(A)*D [dense] - C'*inv(A)*D [sparse]| = " << S_error << std::endl;
137  REQUIRE(S_error < tolerance);
138  }
139 
140  // Testing unsymmetric restricted schur complement.
141  {
142  // Compute a symmetric schur complement Bv'*Bi'*inv(A)*Ci*Cv
143  auto Bi = random_rows(N,10);
144  auto Bv = Matrix<Precision>::random(ssize(Bi),K1);
145  auto Ci = random_rows(N,10);
146  auto Cv = Matrix<Precision>::random(ssize(Ci),K2);
147  auto S1 = solver.schur(Bi,Bv,Ci,Cv,options);
148  // Compare to reference/dense calculation.
149  auto B = fill(N,Bi,Bv);
150  auto C = fill(N,Ci,Cv);
151  auto S2 = gemm(B.make_Matrix(),'T',gemm(inverse(A.make_Matrix()),C.make_Matrix()));
152  Precision S_error = frobenius(S1-S2)/frobenius(S2);
153  myra::out() << "|schur(B,C)-schur(BiBv,CiCv)| = " << S_error << std::endl;
154  REQUIRE(S_error < tolerance);
155  }
156 
157  // Testing unsymmetric schur complement by a dense Vector, exercises write race resolution.
158  {
159  auto Bi = ilinspace(0,N);
160  auto Bv = Matrix<Precision>::random(N,1);
161  auto Ci = ilinspace(0,N);
162  auto Cv = Matrix<Precision>::random(N,1);
163  Precision S1 = solver.schur(Bi,Bv,Ci,Cv,options)(0,0);
164  // Compare to reference/dense calculation.
165  solver.solveL(Bv);
166  solver.solveL(Cv);
167  Precision S2 = dot(Bv.vector(0),Cv.vector(0));
168  Precision S_error = std::abs(S1-S2)/std::abs(S2);
169  myra::out() << "|schur(Bi,Bv)-dot(L\\Bv,L\\Bv))| = " << S_error << std::endl;
170  REQUIRE(S_error < tolerance);
171  }
172 
173  }
174 
175 } // namespace
176 
177 ADD_TEST("rcholesky2_schur","[multifrontal][parallel]")
178  {
179  test<float>(1.0e-4f);
180  test<double>(1.0e-8);
181  }
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
Interface class for representing subranges of dense Vector&#39;s.
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
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.
Range/Iterator types associated with Pattern.
Sparse direct solver suitable for real symmetric positive definite systems.
Container for either a column vector or row vector (depends upon the usage context) ...
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
Sparse direct solver suitable for real symmetric positive definite systems.
Definition: SparseRCholeskySolver.h:61
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
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]| = 1.26579e-07
|schur(B)-schur(BiBv)| = 1.50978e-07
|schur(Bi,Bv)-dot(L\Bv,L\Bv))| = 8.52305e-08
|C'*inv(A)*D [dense] - C'*inv(A)*D [sparse]| = 2.7761e-07
|schur(B,C)-schur(BiBv,CiCv)| = 1.49129e-07
|schur(Bi,Bv)-dot(L\Bv,L\Bv))| = 5.43625e-07
|B'*inv(A)*B [dense] - B'*inv(A)*B [sparse]| = 2.23428e-16
|schur(B)-schur(BiBv)| = 3.53397e-16
|schur(Bi,Bv)-dot(L\Bv,L\Bv))| = 6.16227e-16
|C'*inv(A)*D [dense] - C'*inv(A)*D [sparse]| = 6.0128e-16
|schur(B,C)-schur(BiBv,CiCv)| = 4.09679e-16
|schur(Bi,Bv)-dot(L\Bv,L\Bv))| = 2.09545e-16


Go back to Summary of /test programs.