MyraMath
zldlt2_schur


Source: tests/multifrontal/zldlt/zldlt2_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 #include <myramath/sparse/phasor.h>
32 
33 // Solver under test.
35 
36 // Reporting.
37 #include <tests/myratest.h>
38 
39 using namespace myra;
40 
41 namespace {
42 
43 // Generates random row indices.
44 std::vector<int> random_rows(int I, int N)
45  {
46  std::vector<int> answer;
47  for (int n = 0; n < N; ++n)
48  answer.push_back( random_int(0,I) );
49  sortunique(answer);
50  return answer;
51  }
52 
53 // Fills SparseMatrix B from (Bi,Bv) data.
54 template<class Number> SparseMatrix<Number> fill(int I, const std::vector<int>& Bi, const Matrix<Number>& Bv)
55  {
56  int J = Bv.size().second;
57  SparseMatrixBuilder<Number> B_builder(I,J);
58  for (int j = 0; j < J; ++j)
59  for (int i = 0; i < Bi.size(); ++i)
60  B_builder(Bi[i],j) = Bv(i,j);
61  return B_builder.make_SparseMatrix();
62  }
63 
64 // Various schur() tests.
65 template<class Precision> void test(Precision tolerance)
66  {
67  typedef typename ReflectComplex<Precision>::type Number;
68  int I = 20;
69  int J = 25;
70  int N = I*J;
71  int K = 23;
72  int K1 = K-1;
73  int K2 = K+1;
74 
75  // Generate A.
76  SparseMatrix<Number> A = laplacian2<Number>(I,J);
77  double shift = 5.5;
78  for (int n = 0; n < N; ++n)
79  A(n,n) -= shift;
80  phasor_symmetric(A);
81 
82  // Options related to reordering.
83  typedef multifrontal::Options Options;
84  Options options = Options::create().set_blocksize(4).set_globsize(4).set_nthreads(4);
85 
86  // Reorder A using bisection and factor it.
87  Permutation perm = bisect2(I,J);
88  SparseZLDLTSolver<double> solver(A,perm,options);
89 
90  // Testing symmetric sparse schur complement.
91  {
92  // Generate B, generate a schur complement B'*inv(A)*B
93  auto B = SparseMatrix<Number>::random(N,K,3*N);
94  LowerMatrix<Number> S1 = solver.schur(B,options);
95  // Compare to reference/dense calculation.
96  Matrix<Number> S2 = gemm(B.make_Matrix(),'T',gemm(inverse(A.make_Matrix()),B.make_Matrix()));
97  Precision S_error = frobenius(S1.make_Matrix('T')-S2)/frobenius(S2);
98  myra::out() << "|B'*inv(A)*B [dense] - B'*inv(A)*B [sparse]| = " << S_error << std::endl;
99  REQUIRE(S_error < tolerance);
100  }
101 
102  // Testing symmetric restricted schur complement.
103  {
104  // Compute a symmetric schur complement Bv'*Bi'*inv(A)*Bi*Bv
105  auto Bi = random_rows(N,10);
106  auto Bv = Matrix<Number>::random(ssize(Bi),K);
107  auto B = fill(N,Bi,Bv);
108  auto S1 = solver.schur(Bi,Bv,options);
109  // Compare to reference/dense calculation.
110  auto S2 = gemm(B.make_Matrix(),'T',gemm(inverse(A.make_Matrix()),B.make_Matrix()));
111  Precision S_error = frobenius(S1.make_Matrix('T')-S2)/frobenius(S2);
112  myra::out() << "|schur(B)-schur(BiBv)| = " << S_error << std::endl;
113  REQUIRE(S_error < tolerance);
114  }
115 
116  // Testing symmetric schur complement by a dense Vector, exercises write race resolution.
117  {
118  // Compute a symmetric schur complement Bv'*Bi'*inv(A)*Bi*Bv
119  auto Bi = ilinspace(0,N);
120  auto Bv = Matrix<Number>::random(N,1);
121  Number S1 = solver.schur(Bi,Bv,options)(0,0);
122  // Compare to reference/dense calculation.
123  solver.solveL(Bv);
124  auto Cv = Bv;
125  solver.solveD(Cv);
126  Number S2 = dotu(Bv.vector(0),Cv.vector(0));
127  Precision S_error = std::abs(S1-S2)/std::abs(S2);
128  myra::out() << "|schur(Bi,Bv)-dot(L\\Bv,L\\Bv))| = " << S_error << std::endl;
129  REQUIRE(S_error < tolerance);
130  }
131 
132  // Testing nonsymmetric schur complement.
133  {
134  // Generate C/D, compute schur complement C'*inv(A)*D
135  auto C = SparseMatrix<Number>::random(N,K1,5*N);
136  auto D = SparseMatrix<Number>::random(N,K2,4*N);
137  Matrix<Number> S1 = solver.schur(C,D,options);
138  // Compare to reference/dense calculation.
139  Matrix<Number> S2 = gemm(C.make_Matrix(),'T',gemm(inverse(A.make_Matrix()),D.make_Matrix()));
140  Precision S_error = frobenius(S1-S2)/frobenius(S2);
141  myra::out() << "|C'*inv(A)*D [dense] - C'*inv(A)*D [sparse]| = " << S_error << std::endl;
142  REQUIRE(S_error < tolerance);
143  }
144 
145  // Testing unsymmetric restricted schur complement.
146  {
147  // Compute a symmetric schur complement Bv'*Bi'*inv(A)*Ci*Cv
148  auto Bi = random_rows(N,10);
149  auto Bv = Matrix<Number>::random(ssize(Bi),K1);
150  auto Ci = random_rows(N,10);
151  auto Cv = Matrix<Number>::random(ssize(Ci),K2);
152  auto S1 = solver.schur(Bi,Bv,Ci,Cv,options);
153  // Compare to reference/dense calculation.
154  auto B = fill(N,Bi,Bv);
155  auto C = fill(N,Ci,Cv);
156  auto S2 = gemm(B.make_Matrix(),'T',gemm(inverse(A.make_Matrix()),C.make_Matrix()));
157  Precision S_error = frobenius(S1-S2)/frobenius(S2);
158  myra::out() << "|schur(B,C)-schur(BiBv,CiCv)| = " << S_error << std::endl;
159  REQUIRE(S_error < tolerance);
160  }
161 
162  // Testing unsymmetric schur complement by a dense Vector, exercises write race resolution.
163  {
164  auto Bi = ilinspace(0,N);
165  auto Bv = Matrix<Number>::random(N,1);
166  auto Ci = ilinspace(0,N);
167  auto Cv = Matrix<Number>::random(N,1);
168  Number S1 = solver.schur(Bi,Bv,Ci,Cv,options)(0,0);
169  // Compare to reference/dense calculation.
170  solver.solveL(Bv);
171  solver.solveL(Cv);
172  solver.solveD(Cv);
173  Number S2 = dotu(Bv.vector(0),Cv.vector(0));
174  Precision S_error = std::abs(S1-S2)/std::abs(S2);
175  myra::out() << "|schur(Bi,Bv)-dot(L\\Bv,L\\Bv))| = " << S_error << std::endl;
176  REQUIRE(S_error < tolerance);
177  }
178 
179  }
180 
181 } // namespace
182 
183 ADD_TEST("zldlt2_schur","[multifrontal][parallel]")
184  {
185  test<double>(1.0e-8);
186  }
Sparse direct solver suitable for complex symmetric systems.
Definition: SparseZLDLTSolver.h:61
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 complex symmetric 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.
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
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]| = 3.71176e-14
|schur(B)-schur(BiBv)| = 3.44232e-14
|schur(Bi,Bv)-dot(L\Bv,L\Bv))| = 1.52267e-14
|C'*inv(A)*D [dense] - C'*inv(A)*D [sparse]| = 3.44319e-14
|schur(B,C)-schur(BiBv,CiCv)| = 3.54289e-14
|schur(Bi,Bv)-dot(L\Bv,L\Bv))| = 1.60637e-15


Go back to Summary of /test programs.