sym-ildl  1.2
Incomplete LDL' factorizations of indefinite symmetric and skew-symmetric matrices.
block_diag_matrix.h
1 // -*- mode: c++ -*-
2 #ifndef _BLOCK_DIAG_MATRIX_H_
3 #define _BLOCK_DIAG_MATRIX_H_
4 
5 #include <unordered_map>
6 #include <vector>
7 #include <string>
8 #include <fstream>
9 #include <cassert>
10 #include <iostream>
11 #include <algorithm>
12 #include <cmath>
13 
14 #ifdef SYM_ILDL_DEBUG
15 template<class el_type>
16 std::ostream& operator<< (std::ostream& os, const std::vector<el_type>& vec)
17 {
18  os << "[";
19  if (!vec.empty())
20  {
21  for (typename std::vector<el_type>::size_type index = 0; index < vec.size() - 1; index ++)
22  {
23  os << vec[index] << ", ";
24  }
25 
26  os << vec[vec.size()-1];
27  }
28  os << "]";
29  return os;
30 }
31 #endif
32 
33 
34 using std::abs;
35 
38 template<class el_type>
40 {
41 public:
42 
43  typedef std::unordered_map<int, el_type> int_elt_map;
44  typedef std::vector<el_type> elt_vector_type;
45 
47  friend std::ostream & operator<<(std::ostream& os, const block_diag_matrix& D)
48  {
49  os << D.to_string();
50  return os;
51  };
52 
53  int m_n_size;
54  int nnz_count;
55  elt_vector_type main_diag;
56  int_elt_map off_diag;
57 
60  block_diag_matrix (int n_rows = 0, int n_cols = 0) : m_n_size(n_rows)
61  {
62  assert(n_rows == n_cols);
63  nnz_count = n_rows;
64  main_diag.clear();
65  main_diag.resize(n_rows);
66  }
67 
70  void resize(int n, el_type default_value) {
71  m_n_size = n;
72  main_diag.clear();
73  main_diag.resize(n, default_value);
74  off_diag.clear();
75  nnz_count = n;
76  }
77 
80  void resize(int n) {
81  m_n_size = n;
82  resize(n, 0);
83  nnz_count = n;
84  }
85 
87  int n_rows() const
88  {
89  return m_n_size;
90  }
91 
93  int n_cols() const
94  {
95  return m_n_size;
96  }
97 
99  int nnz() const
100  {
101  return nnz_count;
102  };
103 
107  el_type& operator[](int i) {
108  return main_diag.at(i);
109  }
110 
114  el_type& off_diagonal(int i) {
115  if (!off_diag.count(i)) {
116  off_diag.insert(std::make_pair(i, 0));
117  nnz_count++;
118  }
119 
120  return off_diag[i];
121  }
122 
128  int block_size(int i) const {
129  if (off_diag.count(i)) {
130  return 2;
131  } else if (off_diag.count(i-1)) {
132  return -2;
133  } else {
134  return 1;
135  }
136  }
137 
143  void sqrt_solve(const elt_vector_type& b, elt_vector_type& x, bool transposed = false) {
144  assert(b.size() == x.size());
145 
146  const double eps = 1e-8;
147  double alpha, beta, gamma, eig0, eig1, disc;
148  double Q[2][2], tx[2];
149  for (int i = 0; i < m_n_size; i += block_size(i)) {
150  if (block_size(i) == 2) {
151  alpha = main_diag[i];
152  beta = main_diag[i+1];
153  gamma = off_diag[i];
154 
155  disc = sqrt((alpha-beta)*(alpha-beta) + 4*gamma*gamma);
156  eig0 = 0.5*(alpha+beta+disc);
157  eig1 = 0.5*(alpha+beta-disc);
158 
159  if (abs(gamma/std::min(alpha, beta)) < eps) {
160  eig0 = alpha; eig1 = beta;
161  Q[0][0] = 1; Q[1][0] = 0;
162  Q[0][1] = 0; Q[1][1] = 1;
163  } else {
164  double sin2t = 2*gamma/disc, cos2t = (alpha-beta)/disc;
165  double theta = 0.5*atan2(sin2t, cos2t);
166 
167  Q[0][0] = cos(theta); Q[0][1] = -sin(theta);
168  Q[1][0] = sin(theta); Q[1][1] = cos(theta);
169  }
170 
171  //solves Q|V|^(1/2) x = b or solves the transposed version |V|^(1/2)Q' x = b.
172  if (!transposed) {
173  //tx = Q'*b
174  tx[0] = Q[0][0] * b[i] + Q[1][0] * b[i+1];
175  tx[1] = Q[0][1] * b[i] + Q[1][1] * b[i+1];
176 
177  //x = |V|^(-1/2)*tx
178  x[i] = tx[0]/sqrt(abs(eig0));
179  x[i+1] = tx[1]/sqrt(abs(eig1));
180  } else {
181  //tx = |V|^(-1/2)*b
182  tx[0] = b[i]/sqrt(abs(eig0));
183  tx[1] = b[i+1]/sqrt(abs(eig1));
184 
185  //x = Q*tx
186  x[i] = Q[0][0] * tx[0] + Q[0][1] * tx[1];
187  x[i+1] = Q[1][0] * tx[0] + Q[1][1] * tx[1];
188  }
189  } else {
190  x[i] = b[i]/sqrt(abs(main_diag[i]));
191  }
192  }
193  }
194 
199  void solve(const elt_vector_type& b, elt_vector_type& x) {
200  assert(b.size() == x.size());
201 
202  double a, d, c, det;
203  for (int i = 0; i < m_n_size; i += block_size(i)) {
204  if (block_size(i) == 2) {
205  a = main_diag[i];
206  d = main_diag[i+1];
207  c = off_diag[i];
208  det = a*d - c*c;
209  // system is (a c; c d)
210  // inverse is 1/(ad - c^2) * (d -c; -c a)
211  x[i] = (d*b[i] - c*b[i+1])/det;
212  x[i+1] = (-c*b[i] + a*b[i+1])/det;
213  } else {
214  x[i] = b[i]/main_diag[i];
215  }
216  }
217  }
218 
221  std::string to_string () const;
222 
226  bool save(std::string filename) const;
227 
231  {
232  }
233 };
234 
235 #include "block_diag_matrix_to_string.h"
236 #include "block_diag_matrix_save.h"
237 
238 #endif
el_type & operator[](int i)
Definition: block_diag_matrix.h:107
el_type & off_diagonal(int i)
Definition: block_diag_matrix.h:114
int_elt_map off_diag
Stores off-diagonal elements of 2x2 pivots.
Definition: block_diag_matrix.h:56
int n_rows() const
Definition: block_diag_matrix.h:87
elt_vector_type main_diag
Stores main diagonal elements.
Definition: block_diag_matrix.h:55
int nnz_count
Number of non-zeros in the matrix.
Definition: block_diag_matrix.h:54
void solve(const elt_vector_type &b, elt_vector_type &x)
Solves the system Dx = b.
Definition: block_diag_matrix.h:199
void sqrt_solve(const elt_vector_type &b, elt_vector_type &x, bool transposed=false)
Solves the preconditioned problem |D| = Q|V|Q&#39;, where QVQ&#39; is the eigendecomposition of D...
Definition: block_diag_matrix.h:143
block_diag_matrix(int n_rows=0, int n_cols=0)
Constructor for diagonal class. Initializes a 0x0 matrix when given no arguments. ...
Definition: block_diag_matrix.h:60
bool save(std::string filename) const
Definition: block_diag_matrix_save.h:6
void resize(int n, el_type default_value)
Resizes this matrix to an n*n matrix with default_value on the main diagonal.
Definition: block_diag_matrix.h:70
friend std::ostream & operator<<(std::ostream &os, const block_diag_matrix &D)
Definition: block_diag_matrix.h:47
~block_diag_matrix()
Generic class destructor.
Definition: block_diag_matrix.h:230
A quick implementation of a diagonal matrix with 1x1 and 2x2 blocks.
Definition: block_diag_matrix.h:39
int nnz() const
Definition: block_diag_matrix.h:99
std::string to_string() const
Definition: block_diag_matrix_to_string.h:9
void resize(int n)
Resizes this matrix to an n*n matrix.
Definition: block_diag_matrix.h:80
int n_cols() const
Definition: block_diag_matrix.h:93
int m_n_size
Dimension of the matrix.
Definition: block_diag_matrix.h:51
int block_size(int i) const
Definition: block_diag_matrix.h:128