MyraMath
zcholesky2_schur


Source: tests/multifrontal/zcholesky/zcholesky2_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.
13 #include <myramath/dense/Matrix.h>
21 
22 // Algorithms.
25 #include <myramath/dense/dot.h>
26 #include <myramath/dense/gemm.h>
27 #include <myramath/dense/inverse.h>
30 #include <myramath/sparse/phasor.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  typedef typename ReflectComplex<Precision>::type Number;
67  int I = 20;
68  int J = 25;
69  int N = I*J;
70  int K = 23;
71  int K1 = K-1;
72  int K2 = K+1;
73 
74  // Generate A.
75  SparseMatrix<Number> A = laplacian2<Number>(I,J);
76  phasor_hermitian(A);
77 
78  // Options related to reordering.
79  typedef multifrontal::Options Options;
80  Options options = Options::create().set_blocksize(4).set_globsize(4).set_nthreads(4);
81 
82  // Reorder A using bisection and factor it.
83  Permutation perm = bisect2(I,J);
84  SparseZCholeskySolver<Precision> solver(A,perm,options);
85 
86  // Testing symmetric sparse schur complement.
87  {
88  // Generate B, generate a schur complement B'*inv(A)*B
89  auto B = SparseMatrix<Number>::random(N,K,3*N);
90  LowerMatrix<Number> S1 = solver.schur(B,options);
91  // Compare to reference/dense calculation.
92  Matrix<Number> S2 = gemm(B.make_Matrix(),'H',gemm(inverse(A.make_Matrix()),B.make_Matrix()));
93  Precision S_error = frobenius(S1.make_Matrix('H')-S2)/frobenius(S2);
94  myra::out() << "|B'*inv(A)*B [dense] - B'*inv(A)*B [sparse]| = " << S_error << std::endl;
95  REQUIRE(S_error < tolerance);
96  }
97 
98  // Testing symmetric restricted schur complement.
99  {
100  // Compute a symmetric schur complement Bv'*Bi'*inv(A)*Bi*Bv
101  auto Bi = random_rows(N,10);
102  auto Bv = Matrix<Number>::random(ssize(Bi),K);
103  auto B = fill(N,Bi,Bv);
104  auto S1 = solver.schur(Bi,Bv,options);
105  // Compare to reference/dense calculation.
106  auto S2 = gemm(B.make_Matrix(),'H',gemm(inverse(A.make_Matrix()),B.make_Matrix()));
107  Precision S_error = frobenius(S1.make_Matrix('H')-S2)/frobenius(S2);
108  myra::out() << "|schur(B)-schur(BiBv)| = " << S_error << std::endl;
109  REQUIRE(S_error < tolerance);
110  }
111 
112  // Testing symmetric schur complement by a dense Vector, exercises write race resolution.
113  {
114  // Compute a symmetric schur complement Bv'*Bi'*inv(A)*Bi*Bv
115  auto Bi = ilinspace(0,N);
116  auto Bv = Matrix<Number>::random(N,1);
117  Number S1 = solver.schur(Bi,Bv,options)(0,0);
118  // Compare to reference/dense calculation.
119  solver.solveL(Bv);
120  Number S2 = dot(Bv.vector(0),Bv.vector(0));
121  Precision S_error = std::abs(S1-S2)/std::abs(S2);
122  myra::out() << "|schur(Bi,Bv)-dot(L\\Bv,L\\Bv))| = " << S_error << std::endl;
123  REQUIRE(S_error < tolerance);
124  }
125 
126  // Testing nonsymmetric schur complement.
127  {
128  // Generate C/D, compute schur complement C'*inv(A)*D
129  auto C = SparseMatrix<Number>::random(N,K1,5*N);
130  auto D = SparseMatrix<Number>::random(N,K2,4*N);
131  Matrix<Number> S1 = solver.schur(C,D,options);
132  // Compare to reference/dense calculation.
133  Matrix<Number> S2 = gemm(C.make_Matrix(),'H',gemm(inverse(A.make_Matrix()),D.make_Matrix()));
134  Precision S_error = frobenius(S1-S2)/frobenius(S2);
135  myra::out() << "|C'*inv(A)*D [dense] - C'*inv(A)*D [sparse]| = " << S_error << std::endl;
136  REQUIRE(S_error < tolerance);
137  }
138 
139  // Testing unsymmetric restricted schur complement.
140  {
141  // Compute a symmetric schur complement Bv'*Bi'*inv(A)*Ci*Cv
142  auto Bi = random_rows(N,10);
143  auto Bv = Matrix<Number>::random(ssize(Bi),K1);
144  auto Ci = random_rows(N,10);
145  auto Cv = Matrix<Number>::random(ssize(Ci),K2);
146  auto S1 = solver.schur(Bi,Bv,Ci,Cv,options);
147  // Compare to reference/dense calculation.
148  auto B = fill(N,Bi,Bv);
149  auto C = fill(N,Ci,Cv);
150  auto S2 = gemm(B.make_Matrix(),'H',gemm(inverse(A.make_Matrix()),C.make_Matrix()));
151  Precision S_error = frobenius(S1-S2)/frobenius(S2);
152  myra::out() << "|schur(B,C)-schur(BiBv,CiCv)| = " << S_error << std::endl;
153  REQUIRE(S_error < tolerance);
154  }
155 
156  // Testing unsymmetric schur complement by a dense Vector, exercises write race resolution.
157  {
158  auto Bi = ilinspace(0,N);
159  auto Bv = Matrix<Number>::random(N,1);
160  auto Ci = ilinspace(0,N);
161  auto Cv = Matrix<Number>::random(N,1);
162  Number S1 = solver.schur(Bi,Bv,Ci,Cv,options)(0,0);
163  // Compare to reference/dense calculation.
164  solver.solveL(Bv);
165  solver.solveL(Cv);
166  Number S2 = dot(Bv.vector(0),Cv.vector(0));
167  Precision S_error = std::abs(S1-S2)/std::abs(S2);
168  myra::out() << "|schur(Bi,Bv)-dot(L\\Bv,L\\Bv))| = " << S_error << std::endl;
169  REQUIRE(S_error < tolerance);
170  }
171 
172  }
173 
174 } // namespace
175 
176 ADD_TEST("zcholesky2_schur","[multifrontal][parallel]")
177  {
178  test<float>(1.0e-4f);
179  test<double>(1.0e-8);
180  }
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
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 hermitian positive definite systems.
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...
Reflects a Precision type into a complex type.
Definition: Number.h:46
Routines for inner products of Vector&#39;s / VectorRange&#39;s.
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
Sparse direct solver suitable for hermitian positive definite systems.
Definition: SparseZCholeskySolver.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 a lower triangular matrix in rectangular packed format.
Definition: conjugate.h:22
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.
Applies random phase shifts to a complex square SparseMatrix.
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.55229e-07
|schur(B)-schur(BiBv)| = 1.94353e-07
|schur(Bi,Bv)-dot(L\Bv,L\Bv))| = 6.00614e-07
|C'*inv(A)*D [dense] - C'*inv(A)*D [sparse]| = 3.05684e-07
|schur(B,C)-schur(BiBv,CiCv)| = 1.92332e-07
|schur(Bi,Bv)-dot(L\Bv,L\Bv))| = 6.13198e-07
|B'*inv(A)*B [dense] - B'*inv(A)*B [sparse]| = 2.46697e-16
|schur(B)-schur(BiBv)| = 4.39655e-16
|schur(Bi,Bv)-dot(L\Bv,L\Bv))| = 5.00086e-16
|C'*inv(A)*D [dense] - C'*inv(A)*D [sparse]| = 6.05179e-16
|schur(B,C)-schur(BiBv,CiCv)| = 8.87199e-16
|schur(Bi,Bv)-dot(L\Bv,L\Bv))| = 1.15114e-15


Go back to Summary of /test programs.