DOCI-Exact  1.0
DM2.cpp
Go to the documentation of this file.
1 #include <algorithm>
2 #include <functional>
3 #include <hdf5.h>
4 #include <assert.h>
5 #include <omp.h>
6 #include <chrono>
7 
8 #include "DM2.h"
9 #include "DOCIHamtilonian.h"
10 #include "lapack.h"
11 
12 using namespace doci;
13 
14 std::unique_ptr<helpers::matrix> doci::DM2::sp2tp = nullptr;
15 std::unique_ptr<helpers::matrix> doci::DM2::tp2sp = nullptr;
16 
17 // this helps to check the return codes of HDF5 calls
18 #define HDF5_STATUS_CHECK(status) if(status < 0) std::cerr << __FILE__ << ":" << __LINE__ << ": Problem with writing to file. Status code=" << status << std::endl;
19 
26 DM2::DM2(unsigned int n_sp, unsigned int n)
27 {
28  if(!sp2tp || !tp2sp)
29  fill_lists(n_sp);
30 
31  block.reset(new helpers::matrix(n_sp, n_sp));
32  diag.resize((n_sp*(n_sp-1))/2);
33 
34  this->N = n;
35 }
36 
37 
43 DM2::DM2(const Molecule &mol)
44 {
45  auto n_sp = mol.get_n_sp();
46 
47  if(!sp2tp || !tp2sp)
48  fill_lists(n_sp);
49 
50  block.reset(new helpers::matrix(n_sp, n_sp));
51  diag.resize((n_sp*(n_sp-1))/2);
52  N = mol.get_n_electrons();
53 }
54 
55 DM2::DM2(const DM2 &orig)
56 {
57  assert(sp2tp && tp2sp);
58 
59  block.reset(new helpers::matrix(*orig.block));
60  diag = orig.diag;
61  N = orig.N;
62 }
63 
64 DM2::DM2(DM2 &&orig)
65 {
66  block = std::move(orig.block);
67  diag = std::move(orig.diag);
68  N = orig.N;
69 }
70 
71 DM2& DM2::operator=(const DM2 &orig)
72 {
73  block.reset(new helpers::matrix(*orig.block));
74  diag = orig.diag;
75  N = orig.N;
76 
77  return *this;
78 }
79 
80 DM2& DM2::operator=(DM2 &&orig)
81 {
82  block = std::move(orig.block);
83  diag = std::move(orig.diag);
84  N = orig.N;
85 
86  return *this;
87 }
88 
94 DM2& DM2::operator=(double val)
95 {
96  (*block) = val;
97  std::fill(diag.begin(), diag.end(), val);
98 
99  return *this;
100 }
101 
111 double DM2::operator()(int a, int b, int c, int d) const
112 {
113  if(a==b || c==d)
114  return 0;
115 
116  int sign = 1;
117 
118  if(a > b)
119  sign *= -1;
120 
121  if(c > d)
122  sign *= -1;
123 
124  int i = (*sp2tp)(a,b);
125  int j = (*sp2tp)(c,d);
126 
127  if(i<block->getn() && j<block->getn())
128  return sign * (*block)(i,j);
129  else if(i==j)
130  return sign * diag[(i-block->getn())%diag.size()];
131  else
132  return 0;
133 }
134 
140 DM2& DM2::operator+=(const DM2 &a)
141 {
142  (*block) += (*a.block);
143 // std::transform(diag.begin(), diag.end(), a.diag.begin(), diag.begin(), std::plus<double>());
144 
145  int dim = diag.size();
146  int inc = 1;
147  double alpha = 1.0;
148  double *tmp = const_cast<double *>(a.diag.data());
149 
150  daxpy_(&dim,&alpha,tmp,&inc,diag.data(),&inc);
151 
152  return *this;
153 }
154 
159 void DM2::fill_lists(unsigned int n_sp)
160 {
161  auto L = n_sp;
162  auto M = 2*n_sp;
163  auto n_tp = M*(M-1)/2;
164 
165  sp2tp.reset(new helpers::matrix(M,M));
166  (*sp2tp) = -1; // if you use something you shouldn't, this will case havoc
167 
168  tp2sp.reset(new helpers::matrix(n_tp,2));
169  (*tp2sp) = -1; // if you use something you shouldn't, this will case havoc
170 
171  auto tel = 0;
172 
173  // a \bar a
174  for(int a=0;a<L;a++)
175  (*sp2tp)(a,a+L) = (*sp2tp)(a+L,a) = tel++;
176 
177  // a b
178  for(int a=0;a<L;a++)
179  for(int b=a+1;b<L;b++)
180  (*sp2tp)(a,b) = (*sp2tp)(b,a) = tel++;
181 
182  // \bar a \bar b
183  for(int a=L;a<M;a++)
184  for(int b=a+1;b<M;b++)
185  (*sp2tp)(a,b) = (*sp2tp)(b,a) = tel++;
186 
187  // a \bar b ; a \bar b
188  for(int a=0;a<L;a++)
189  for(int b=L+a+1;b<M;b++)
190  if(a%L!=b%L)
191  (*sp2tp)(a,b) = (*sp2tp)(b,a) = tel++;
192 
193  // \bar a b ; \bar a b
194  for(int a=L;a<M;a++)
195  for(int b=a%L+1;b<L;b++)
196  if(a%L!=b%L)
197  (*sp2tp)(a,b) = (*sp2tp)(b,a) = tel++;
198 
199  assert(tel == n_tp);
200 
201  for(int a=0;a<M;a++)
202  for(int b=a+1;b<M;b++)
203  {
204  (*tp2sp)((*sp2tp)(a,b),0) = a;
205  (*tp2sp)((*sp2tp)(a,b),1) = b;
206  }
207 }
208 
213 void DM2::WriteToFile(std::string filename) const
214 {
215  hid_t file_id, group_id, dataset_id, attribute_id, dataspace_id;
216  herr_t status;
217 
218  file_id = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
219 
220  group_id = H5Gcreate(file_id, "/RDM", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
221 
222  hsize_t dimblock = block->getn() * block->getn();
223 
224  dataspace_id = H5Screate_simple(1, &dimblock, NULL);
225 
226  dataset_id = H5Dcreate(group_id, "Block", H5T_IEEE_F64LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
227 
228  double *data = const_cast<helpers::matrix &>(*block).getpointer();
229 
230  status = H5Dwrite(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
231  HDF5_STATUS_CHECK(status);
232 
233  status = H5Sclose(dataspace_id);
234  HDF5_STATUS_CHECK(status);
235 
236  status = H5Dclose(dataset_id);
237  HDF5_STATUS_CHECK(status);
238 
239  dimblock = diag.size();
240 
241  dataspace_id = H5Screate_simple(1, &dimblock, NULL);
242 
243  dataset_id = H5Dcreate(group_id, "Vector", H5T_IEEE_F64LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
244 
245  status = H5Dwrite(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, diag.data());
246  HDF5_STATUS_CHECK(status);
247 
248  status = H5Sclose(dataspace_id);
249  HDF5_STATUS_CHECK(status);
250 
251  status = H5Dclose(dataset_id);
252  HDF5_STATUS_CHECK(status);
253 
254 
255  dataspace_id = H5Screate(H5S_SCALAR);
256  unsigned int L = block->getn();
257 
258  attribute_id = H5Acreate (group_id, "L", H5T_STD_U32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT);
259  status = H5Awrite (attribute_id, H5T_NATIVE_UINT, &L );
260  HDF5_STATUS_CHECK(status);
261 
262  status = H5Aclose(attribute_id);
263  HDF5_STATUS_CHECK(status);
264 
265  attribute_id = H5Acreate (group_id, "N", H5T_STD_U32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT);
266  status = H5Awrite (attribute_id, H5T_NATIVE_UINT, &N );
267  HDF5_STATUS_CHECK(status);
268 
269  status = H5Aclose(attribute_id);
270  HDF5_STATUS_CHECK(status);
271 
272  status = H5Sclose(dataspace_id);
273  HDF5_STATUS_CHECK(status);
274 
275  status = H5Gclose(group_id);
276  HDF5_STATUS_CHECK(status);
277 
278  status = H5Fclose(file_id);
279  HDF5_STATUS_CHECK(status);
280 }
281 
287 DM2 DM2::ReadFromFile(std::string filename)
288 {
289  hid_t file_id, dataset_id, group_id, attribute_id;
290  herr_t status;
291 
292  file_id = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
293  HDF5_STATUS_CHECK(file_id);
294 
295  group_id = H5Gopen(file_id, "/RDM", H5P_DEFAULT);
296  HDF5_STATUS_CHECK(group_id);
297 
298  attribute_id = H5Aopen(group_id, "L", H5P_DEFAULT);
299  HDF5_STATUS_CHECK(attribute_id);
300 
301  unsigned int L;
302  status = H5Aread(attribute_id, H5T_NATIVE_UINT, &L);
303  HDF5_STATUS_CHECK(status);
304 
305  status = H5Aclose(attribute_id);
306  HDF5_STATUS_CHECK(status);
307 
308  attribute_id = H5Aopen(group_id, "N", H5P_DEFAULT);
309  HDF5_STATUS_CHECK(attribute_id);
310 
311  unsigned int N;
312  status = H5Aread(attribute_id, H5T_NATIVE_UINT, &N);
313  HDF5_STATUS_CHECK(status);
314 
315  status = H5Aclose(attribute_id);
316  HDF5_STATUS_CHECK(status);
317 
318  DM2 dm2(L,N);
319 
320  dataset_id = H5Dopen(file_id, "/RDM/Block", H5P_DEFAULT);
321  HDF5_STATUS_CHECK(dataset_id);
322 
323  status = H5Dread(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, dm2.block->getpointer());
324  HDF5_STATUS_CHECK(status);
325 
326  status = H5Dclose(dataset_id);
327  HDF5_STATUS_CHECK(status);
328 
329  dataset_id = H5Dopen(file_id, "/RDM/Vector", H5P_DEFAULT);
330  HDF5_STATUS_CHECK(dataset_id);
331 
332  status = H5Dread(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, dm2.diag.data());
333  HDF5_STATUS_CHECK(status);
334 
335  status = H5Dclose(dataset_id);
336  HDF5_STATUS_CHECK(status);
337 
338  status = H5Gclose(group_id);
339  HDF5_STATUS_CHECK(status);
340 
341  status = H5Fclose(file_id);
342  HDF5_STATUS_CHECK(status);
343 
344  return dm2;
345 }
346 
350 unsigned int DM2::get_n_electrons() const
351 {
352  return N;
353 }
354 
358 unsigned int DM2::get_n_sp() const
359 {
360  return block->getn();
361 }
362 
369 void DM2::Build(Permutation &perm, std::vector<double> &eigv)
370 {
371  auto num_t = omp_get_max_threads();
372  unsigned long long num_elems = (eigv.size()*1ul*(eigv.size()+1ul))/2;
373  unsigned long long size_part = num_elems/num_t + 1;
374 
375  // every thread should process the lines between i and i+1
376  // with i the thread number
377  std::vector<unsigned int> workload(num_t+1);
378  workload.front() = 0;
379  workload.back() = eigv.size();
380 
381  for(int i=1;i<num_t;i++)
382  {
383  auto num_lines = workload[i-1];
384  unsigned long long num_elems = 0;
385 
386  while(num_elems < size_part)
387  num_elems += eigv.size() - num_lines++;
388 
389  if(num_lines > eigv.size())
390  num_lines = eigv.size();
391 
392  workload[i] = num_lines;
393  }
394 
395  std::vector< std::unique_ptr<DM2> > dm2_parts(num_t);
396 
397  std::cout << "Running with " << num_t << " threads." << std::endl;
398 
399  perm.reset();
400 
401 #pragma omp parallel
402  {
403  auto start = std::chrono::high_resolution_clock::now();
404  auto me = omp_get_thread_num();
405 
406  dm2_parts[me].reset(new DM2(block->getn(),N));
407  (*dm2_parts[me]) = 0;
408 
409  Permutation my_perm(perm);
410 
411  for(auto idx_begin=0;idx_begin<workload[me];++idx_begin)
412  my_perm.next();
413 
414  auto vec_copy = eigv;
415 
416  build_iter(my_perm, vec_copy, workload[me], workload[me+1], (*dm2_parts[me]));
417 
418  auto end = std::chrono::high_resolution_clock::now();
419 
420 #pragma omp critical
421  std::cout << me << "\t" << std::chrono::duration_cast<std::chrono::duration<double,std::ratio<1>>>(end-start).count() << " s" << std::endl;
422  }
423 
424  // add everything
425  (*this) = 0;
426  for(auto &cur_dm2: dm2_parts)
427  (*this) += (*cur_dm2);
428 }
429 
430 void DM2::build_iter(Permutation& perm, std::vector<double> &eigv, unsigned int i_start, unsigned int i_end, DM2 &cur_2dm)
431 {
432  auto& perm_bra = perm;
433 
434  for(unsigned int i=i_start;i<i_end;++i)
435  {
436  const auto bra = perm_bra.get();
437 
438  Permutation perm_ket(perm_bra);
439 
440  auto cur = bra;
441 
442  // find occupied orbitals
443  while(cur)
444  {
445  // select rightmost up state in the ket
446  auto ksp = cur & (~cur + 1);
447  // set it to zero
448  cur ^= ksp;
449 
450  // number of the orbital
451  auto s = DOCIHamiltonian::CountBits(ksp-1);
452 
453  // in this case: s == (*sp2tp)(s,s+L)
454  (*cur_2dm.block)(s,s) += eigv[i] * eigv[i];
455 
456  auto cur2 = cur;
457 
458  while(cur2)
459  {
460  // select rightmost up state in the ket
461  auto ksp2 = cur2 & (~cur2 + 1);
462  // set it to zero
463  cur2 ^= ksp2;
464 
465  // number of the orbital
466  auto r = DOCIHamiltonian::CountBits(ksp2-1);
467 
468  unsigned int idx = (*sp2tp)(r,s);
469  // find correct relative index
470  idx -= block->getn();
471  idx %= diag.size();
472 
473  cur_2dm.diag[idx] += eigv[i] * eigv[i];
474  }
475  }
476 
477 
478  for(unsigned int j=i+1;j<eigv.size();++j)
479  {
480  const auto ket = perm_ket.next();
481 
482  const auto diff = bra ^ ket;
483 
484  // this means 4 orbitals are different
485  if(DOCIHamiltonian::CountBits(diff) == 2)
486  {
487  auto diff_c = diff;
488 
489  // select rightmost up state in the ket
490  auto ksp1 = diff_c & (~diff_c + 1);
491  // set it to zero
492  diff_c ^= ksp1;
493 
494  auto ksp2 = diff_c & (~diff_c + 1);
495 
496  // number of the orbital
497  auto r = DOCIHamiltonian::CountBits(ksp1-1);
498  auto s = DOCIHamiltonian::CountBits(ksp2-1);
499 
500  // in this case:
501  // r == (*sp2tp)(r,r+L)
502  // s == (*sp2tp)(s,s+L)
503  (*cur_2dm.block)(r,s) += eigv[i] * eigv[j];
504  (*cur_2dm.block)(s,r) += eigv[i] * eigv[j];
505  }
506  }
507 
508  perm_bra.next();
509  }
510 }
511 
512 std::ostream &operator<<(std::ostream &output,doci::DM2 &dm2)
513 {
514  auto L = dm2.get_n_sp();
515  output << "Block: " << std::endl;
516  for(int i=0;i<L;i++)
517  for(int j=i;j<L;j++)
518  output << i << "\t" << j << "\t|\t" << (*dm2.tp2sp)(i,0) << " " << (*dm2.tp2sp)(i,1) << " ; " << (*dm2.tp2sp)(j,0) << " " << (*dm2.tp2sp)(j,1) << "\t\t" << (*dm2.block)(i,j) << std::endl;
519 
520  output << std::endl;
521 
522  output << "Vector (4x): " << std::endl;
523  for(int i=0;i<dm2.diag.size();i++)
524  output << i << "\t|\t" << (*dm2.tp2sp)(L+i,0) << " " << (*dm2.tp2sp)(L+i,1) << "\t\t" << dm2.diag[i] << std::endl;
525 
526  return output;
527 }
528 
533 void DM2::BuildHamiltonian(const Molecule &mol)
534 {
535  auto L = block->getn();
536 
537  // make our life easier
538  auto calc_elem = [this,&mol,L] (int i, int j) {
539  int a = (*tp2sp)(i,0);
540  int b = (*tp2sp)(i,1);
541  int c = (*tp2sp)(j,0);
542  int d = (*tp2sp)(j,1);
543 
544  int a_ = a % L;
545  int b_ = b % L;
546  int c_ = c % L;
547  int d_ = d % L;
548 
549  double result = 0;
550 
551  // sp terms
552  if(i==j)
553  result += (mol.getT(a_,a_) + mol.getT(b_,b_))/(N - 1.0);
554 
555  // tp terms:
556 
557  // a \bar a ; b \bar b
558  if(b==(a+L) && d==(c+L))
559  result += mol.getV(a_,b_,c_,d_);
560 
561  // a b ; a b
562  // \bar a \bar b ; \bar a \bar b
563  if(i==j && a/L == b/L && a!=b)
564  result += mol.getV(a_,b_,c_,d_) - mol.getV(a_,b_,d_,c_);
565 
566  // a \bar b ; a \bar b
567  // \bar a b ; \bar a b
568  if(i==j && a/L != b/L && a%L!=b%L)
569  result += mol.getV(a_,b_, c_,d_);
570 
571  return result;
572  };
573 
574  for(int i=0;i<block->getn();++i)
575  for(int j=i;j<block->getn();++j)
576  (*block)(i,j) = (*block)(j,i) = calc_elem(i,j);
577 
578  for(int i=0;i<diag.size();i++)
579  // keep in mind that the degen of the vector is 4. We need prefactor of 2, so
580  // we end up with 0.5
581  diag[i] = 0.5*calc_elem(L+i,L+i) + 0.5*calc_elem(L*L+i,L*L+i);
582 }
583 
589 double DM2::Dot(const DM2 &x) const
590 {
591  double result = 0;
592 
593  int n = block->getn()*block->getn();
594  int inc = 1;
595 
596  result += ddot_(&n,block->getpointer(),&inc,x.block->getpointer(),&inc);
597 
598  n = diag.size();
599  result += 4 * ddot_(&n,diag.data(),&inc,x.diag.data(),&inc);
600 
601  return result;
602 }
603 
607 double DM2::Trace() const
608 {
609  double result = 0;
610  for(auto elem : diag)
611  result += elem;
612 
613  return block->trace() + 4 * result;
614 }
615 
626 std::pair<double,bool> DM2::find_min_angle(int k, int l, double start_angle, std::function<double(int,int)> &T, std::function<double(int,int,int,int)> &V) const
627 {
628  assert(k!=l);
629 
630  const int L = block->getn();
631 
632  double theta = start_angle;
633 
634  const DM2 &rdm = *this;
635 
636  double cos2 = 2.0/(N-1.0)*(T(k,k)*rdm(k,k+L,k,k+L)+T(l,l)*rdm(l,l+L,l,l+L));
637 
638  double sin2 = 2.0/(N-1.0)*(T(l,l)*rdm(k,k+L,k,k+L)+T(k,k)*rdm(l,l+L,l,l+L));
639 
640  // 2sincos actually
641  double sincos = 2.0/(N-1.0)*T(k,l)*(rdm(l,l+L,l,l+L)-rdm(k,k+L,k,k+L));
642 
643  for(int a=0;a<L;a++)
644  {
645  if(a==k || a==l)
646  continue;
647 
648  cos2 += 2*V(k,k,a,a)*rdm(k,k+L,a,a+L)+2*V(l,l,a,a)*rdm(l,l+L,a,a+L)+2*(2*V(k,a,k,a)-V(k,a,a,k)+2.0/(N-1.0)*T(k,k))*rdm(k,a,k,a)+2*(2*V(l,a,l,a)-V(l,a,a,l)+2.0/(N-1.0)*T(l,l))*rdm(l,a,l,a);
649 
650  sin2 += 2*V(l,l,a,a)*rdm(k,k+L,a,a+L)+2*V(k,k,a,a)*rdm(l,l+L,a,a+L)+2*(2*V(k,a,k,a)-V(k,a,a,k)+2.0/(N-1.0)*T(k,k))*rdm(l,a,l,a)+2*(2*V(l,a,l,a)-V(l,a,a,l)+2.0/(N-1.0)*T(l,l))*rdm(k,a,k,a);
651 
652  sincos += 2*V(k,l,a,a)*(rdm(l,l+L,a,a+L)-rdm(k,k+L,a,a+L))+2*(2*V(k,a,l,a)-V(k,a,a,l)+2.0/(N-1.0)*T(k,l))*(rdm(l,a,l,a)-rdm(k,a,k,a));
653  }
654 
655  const double cos4 = V(k,k,k,k)*rdm(k,k+L,k,k+L)+V(l,l,l,l)*rdm(l,l+L,l,l+L)+2*V(k,k,l,l)*rdm(k,k+L,l,l+L)+2*(2*V(k,l,k,l)-V(k,k,l,l))*rdm(k,l,k,l);
656 
657  const double sin4 = V(k,k,k,k)*rdm(l,l+L,l,l+L)+V(l,l,l,l)*rdm(k,k+L,k,k+L)+2*V(k,k,l,l)*rdm(k,k+L,l,l+L)+2*(2*V(k,l,k,l)-V(k,k,l,l))*rdm(k,l,k,l);
658 
659  // 2 x
660  const double cos2sin2 = (2*V(k,k,l,l)+V(k,l,k,l))*(rdm(k,k+L,k,k+L)+rdm(l,l+L,l,l+L))+((V(k,k,k,k)+V(l,l,l,l)-2*(V(k,l,k,l)+V(k,k,l,l))))*rdm(k,k+L,l,l+L)+(V(k,k,k,k)+V(l,l,l,l)-6*V(k,k,l,l)+2*V(k,l,k,l))*rdm(k,l,k,l);
661 
662  // 4 x
663  const double sin3cos = V(k,l,k,k)*rdm(l,l+L,l,l+L)-V(k,l,l,l)*rdm(k,k+L,k,k+L)-(V(k,l,k,k)-V(k,l,l,l))*(rdm(k,k+L,l,l+L)+rdm(k,l,k,l));
664 
665  // 4 x
666  const double cos3sin = V(k,l,l,l)*rdm(l,l+L,l,l+L)-V(k,l,k,k)*rdm(k,k+L,k,k+L)+(V(k,l,k,k)-V(k,l,l,l))*(rdm(k,k+L,l,l+L)+rdm(k,l,k,l));
667 
668  // A*cos(t)^4+B*sin(t)^4+C*cos(t)^2+D*sin(t)^2+2*E*cos(t)*sin(t)+2*F*cos(t)^2*sin(t)^2+4*G*sin(t)*cos(t)^3+4*H*sin(t)^3*cos(t)
669 
670  // (16*G-16*H)*cos(t)^4+(-4*A-4*B+8*F)*sin(t)*cos(t)^3+(4*E-12*G+20*H)*cos(t)^2+(4*B-2*C+2*D-4*F)*sin(t)*cos(t)-2*E-4*H
671  auto gradient = [&] (double theta) -> double {
672  double cos = std::cos(theta);
673  double sin = std::sin(theta);
674 
675  double res = 16*(cos3sin-sin3cos)*cos*cos*cos*cos - 4*(cos4+sin4-2*cos2sin2)*sin*cos*cos*cos + 4*(sincos-3*cos3sin+5*sin3cos)*cos*cos + 2*(2*sin4-cos2+sin2-2*cos2sin2)*sin*cos-2*sincos-4*sin3cos;
676 
677  return res;
678  };
679 
680  // (-16*A-16*B+32*F)*cos(t)^4+(-64*G+64*H)*sin(t)*cos(t)^3+(12*A+20*B-4*C+4*D-32*F)*cos(t)^2+(-8*E+24*G-40*H)*sin(t)*cos(t)-4*B+2*C-2*D+4*F
681  auto hessian = [&] (double theta) -> double {
682  double cos = std::cos(theta);
683  double sin = std::sin(theta);
684 
685  double res = -16*(cos4+sin4-2*cos2sin2)*cos*cos*cos*cos+64*(sin3cos-cos3sin)*sin*cos*cos*cos+4*(3*cos4+5*sin4-cos2+sin2-8*cos2sin2)*cos*cos-8*(sincos-3*cos3sin+5*sin3cos)*sin*cos+2*(cos2-2*sin4-sin2+2*cos2sin2);
686 
687  return res;
688  };
689 
690 // int Na = 5000;
691 // for(int i=0;i<Na;i++)
692 // {
693 // double t = 2.0 * M_PI / (1.0*Na) * i;
694 // std::cout << t << "\t" << calc_rotate(k,l,t,T,V) << "\t" << gradient(t) << "\t" << hessian(t) << std::endl;
695 // }
696 
697  const int max_iters = 20;
698  const double convergence = 1e-12;
699 
700  double change = gradient(theta)*theta+hessian(theta)*theta*theta/2.0;
701 
702  // if it goes uphill, try flipping sign and try again
703  if(change>0)
704  theta *= -1;
705 
706  int iter;
707  for(iter=0;iter<max_iters;iter++)
708  {
709  double dx = gradient(theta)/hessian(theta);
710 
711  theta -= dx;
712 
713  if(fabs(dx) < convergence)
714  break;
715  }
716 
717  if(iter>=max_iters)
718  std::cout << "Reached max iters in find_min_angle: " << k << " " << l << std::endl;
719 
720  if(hessian(theta)<0)
721  std::cout << "Found max!" << std::endl;
722 
723  return std::make_pair(theta, hessian(theta)>0);
724 }
725 
736 double DM2::calc_rotate(int k, int l, double theta, std::function<double(int,int)> &T, std::function<double(int,int,int,int)> &V) const
737 {
738  assert(k!=l);
739 
740  const int L = block->getn();
741 
742  const DM2 &rdm = *this;
743 
744  double energy = 4/(N-1.0)*(T(k,k)+T(l,l)) * rdm(k,l,k,l);
745 
746  double cos2 = 2.0/(N-1.0)*(T(k,k)*rdm(k,k+L,k,k+L)+T(l,l)*rdm(l,l+L,l,l+L));
747 
748  double sin2 = 2.0/(N-1.0)*(T(l,l)*rdm(k,k+L,k,k+L)+T(k,k)*rdm(l,l+L,l,l+L));
749 
750  // 2sincos actually
751  double sincos = 2.0/(N-1.0)*T(k,l)*(rdm(l,l+L,l,l+L)-rdm(k,k+L,k,k+L));
752 
753  for(int a=0;a<L;a++)
754  {
755  if(a==k || a==l)
756  continue;
757 
758  energy += 2.0/(N-1.0) * T(a,a) * (rdm(a,a+L,a,a+L)+2*rdm(a,k,a,k)+2*rdm(a,l,a,l));
759 
760  for(int b=0;b<L;b++)
761  {
762  if(b==k || b==l)
763  continue;
764 
765  energy += 2.0/(N-1.0) * (T(a,a)+T(b,b)) * rdm(a,b,a,b);
766 
767  energy += V(a,a,b,b) * rdm(a,a+L,b,b+L);
768 
769  energy += (2*V(a,b,a,b)-V(a,b,b,a)) * rdm(a,b,a,b);
770  }
771 
772  cos2 += 2*V(k,k,a,a)*rdm(k,k+L,a,a+L)+2*V(l,l,a,a)*rdm(l,l+L,a,a+L)+2*(2*V(k,a,k,a)-V(k,a,a,k)+2.0/(N-1.0)*T(k,k))*rdm(k,a,k,a)+2*(2*V(l,a,l,a)-V(l,a,a,l)+2.0/(N-1.0)*T(l,l))*rdm(l,a,l,a);
773 
774  sin2 += 2*V(l,l,a,a)*rdm(k,k+L,a,a+L)+2*V(k,k,a,a)*rdm(l,l+L,a,a+L)+2*(2*V(k,a,k,a)-V(k,a,a,k)+2.0/(N-1.0)*T(k,k))*rdm(l,a,l,a)+2*(2*V(l,a,l,a)-V(l,a,a,l)+2.0/(N-1.0)*T(l,l))*rdm(k,a,k,a);
775 
776  sincos += 2*V(k,l,a,a)*(rdm(l,l+L,a,a+L)-rdm(k,k+L,a,a+L))+2*(2*V(k,a,l,a)-V(k,a,a,l)+2.0/(N-1.0)*T(k,l))*(rdm(l,a,l,a)-rdm(k,a,k,a));
777  }
778 
779  const double cos4 = V(k,k,k,k)*rdm(k,k+L,k,k+L)+V(l,l,l,l)*rdm(l,l+L,l,l+L)+2*V(k,k,l,l)*rdm(k,k+L,l,l+L)+2*(2*V(k,l,k,l)-V(k,k,l,l))*rdm(k,l,k,l);
780 
781  const double sin4 = V(k,k,k,k)*rdm(l,l+L,l,l+L)+V(l,l,l,l)*rdm(k,k+L,k,k+L)+2*V(k,k,l,l)*rdm(k,k+L,l,l+L)+2*(2*V(k,l,k,l)-V(k,k,l,l))*rdm(k,l,k,l);
782 
783  // 2 x
784  const double cos2sin2 = (2*V(k,k,l,l)+V(k,l,k,l))*(rdm(k,k+L,k,k+L)+rdm(l,l+L,l,l+L))+((V(k,k,k,k)+V(l,l,l,l)-2*(V(k,l,k,l)+V(k,k,l,l))))*rdm(k,k+L,l,l+L)+(V(k,k,k,k)+V(l,l,l,l)-6*V(k,k,l,l)+2*V(k,l,k,l))*rdm(k,l,k,l);
785 
786  // 4 x
787  const double sin3cos = V(k,l,k,k)*rdm(l,l+L,l,l+L)-V(k,l,l,l)*rdm(k,k+L,k,k+L)-(V(k,l,k,k)-V(k,l,l,l))*(rdm(k,k+L,l,l+L)+rdm(k,l,k,l));
788 
789  // 4 x
790  const double cos3sin = V(k,l,l,l)*rdm(l,l+L,l,l+L)-V(k,l,k,k)*rdm(k,k+L,k,k+L)+(V(k,l,k,k)-V(k,l,l,l))*(rdm(k,k+L,l,l+L)+rdm(k,l,k,l));
791 
792  const double cos = std::cos(theta);
793  const double sin = std::sin(theta);
794 
795  energy += cos*cos*cos*cos*cos4;
796 
797  energy += sin*sin*sin*sin*sin4;
798 
799  energy += cos*cos*cos2;
800 
801  energy += sin*sin*sin2;
802 
803  energy += 2*sin*cos*sincos;
804 
805  energy += 2*cos*cos*sin*sin*cos2sin2;
806 
807  energy += 4*cos*sin*sin*sin*sin3cos;
808 
809  energy += 4*cos*cos*cos*sin*cos3sin;
810 
811  return energy;
812 }
813 
814 /* vim: set ts=3 sw=3 expandtab :*/
std::pair< double, bool > find_min_angle(int k, int l, double start_angle, std::function< double(int, int)> &T, std::function< double(int, int, int, int)> &V) const
Definition: DM2.cpp:630
static DM2 ReadFromFile(const std::string)
Definition: DM2.cpp:291
double Trace() const
Definition: DM2.cpp:611
double calc_rotate(int k, int l, double theta, std::function< double(int, int)> &T, std::function< double(int, int, int, int)> &V) const
Definition: DM2.cpp:740
double ddot_(int *n, double *x, int *incx, double *y, int *incy)
void WriteToFile(const std::string) const
Definition: DM2.cpp:213
double operator()(int, int, int, int) const
Definition: DM2.cpp:111
Definition: DM2.h:24
static unsigned int CountBits(mybitset)
unsigned int get_n_sp() const
Definition: DM2.cpp:362
std::ostream & operator<<(std::ostream &output, doci::DM2 &dm2)
Definition: DM2.cpp:516
virtual mybitset get() const
Definition: Permutation.cpp:57
void Build(Permutation &, std::vector< double > &)
Definition: DM2.cpp:373
void BuildHamiltonian(const Molecule &)
Definition: DM2.cpp:537
DM2(unsigned int, unsigned int)
Definition: DM2.cpp:26
virtual unsigned int get_n_electrons() const
Definition: Molecule.cpp:32
virtual double getT(int, int) const =0
#define HDF5_STATUS_CHECK(status)
Definition: DM2.cpp:18
void daxpy_(int *n, double *alpha, double *x, int *incx, double *y, int *incy)
DM2 & operator=(const DM2 &)
Definition: DM2.cpp:71
virtual double getV(int, int, int, int) const =0
unsigned int get_n_electrons() const
Definition: DM2.cpp:354
virtual void reset()
Definition: Permutation.cpp:66
double Dot(const DM2 &) const
Definition: DM2.cpp:593
double * getpointer() const
Definition: helpers.cpp:165
DM2 & operator+=(const DM2 &)
Definition: DM2.cpp:140
virtual unsigned int get_n_sp() const
Definition: Molecule.cpp:24