sym-ildl  1.2
Incomplete LDL' factorizations of indefinite symmetric and skew-symmetric matrices.
lilc_matrix_ildl_helpers.h
1 #ifndef _LILC_MATRIX_ILDL_HELPERS_H
2 #define _LILC_MATRIX_ILDL_HELPERS_H
3 
4 using std::abs;
5 using std::vector;
6 
7 typedef vector<int>::iterator idx_it;
8 
13 template <class el_type>
14 inline double dot_product(const vector<el_type>& v, const vector<el_type>& w) {
15  double res = 0;
16  for (int i = 0; i < v.size(); i++) {
17  res += v[i]*w[i];
18  }
19  return res;
20 }
21 
25 template <class el_type>
26 inline void vector_sum(double a, vector<el_type>& v, double b, vector<el_type>& w, vector<el_type>& u) {
27  for (int i = 0; i < v.size(); i++) {
28  u[i] = a*v[i] + b*w[i];
29  }
30 }
31 
39 template <class el_type>
40 inline double max(vector<el_type>& v, vector<int>& curr_nnzs, int& r) {
41  double res = 0;
42  for (idx_it it = curr_nnzs.begin(), end = curr_nnzs.end(); it != end; ++it) {
43  if (abs(v[*it]) > res) {
44  res = abs(v[*it]);
45  r = *it;
46  }
47  }
48 
49  return res;
50 }
51 
58 template <class el_type>
59 inline double norm(vector<el_type>& v, vector<int>& curr_nnzs, el_type p = 1) {
60  el_type res = 0;
61  for (idx_it it = curr_nnzs.begin(), end = curr_nnzs.end(); it != end; ++it) {
62  res += pow(abs(v[*it]), p);
63  }
64 
65  return pow(res, 1/p);
66 }
67 
73 template <class el_type>
74 inline double norm(vector<el_type>& v, el_type p = 1) {
75  el_type res = 0;
76  for (int i = 0; i < v.size(); i++) {
77  res += pow(abs(v[i]), p);
78  }
79  return pow(res, 1/p);
80 }
81 
87 template <class InputContainer, class InputIterator>
88 inline void inplace_union(InputContainer& a, InputIterator const& b_start, InputIterator const& b_end)
89 {
90  int mid = a.size(); //store the end of first sorted range
91 
92  //copy the second sorted range into the destination vector
93  std::copy(b_start, b_end, std::back_inserter(a));
94 
95  //perform the in place merge on the two sub-sorted ranges.
96  std::inplace_merge(a.begin(), a.begin() + mid, a.end());
97 
98  //remove duplicate elements from the sorted vector
99  a.erase(std::unique(a.begin(), a.end()), a.end());
100 }
101 
108 template <class InputContainer, class InputIterator>
109 inline void unordered_inplace_union(InputContainer& a, InputIterator const& b_start, InputIterator const& b_end, vector<bool>& in_set)
110 {
111  for (InputIterator it = a.begin(), end = a.end(); it != end; ++it) {
112  assert(*it < in_set.size() && *it >= 0);
113  in_set[*it] = true;
114  }
115 
116  for (InputIterator it = b_start; it != b_end; ++it) {
117  if (!in_set[*it]) {
118  in_set[*it] = true;
119  a.push_back(*it);
120  }
121  }
122 
123  for (InputIterator it = a.begin(), end = a.end(); it != end; ++it) {
124  assert(*it < in_set.size() && *it >= 0);
125  in_set[*it] = false;
126  }
127 }
128 
129 //-------------Dropping rules-------------//
130 
131 
132 namespace {
136 template <class el_type>
137 struct by_value {
138  const vector<el_type>& v;
139  by_value(const vector<el_type>& vec) : v(vec) {}
140  inline bool operator()(int const &a, int const &b) const {
141  // Not needed if we're using sort. If using this comparator
142  // in a set, then uncomment the line below.
143  //if (abs(v[a]) == abs(v[b])) return a < b;
144  return abs(v[a]) > abs(v[b]);
145  }
146 };
147 
152 template <class el_type>
153 struct by_tolerance {
154  const vector<el_type>& v;
155  double eps;
156  by_tolerance(const vector<el_type>& vec, const double& eps) : v(vec), eps(eps) {}
157  inline bool operator()(int const &i) const {
158  return abs(v[i]) < eps;
159  }
160 };
161 }
162 
169 template <class el_type>
170 inline void drop_tol(vector<el_type>& v, vector<int>& curr_nnzs, const int& lfil, const double& tol) {
171  //determine dropping tolerance. all elements with value less than tolerance = tol * norm(v) is dropped.
172  el_type tolerance = tol*norm<el_type>(v, curr_nnzs);
173  const long double eps = 1e-13; //TODO: fix later. need to make this a global thing
174  if (tolerance > eps) {
175  for (idx_it it = curr_nnzs.begin(), end = curr_nnzs.end(); it != end; ++it)
176  if (abs(v[*it]) < tolerance) v[*it] = 0;
177 
178  //sort the remaining elements by value in decreasing order.
179  by_value<el_type> sorter(v);
180  std::sort(curr_nnzs.begin(), curr_nnzs.end(), sorter);
181  }
182 
183  for (int i = lfil, end = curr_nnzs.size(); i < end ; ++i) {
184  v[curr_nnzs[i]] = 0;
185  }
186 
187  by_tolerance<el_type> is_zero(v, eps);
188  curr_nnzs.erase( remove_if(curr_nnzs.begin(), curr_nnzs.end(), is_zero), curr_nnzs.end() );
189  curr_nnzs.resize( std::min(lfil, (int) curr_nnzs.size()) );
190  //sort the first lfil elements by index, only these will be assigned into L. this part can be removed.
191  std::sort(curr_nnzs.begin(), curr_nnzs.end());
192 }
193 
194 //----------------Column updates------------------//
195 
196 template <class el_type>
197 inline void update_single(const int& k, const int& j, const el_type& l_ki, const el_type& d, vector<el_type>& work, vector<int>& curr_nnzs, lilc_matrix<el_type>& L, vector<bool>& in_set) {
198  //find where L(k, k+1:n) starts
199  int i, offset = L.col_first[j];
200 
201  L.ensure_invariant(j, k, L.m_idx[j]);
202 
203  el_type factor = l_ki * d;
204  for (i = offset; i < L.m_idx[j].size(); ++i) {
205  int x = L.m_idx[j][i];
206  work[x] -= factor * L.m_x[j][i];
207  if (!in_set[x]) {
208  curr_nnzs.push_back(x);
209  in_set[x] = true;
210  }
211  }
212 }
213 
222 template <class el_type>
223 inline void update(const int& r, vector<el_type>& work, vector<int>& curr_nnzs, lilc_matrix<el_type>& L, block_diag_matrix<el_type>& D, vector<bool>& in_set) {
224  unsigned int j;
225  int blk_sz;
226  el_type d_12, l_ri;
227 
228  // precord: in_set is all false.
229  // TOOD: if we are for sure doing sequential code, make in_set a static var.
230  for (int x : curr_nnzs) {
231  in_set[x] = true;
232  }
233 
234  //iterate across non-zeros of row k using Llist
235  for (int i = 0; i < (int) L.list[r].size(); ++i) {
236  j = L.list[r][i];
237  assert(j < r);
238  l_ri = L.coeff(r, j, L.col_first[j]);
239 
240  update_single(r, j, l_ri, D[j], work, curr_nnzs, L, in_set); //update col using d11
241 
242  blk_sz = D.block_size(j);
243  if (blk_sz == 2) {
244  d_12 = D.off_diagonal(j);
245  update_single(r, j + 1, l_ri, d_12, work, curr_nnzs, L, in_set);
246  } else if (blk_sz == -2) {
247  d_12 = D.off_diagonal(j-1);
248  update_single(r, j - 1, l_ri, d_12, work, curr_nnzs, L, in_set); //update col using d12
249  }
250 
251  }
252 
253  for (int x : curr_nnzs) {
254  in_set[x] = false;
255  }
256 }
257 
258 //not needed anymore
259 template <class el_type>
260 inline void vec_add(vector<el_type>& v1, vector<int>& v1_nnzs, vector<el_type>& v2, vector<int>& v2_nnzs) {
261  //merge current non-zeros of col k with nonzeros of col *it.
262  inplace_union(v1_nnzs, v2_nnzs.begin(), v2_nnzs.end());
263  for (idx_it it = v1_nnzs.begin(), end = v1_nnzs.end(); it != end; ++it) {
264  v1[*it] += v2[*it];
265  }
266 }
267 
268 inline void safe_swap(vector<int>& curr_nnzs, const int& k, const int& r) {
269  bool con_k = false, con_r = false;
270  vector<int>::iterator k_idx, r_idx;
271  for (idx_it it = curr_nnzs.begin(), end = curr_nnzs.end(); it != end; ++it) {
272  if (*it == k) {
273  con_k = true;
274  k_idx = it;
275  }
276 
277  if (*it == r) {
278  con_r = true;
279  r_idx = it;
280  }
281  }
282 
283  if (con_k) *k_idx = r; //if we have k we'll swap index to r
284  if (con_r) *r_idx = k; //if we have r we'll swap index to k
285 }
286 
287 #endif
el_type & off_diagonal(int i)
Definition: block_diag_matrix.h:114
vector< elt_vector_type > m_x
The values of the nonzeros in the matrix.
Definition: lil_sparse_matrix.h:36
vector< idx_vector_type > m_idx
The row/col indices. The way m_idx is used depends on whether the matrix is in LIL-C or LIL-R...
Definition: lil_sparse_matrix.h:35
A list-of-lists (LIL) matrix in column oriented format.
Definition: lilc_matrix.h:9
A quick implementation of a diagonal matrix with 1x1 and 2x2 blocks.
Definition: block_diag_matrix.h:39
virtual el_type coeff(const int &i, const int &j, int offset=0) const
Finds the (i,j)th coefficient of the matrix.
Definition: lilc_matrix_declarations.h:80
std::vector< int > col_first
On iteration k, first[i] gives the number of non-zero elements on col i of A before A(i...
Definition: lilc_matrix_declarations.h:47
void ensure_invariant(const int &j, const int &k, Container &con, bool update_list=false)
Ensures two the invariants observed by A.first and A.list are held.
Definition: lilc_matrix_declarations.h:300
std::vector< std::vector< int > > list
A list of linked lists that gives the non-zero elements in each row of A. Since at any time we may sw...
Definition: lilc_matrix_declarations.h:44
int block_size(int i) const
Definition: block_diag_matrix.h:128