1 /////////////////////////////////////////////////////////////////////////////////////////////////
2 /// \file /utils/lmyengine/block_mat.cpp
3 ///
4 /// \brief Implementation file for block recursive matrix class
5 ///
6 /////////////////////////////////////////////////////////////////////////////////////////////////
7
8 #include <vector>
9 #include <list>
10 #include <string>
11 #include <numeric>
12 #include <cassert>
13 #include <algorithm>
14 #include <cmath>
15 #include <sstream>
16 #include "formic/utils/openmp.h"
17
18 #include <boost/format.hpp>
19 #include <boost/shared_ptr.hpp>
20
21 #include "formic/utils/matrix.h"
22 #include "formic/utils/mpi_interface.h"
23 #include "block_mat.h"
24 #include "formic/utils/lmyengine/block_detail.h"
25
26 //////////////////////////////////////////////////////////////////////////////////////////////////
27 /// \brief Function that contracts each block's previous update components with derivative ratios
28 ///
29 /// \param[in] dr derivative ratio(bare or energy) for this sample
30 /// \param[in] ou_mat matrix holds old updates, size num_old_update * num_variables
31 /// \param[out] cont_vec contracted results
32 ///
33 //////////////////////////////////////////////////////////////////////////////////////////////////
prep_block_ou_contractions(const std::vector<double> & dr,const formic::Matrix<double> & ou_mat,std::vector<formic::ColVec<double>> & cont_vec)34 void cqmc::engine::LMBlockerMatData::prep_block_ou_contractions(const std::vector<double> & dr,
35 const formic::Matrix<double> & ou_mat,
36 std::vector<formic::ColVec<double> > & cont_vec) {
37
38 // loop over blocks
39 for (int b = 0; b < this->nb(); b++) {
40
41 const int ibeg = 1 + m_block_beg.at(b);
42 const int len = m_block_len.at(b);
43
44 formic::ColVec<double> & cont = cont_vec.at(b);
45 for (int i = 0; i < cont.size(); i++)
46 cont.at(i) = 0.0;
47
48 for (int k = 0; k < m_nou; k++) {
49 for (int j = ibeg; j < ibeg+len; j++) {
50 cont.at(k) += dr.at(j) * ou_mat.at(j-1,k);
51 }
52 }
53 }
54 }
55
56 ////////////////////////////////////////////////////////////////////////////////////////////////
57 /// \brief Function that create a matrix in the basis of a block of variables and older updates
58 /// from a different block
59 ///
60 /// \param[in] b block index
61 /// \param[in] x block index
62 /// \param[out] mat output matrix
63 ///
64 ////////////////////////////////////////////////////////////////////////////////////////////////
prep_lm_block_plus_other_ou_matrix(const int b,const int x,formic::Matrix<double> & mat)65 void cqmc::engine::LMBlockerMatData::prep_lm_block_plus_other_ou_matrix(const int b, const int x, formic::Matrix<double> & mat) {
66
67 // first check that if x and b is the same block
68 if ( x == b )
69 throw formic::Exception("b and x must be different in prep_lm_block_plus_other_ou_matrix");
70
71 // get the length of this block
72 const int len = this->bl(b);
73
74 // get the dimension of this matrix
75 const int dim = 1 + len + m_nou;
76
77 const int y = x - ( x > b ? 1 : 0 );
78
79 // size the output matrix correctly
80 mat.reset(dim, dim);
81
82 // <wfn|wfn> element
83 mat.at(0,0) = m_ww[0];
84 //std::cout << "in prep_lm_block_plus_other_ou_matrix mat(0,0) is " << m_ww << std::endl;
85
86 // <wfn|var>
87 for (int i = 0; i < len; i++)
88 mat.at(0, 1+i) = m_wv[0].at(b).at(i);
89
90 // <var|wfn>
91 for (int i = 0; i < len; i++)
92 mat.at(1+i, 0) = m_vw[0].at(b).at(i);
93
94 // <var|var>
95 for (int i = 0; i < len; i++) {
96 for (int j = 0; j < len; j++) {
97 mat.at(1+i,1+j) = m_vv[0].at(b).at(i,j);
98 }
99 }
100
101 // <wfn|old_update>
102 for (int k = 0; k < m_nou; k++)
103 mat.at(0, 1+len+k) = m_wo[0].at(x).at(k);
104
105 // <old_update_wfn>
106 for (int k = 0; k < m_nou; k++)
107 mat.at(1+len+k, 0) = m_ow[0].at(x).at(k);
108
109 // <var|old_update>
110 for (int i = 0; i < len; i++) {
111 for (int k = 0; k < m_nou; k++) {
112 mat.at(1+i, 1+len+k) = m_vo[0].at(b).at(i, y*m_nou+k);
113 }
114 }
115
116 // <old_update|var>
117 for (int k = 0; k < m_nou; k++) {
118 for (int i = 0; i < len; i++) {
119 mat.at(1+len+k, 1+i) = m_ov[0].at(b).at(y*m_nou+k, i);
120 }
121 }
122
123 // <old_update|old_update>
124 for (int k = 0; k < m_nou; k++) {
125 for (int l = 0; l < m_nou; l++) {
126 mat.at(1+len+k, 1+len+l) = m_oo[0].at(x).at(k,l);
127 }
128 }
129 }
130
131
132 ////////////////////////////////////////////////////////////////////////////////////////////////
133 /// \brief Function that accumulates contribution to block matrices for this sample
134 ///
135 /// \param[in] d weight for this sample
136 /// \param[in] lr left vector for outer product
137 /// \param[in] rr right vector for outer product
138 /// \param[in] ou_mat matrix storing the old update coefficients
139 ///
140 ////////////////////////////////////////////////////////////////////////////////////////////////
acc(const double d,const std::vector<double> & lr,const std::vector<double> & rr,const formic::Matrix<double> & ou_mat)141 void cqmc::engine::LMBlockerMatData::acc(const double d, const std::vector<double> & lr, const std::vector<double> &rr, const formic::Matrix<double> & ou_mat) {
142
143 // get the thread number
144 int myThread = omp_get_thread_num();
145
146 // check to see if the input vector is of the correct size
147 if ( lr.size() != 1 + this->tot_rows(m_vv[myThread]) )
148 throw formic::Exception("lr vector length was %i but should be %i LMBlockerMatData::acc") % lr.size() % ( 1 + this->tot_rows(m_vv[myThread]) );
149 if ( rr.size() != 1 + this->tot_rows(m_vv[myThread]) )
150 throw formic::Exception("rr vector length was %i but should be %i LMBlockerMatData::acc") % rr.size() % ( 1 + this->tot_rows(m_vv[myThread]) );
151
152 // prep intermediates for old updates
153 this->prep_block_ou_contractions(lr, ou_mat, m_boulr[myThread]);
154 this->prep_block_ou_contractions(rr, ou_mat, m_bourr[myThread]);
155
156 // <wfn|wfn>
157 m_ww[myThread] += d * lr.at(0) * rr.at(0);
158
159 // loop over blocks
160 for (int b = 0; b < this->nb(); b++) {
161
162 // beginning index
163 const int ibeg = 1 + m_block_beg.at(b);
164
165 // block length
166 const int len = m_block_len.at(b);
167
168 for (int i = 0; i < len; i++) {
169
170 // <wfn|var>
171 m_wv[myThread].at(b).at(i) += d * lr.at(0) * rr.at(ibeg + i);
172
173 // <var|wfn>
174 m_vw[myThread].at(b).at(i) += d * lr.at(ibeg + i) * rr.at(0);
175
176 }
177
178 for (int k = 0; k < m_nou; k++) {
179
180 // <wfn|old_updates>
181 m_wo[myThread].at(b).at(k) += d * lr.at(0) * m_bourr[myThread].at(b).at(k);
182
183 // <old_updates|wfn>
184 m_ow[myThread].at(b).at(k) += d * m_boulr[myThread].at(b).at(k) * rr.at(0);
185 }
186
187 // <var|var>
188 { formic::Matrix<double> & vv_mat = m_vv[myThread].at(b);
189 for (int i = 0; i < len; i++) {
190 for (int j = 0; j < len; j++) {
191 vv_mat.at(i,j) += d * lr.at(ibeg+i) * rr.at(ibeg+j);
192 }
193 }
194 }
195
196 // <var|old_update> note this is for var in the current block and old-update in all other blocks
197 { formic::Matrix<double> & vo_mat = m_vo[myThread].at(b);
198 for (int x = 0, y = 0; x < this->nb(); x++) {
199 if ( x == b )
200 continue;
201 const formic::ColVec<double> & rr_vec = m_bourr[myThread].at(x);
202 for (int o = 0; o < m_nou; o++) {
203 for (int i = 0; i < len; i++) {
204 vo_mat.at(i,y*m_nou+o) += d * lr.at(ibeg+i) * rr_vec.at(o);
205 }
206 }
207 y++;
208 }
209 }
210
211 // <old_update|var> note this is for var in the current block and old-update in all other blocks
212 { formic::Matrix<double> & ov_mat = m_ov[myThread].at(b);
213 for (int i = 0; i < len; i++) {
214 for (int x = 0, y = 0; x < this->nb(); x++) {
215 if ( x == b )
216 continue;
217 const formic::ColVec<double> & lr_vec = m_boulr[myThread].at(x);
218 for (int k = 0; k < m_nou; k++) {
219 ov_mat.at(m_nou*y+k, i) += d * lr_vec.at(k) * rr.at(ibeg+i);
220 }
221 y++;
222 }
223 }
224 }
225
226 // <old_update|old_update>
227 { formic::Matrix<double> & oo_mat = m_oo[myThread].at(b);
228 for (int k = 0; k < m_nou; k++) {
229 for (int l = 0; l < m_nou; l++) {
230 oo_mat.at(k,l) += d * m_boulr[myThread].at(b).at(k) * m_bourr[myThread].at(b).at(l);
231 }
232 }
233 }
234 }
235 }
236
237 ////////////////////////////////////////////////////////////////////////////////////////////////
238 /// \brief Function that finalizes the accumulation by dividing matrices total weight
239 ///
240 ////////////////////////////////////////////////////////////////////////////////////////////////
finalize(const double total_weight)241 void cqmc::engine::LMBlockerMatData::finalize(const double total_weight) {
242
243 // get the number of threads
244 int NumThreads = omp_get_max_threads();
245
246 // sum over threads
247 for (int ip = 1; ip < NumThreads; ip++) {
248 m_ww[0] += m_ww[ip];
249 for (int b = 0; b < this->nb(); b++) {
250 m_wv[0].at(b) += m_wv[ip].at(b);
251 m_vw[0].at(b) += m_vw[ip].at(b);
252 m_wo[0].at(b) += m_wo[ip].at(b);
253 m_ow[0].at(b) += m_ow[ip].at(b);
254 m_ov[0].at(b) += m_ov[ip].at(b);
255 m_vo[0].at(b) += m_vo[ip].at(b);
256 m_oo[0].at(b) += m_oo[ip].at(b);
257 }
258 }
259
260 // <wfn|wfn>
261 m_ww[0] /= total_weight;
262
263 // loop over blocks
264 for (int b = 0; b < this->nb(); b++) {
265 m_wv[0].at(b) /= total_weight;
266 m_vw[0].at(b) /= total_weight;
267 m_vv[0].at(b) /= total_weight;
268 m_wo[0].at(b) /= total_weight;
269 m_ow[0].at(b) /= total_weight;
270 m_ov[0].at(b) /= total_weight;
271 m_vo[0].at(b) /= total_weight;
272 m_oo[0].at(b) /= total_weight;
273 }
274 }
275
276 ////////////////////////////////////////////////////////////////////////////////////////////////
277 /// \brief Function that finalizes the accumulation by dividing matrices total weight
278 /// across the whole processes
279 ///
280 ////////////////////////////////////////////////////////////////////////////////////////////////
mpi_finalize(const double total_weight)281 void cqmc::engine::LMBlockerMatData::mpi_finalize(const double total_weight) {
282
283 // get rank number and number of ranks
284 int my_rank = formic::mpi::rank();
285
286 // get the number of threads
287 int NumThreads = omp_get_max_threads();
288
289 // loop over blocks
290 //for (int b = 0; b < this->nb(); b++) {
291 // // print out to debug
292 // for (int i = 0; i < m_ow.at(b).size(); i++) {
293 // std::cout << m_ow.at(b).at(i) << " ";
294 // }
295 // std::cout << std::endl;
296 //}
297 //std::cout << std::endl;
298
299 // sum over threads
300 for (int ip = 1; ip < NumThreads; ip++) {
301 m_ww[0] += m_ww[ip];
302 for (int b = 0; b < this->nb(); b++) {
303 m_wv[0].at(b) += m_wv[ip].at(b);
304 m_vw[0].at(b) += m_vw[ip].at(b);
305 m_vv[0].at(b) += m_vv[ip].at(b);
306 m_wo[0].at(b) += m_wo[ip].at(b);
307 m_ow[0].at(b) += m_ow[ip].at(b);
308 m_ov[0].at(b) += m_ov[ip].at(b);
309 m_vo[0].at(b) += m_vo[ip].at(b);
310 m_oo[0].at(b) += m_oo[ip].at(b);
311 }
312 }
313
314 // <wfn|wfn>
315 double m_ww_tot = 0.0;
316 formic::mpi::reduce(&m_ww[0], &m_ww_tot, 1, MPI_SUM);
317 //MPI_Reduce(&m_ww, &m_ww_tot, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
318 m_ww[0] = m_ww_tot / total_weight;
319
320 // get space for MPI reduce
321 std::vector<formic::ColVec<double> > m_wv_tot, m_vw_tot, m_wo_tot, m_ow_tot;
322 std::vector<formic::Matrix<double> > m_vv_tot, m_vo_tot, m_ov_tot, m_oo_tot;
323 for (int i = 0; i < this->nb(); i++) {
324 m_wv_tot.push_back(formic::ColVec<double>(this->bl(i), 0.0));
325 m_vw_tot.push_back(formic::ColVec<double>(this->bl(i), 0.0));
326 m_vv_tot.push_back(formic::Matrix<double>(this->bl(i), this->bl(i), 0.0));
327 m_wo_tot.push_back(formic::ColVec<double>(m_nou, 0.0));
328 m_ow_tot.push_back(formic::ColVec<double>(m_nou, 0.0));
329 m_ov_tot.push_back(formic::Matrix<double>((this->nb()-1)*m_nou, this->bl(i), 0.0));
330 m_vo_tot.push_back(formic::Matrix<double>(this->bl(i), (this->nb()-1)*m_nou, 0.0));
331 m_oo_tot.push_back(formic::Matrix<double>(m_nou, m_nou, 0.0));
332 }
333
334 // do MPI reduce
335 for (int i = 0; i < this->nb(); i++) {
336 formic::mpi::reduce(&m_wv[0].at(i).at(0), &m_wv_tot.at(i).at(0), this->bl(i), MPI_SUM);
337 formic::mpi::reduce(&m_vw[0].at(i).at(0), &m_vw_tot.at(i).at(0), this->bl(i), MPI_SUM);
338 formic::mpi::reduce(&m_vv[0].at(i).at(0,0), &m_vv_tot.at(i).at(0,0), m_vv[0].at(i).size(), MPI_SUM);
339 formic::mpi::reduce(&m_wo[0].at(i).at(0), &m_wo_tot.at(i).at(0), m_nou, MPI_SUM);
340 formic::mpi::reduce(&m_ow[0].at(i).at(0), &m_ow_tot.at(i).at(0), m_nou, MPI_SUM);
341 formic::mpi::reduce(&m_ov[0].at(i).at(0,0), &m_ov_tot.at(i).at(0,0), m_ov[0].at(i).size(), MPI_SUM);
342 formic::mpi::reduce(&m_vo[0].at(i).at(0,0), &m_vo_tot.at(i).at(0,0), m_vo[0].at(i).size(), MPI_SUM);
343 formic::mpi::reduce(&m_oo[0].at(i).at(0,0), &m_oo_tot.at(i).at(0,0), m_oo[0].at(i).size(), MPI_SUM);
344 }
345
346 // evaluate the average across all processors
347 if ( my_rank == 0 ) {
348
349 // loop over blocks
350 for (int b = 0; b < this->nb(); b++) {
351 m_vw[0].at(b) = m_vw_tot.at(b) / total_weight;
352 m_wv[0].at(b) = m_wv_tot.at(b) / total_weight;
353 m_vv[0].at(b) = m_vv_tot.at(b) / total_weight;
354 m_ow[0].at(b) = m_ow_tot.at(b) / total_weight;
355 m_wo[0].at(b) = m_wo_tot.at(b) / total_weight;
356 m_vo[0].at(b) = m_vo_tot.at(b) / total_weight;
357 m_ov[0].at(b) = m_ov_tot.at(b) / total_weight;
358 m_oo[0].at(b) = m_oo_tot.at(b) / total_weight;
359 // print out to debug
360 //for (int i = 0; i < m_ow.at(b).size(); i++) {
361 // std::cout << m_ow.at(b).at(i) << " ";
362 //}
363 //std::cout << std::endl;
364 }
365 }
366 }
367
368 /////////////////////////////////////////////////////////////////////////////////////////////////
369 /// \brief Function that resets the matrices
370 ///
371 /////////////////////////////////////////////////////////////////////////////////////////////////
reset(const int nv,const int nblock,const int nou)372 void cqmc::engine::LMBlockerMatData::reset(const int nv, const int nblock, const int nou) {
373
374 m_nou = nou;
375
376 // get block information
377 cqmc::engine::brlm_get_block_info(nv, nblock, m_block_beg, m_block_end, m_block_len);
378
379 // get the maximum number of threads
380 int NumThreads = omp_get_max_threads();
381
382 m_ww.assign(NumThreads, 0.0);
383
384 m_wv.clear();
385 m_wv.resize(NumThreads);
386 for (int ip = 0; ip < NumThreads; ip++) {
387 for (int i = 0; i < this->nb(); i++) {
388 m_wv[ip].push_back(formic::ColVec<double>(this->bl(i), 0.0));
389 }
390 }
391
392 m_vw.clear();
393 m_vw.resize(NumThreads);
394 for (int ip = 0; ip < NumThreads; ip++) {
395 for (int i = 0; i < this->nb(); i++) {
396 m_vw[ip].push_back(formic::ColVec<double>(this->bl(i), 0.0));
397 }
398 }
399
400 m_vv.clear();
401 m_vv.resize(NumThreads);
402 for (int ip = 0; ip < NumThreads; ip++) {
403 for (int i = 0; i < this->nb(); i++) {
404 m_vv[ip].push_back(formic::Matrix<double>(this->bl(i), this->bl(i), 0.0));
405 }
406 }
407
408 m_wo.clear();
409 m_wo.resize(NumThreads);
410 for (int ip = 0; ip < NumThreads; ip++) {
411 for (int i = 0; i < this->nb(); i++) {
412 m_wo[ip].push_back(formic::ColVec<double>(m_nou, 0.0));
413 }
414 }
415
416 m_ow.clear();
417 m_ow.resize(NumThreads);
418 for (int ip = 0; ip < NumThreads; ip++) {
419 for (int i = 0; i < this->nb(); i++) {
420 m_ow[ip].push_back(formic::ColVec<double>(m_nou, 0.0));
421 }
422 }
423
424 m_vo.clear();
425 m_vo.resize(NumThreads);
426 for (int ip = 0; ip < NumThreads; ip++) {
427 for (int i = 0; i < this->nb(); i++) {
428 m_vo[ip].push_back(formic::Matrix<double>(this->bl(i), (this->nb()-1)*m_nou, 0.0));
429 }
430 }
431
432 m_ov.clear();
433 m_ov.resize(NumThreads);
434 for (int ip = 0; ip < NumThreads; ip++) {
435 for (int i = 0; i < this->nb(); i++) {
436 m_ov[ip].push_back(formic::Matrix<double>((this->nb()-1)*m_nou, this->bl(i), 0.0));
437 }
438 }
439
440 m_oo.clear();
441 m_oo.resize(NumThreads);
442 for (int ip = 0; ip < NumThreads; ip++) {
443 for (int i = 0; i < this->nb(); i++) {
444 m_oo[ip].push_back(formic::Matrix<double>(m_nou, m_nou, 0.0));
445 }
446 }
447
448 m_boulr.clear();
449 m_bourr.clear();
450 m_boulr.resize(NumThreads);
451 m_bourr.resize(NumThreads);
452 for (int ip = 0; ip < NumThreads; ip++) {
453 for (int i = 0; i < this->nb(); i++) {
454 m_boulr[ip].push_back(formic::ColVec<double>(m_nou, 0.0));
455 m_bourr[ip].push_back(formic::ColVec<double>(m_nou, 0.0));
456 }
457 }
458 }
459
460