QMCPACK
RotatedSPOs.cpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////////////
2 //// This file is distributed under the University of Illinois/NCSA Open Source License.
3 //// See LICENSE file in top directory for details.
4 ////
5 //// Copyright (c) QMCPACK developers.
6 ////
7 //// File developed by: Sergio D. Pineda Flores, sergio_pinedaflores@berkeley.edu, University of California, Berkeley
8 //// Eric Neuscamman, eneuscamman@berkeley.edu, University of California, Berkeley
9 //// Ye Luo, yeluo@anl.gov, Argonne National Laboratory
10 ////
11 //// File created by: Sergio D. Pineda Flores, sergio_pinedaflores@berkeley.edu, University of California, Berkeley
12 ////////////////////////////////////////////////////////////////////////////////////////
13 #include "RotatedSPOs.h"
16 #include "CPU/BLAS.hpp"
17 #include "io/hdf/hdf_archive.h"
19 
20 namespace qmcplusplus
21 {
22 RotatedSPOs::RotatedSPOs(const std::string& my_name, std::unique_ptr<SPOSet>&& spos)
23  : SPOSet(my_name),
24  OptimizableObject(my_name),
25  Phi_(std::move(spos)),
26  nel_major_(0),
27  params_supplied_(false),
28  apply_rotation_timer_(createGlobalTimer("RotatedSPOs::apply_rotation", timer_level_fine))
29 {
30  OrbitalSetSize = Phi_->getOrbitalSetSize();
31 }
32 
34 
35 
36 void RotatedSPOs::setRotationParameters(const std::vector<RealType>& param_list)
37 {
38  const size_t num_param = IsComplex_t<ValueType>::value ? param_list.size() / 2 : param_list.size();
39  params_.resize(num_param);
40 
41  //handling both real and complex by casting data to RealType*, since laid out as real_0, imag_0, real_1, imag_1, etc
42  auto* params_data_alias = (RealType*)params_.data();
43  std::copy(param_list.begin(), param_list.end(), params_data_alias);
44 
45  params_supplied_ = true;
46 }
47 
48 void RotatedSPOs::createRotationIndices(int nel, int nmo, RotationIndices& rot_indices)
49 {
50  for (int i = 0; i < nel; i++)
51  for (int j = nel; j < nmo; j++)
52  rot_indices.emplace_back(i, j);
53 }
54 
55 void RotatedSPOs::createRotationIndicesFull(int nel, int nmo, RotationIndices& rot_indices)
56 {
57  rot_indices.reserve(nmo * (nmo - 1) / 2);
58 
59  // start with core-active rotations - put them at the beginning of the list
60  // so it matches the other list of rotation indices
61  for (int i = 0; i < nel; i++)
62  for (int j = nel; j < nmo; j++)
63  rot_indices.emplace_back(i, j);
64 
65  // Add core-core rotations - put them at the end of the list
66  for (int i = 0; i < nel; i++)
67  for (int j = i + 1; j < nel; j++)
68  rot_indices.emplace_back(i, j);
69 
70  // Add active-active rotations - put them at the end of the list
71  for (int i = nel; i < nmo; i++)
72  for (int j = i + 1; j < nmo; j++)
73  rot_indices.emplace_back(i, j);
74 }
75 
77  const std::vector<ValueType>& param,
78  ValueMatrix& rot_mat)
79 {
80  assert(rot_indices.size() == param.size());
81  // Assumes rot_mat is of the correct size
82 
83  rot_mat = 0.0;
84 
85  for (int i = 0; i < rot_indices.size(); i++)
86  {
87  const int p = rot_indices[i].first;
88  const int q = rot_indices[i].second;
89  const ValueType x = param[i];
90 
91  rot_mat[q][p] = x;
92  //This conj is from type_traits/complex_help.hpp. So conj(Real) returns Real and not complex.
93  rot_mat[p][q] = -qmcplusplus::conj(x);
94  }
95 }
96 
98  const ValueMatrix& rot_mat,
99  std::vector<ValueType>& param)
100 {
101  assert(rot_indices.size() == param.size());
102  // Assumes rot_mat is of the correct size
103 
104  for (int i = 0; i < rot_indices.size(); i++)
105  {
106  const int p = rot_indices[i].first;
107  const int q = rot_indices[i].second;
108  param[i] = rot_mat[q][p];
109  }
110 }
111 
113 {
114  const size_t nact_rot = m_act_rot_inds_.size();
115  std::vector<ValueType> delta_param(nact_rot);
116 
117  //cast ValueType to RealType for delta param
118  //allows us to work with both real and complex since
119  //active and myVars are stored as only reals
120  auto* delta_param_data_alias = (RealType*)delta_param.data();
121  for (int i = 0; i < myVars.size(); i++)
122  {
123  int loc = myVars.where(i);
124  delta_param_data_alias[i] = active[loc] - myVars[i];
125  myVars[i] = active[loc];
126  }
127 
128  if (use_global_rot_)
129  {
130  std::vector<ValueType> old_param(m_full_rot_inds_.size());
131  std::copy_n(myVarsFull_.data(), myVarsFull_.size(), old_param.data());
132 
133  applyDeltaRotation(delta_param, old_param, myVarsFull_);
134  }
135  else
136  {
137  apply_rotation(delta_param, false);
138 
139  // Save the parameters in the history list
140  history_params_.push_back(delta_param);
141  }
142 }
143 
145 {
146  hout.push("RotatedSPOs");
147  if (use_global_rot_)
148  {
149  hout.push("rotation_global");
150  const std::string rot_global_name = std::string("rotation_global_") + SPOSet::getName();
151 
152  hout.write(myVarsFull_, rot_global_name);
153  hout.pop();
154  }
155  else
156  {
157  hout.push("rotation_history");
158  size_t rows = history_params_.size();
159  size_t cols = 0;
160  if (rows > 0)
161  cols = history_params_[0].size();
162 
163  Matrix<ValueType> tmp(rows, cols);
164  for (size_t i = 0; i < rows; i++)
165  for (size_t j = 0; j < cols; j++)
166  tmp[i][j] = history_params_[i][j];
167  std::string rot_hist_name = std::string("rotation_history_") + SPOSet::getName();
168  hout.write(tmp, rot_hist_name);
169  hout.pop();
170  }
171 
172  // Save myVars in order to restore object state exactly
173  // The values aren't meaningful, but they need to match those saved in VariableSet
174  hout.push("rotation_params");
175  std::string rot_params_name = std::string("rotation_params_") + SPOSet::getName();
176 
177  std::vector<ValueType> params(m_act_rot_inds_.size());
178  auto* params_data_alias = (RealType*)params.data();
179  for (int i = 0; i < myVars.size(); i++)
180  params_data_alias[i] = myVars[i];
181 
182  hout.write(params, rot_params_name);
183  hout.pop();
184 
185  hout.pop();
186 }
187 
189 {
190  hin.push("RotatedSPOs", false);
191 
192  bool grp_hist_exists = hin.is_group("rotation_history");
193  bool grp_global_exists = hin.is_group("rotation_global");
194  if (!grp_hist_exists && !grp_global_exists)
195  app_warning() << "Rotation parameters not found in VP file";
196 
197 
198  if (grp_global_exists)
199  {
200  hin.push("rotation_global", false);
201  const std::string rot_global_name = std::string("rotation_global_") + SPOSet::getName();
202 
203  std::vector<int> sizes(1);
204  if (!hin.getShape<ValueType>(rot_global_name, sizes))
205  throw std::runtime_error("Failed to read rotation_global in VP file");
206 
207  if (myVarsFull_.size() != sizes[0])
208  {
209  std::ostringstream tmp_err;
210  tmp_err << "Expected number of full rotation parameters (" << myVarsFull_.size()
211  << ") does not match number in file (" << sizes[0] << ")";
212  throw std::runtime_error(tmp_err.str());
213  }
214  hin.read(myVarsFull_, rot_global_name);
215 
216  hin.pop();
217 
219  }
220  else if (grp_hist_exists)
221  {
222  hin.push("rotation_history", false);
223  std::string rot_hist_name = std::string("rotation_history_") + SPOSet::getName();
224  std::vector<int> sizes(2);
225  if (!hin.getShape<ValueType>(rot_hist_name, sizes))
226  throw std::runtime_error("Failed to read rotation history in VP file");
227 
228  int rows = sizes[0];
229  int cols = sizes[1];
230  history_params_.resize(rows);
231  Matrix<ValueType> tmp(rows, cols);
232  hin.read(tmp, rot_hist_name);
233  for (size_t i = 0; i < rows; i++)
234  {
235  history_params_[i].resize(cols);
236  for (size_t j = 0; j < cols; j++)
237  history_params_[i][j] = tmp(i, j);
238  }
239 
240  hin.pop();
241 
243  }
244 
245  hin.push("rotation_params", false);
246  std::string rot_param_name = std::string("rotation_params_") + SPOSet::getName();
247 
248  std::vector<int> sizes(1);
249  if (!hin.getShape<ValueType>(rot_param_name, sizes))
250  throw std::runtime_error("Failed to read rotation_params in VP file");
251 
252  //values stored as ValueType. Now unpack into reals
253  int nparam_actual = IsComplex_t<ValueType>::value ? 2 * sizes[0] : sizes[0];
254  int nparam = myVars.size();
255  if (nparam != nparam_actual)
256  {
257  std::ostringstream tmp_err;
258  tmp_err << "Expected number of rotation parameters (" << nparam << ") does not match number in file ("
259  << nparam_actual << ")";
260  throw std::runtime_error(tmp_err.str());
261  }
262 
263  std::vector<ValueType> params(sizes[0]);
264  hin.read(params, rot_param_name);
265  auto* params_data_alias = (RealType*)params.data();
266  for (int i = 0; i < nparam; i++)
267  myVars[i] = params_data_alias[i];
268 
269  hin.pop();
270 
271  hin.pop();
272 }
273 
274 void RotatedSPOs::buildOptVariables(const size_t nel)
275 {
276  /* Only rebuild optimized variables if more after-rotation orbitals are needed
277  * Consider ROHF, there is only one set of SPO for both spin up and down Nup > Ndown.
278  * nel_major_ will be set Nup.
279  *
280  * Use the size of myVars as a flag to avoid building the rotation parameters again
281  * when a clone is made (the DiracDeterminant constructor calls buildOptVariables)
282  */
283  if (nel > nel_major_ && myVars.size() == 0)
284  {
285  nel_major_ = nel;
286 
287  const size_t nmo = Phi_->getOrbitalSetSize();
288 
289  // create active rotation parameter indices
290  RotationIndices created_m_act_rot_inds;
291 
292  RotationIndices created_full_rot_inds;
293  if (use_global_rot_)
294  createRotationIndicesFull(nel, nmo, created_full_rot_inds);
295 
296  createRotationIndices(nel, nmo, created_m_act_rot_inds);
297 
298  buildOptVariables(created_m_act_rot_inds, created_full_rot_inds);
299  }
300 }
301 
302 void RotatedSPOs::buildOptVariables(const RotationIndices& rotations, const RotationIndices& full_rotations)
303 {
304  const size_t nmo = Phi_->getOrbitalSetSize();
305 
306  // create active rotations
307  m_act_rot_inds_ = rotations;
308 
309  if (use_global_rot_)
310  m_full_rot_inds_ = full_rotations;
311 
312  if (use_global_rot_)
313  app_log() << "Orbital rotation using global rotation" << std::endl;
314  else
315  app_log() << "Orbital rotation using history" << std::endl;
316 
317  // This will add the orbital rotation parameters to myVars
318  // and will also read in initial parameter values supplied in input file
319  int nparams_active = m_act_rot_inds_.size();
320 
321  if (params_supplied_)
322  if (nparams_active != params_.size())
323  throw std::runtime_error(
324  "The number of supplied orbital rotation parameters does not match number prdouced by the slater "
325  "expansion. \n");
326 
327 
328  auto registerParameter = [this](const int i, const int p, const int q, opt_variables_type& optvars,
329  std::vector<ValueType>& params, bool real_part) {
330  std::stringstream sstr;
331  std::string label = real_part ? "_r" : "_i";
332  sstr << my_name_ << "_orb_rot_" << (p < 10 ? "0" : "") << (p < 100 ? "0" : "") << (p < 1000 ? "0" : "") << p << "_"
333  << (q < 10 ? "0" : "") << (q < 100 ? "0" : "") << (q < 1000 ? "0" : "") << q << label;
334 
335  // If the user input parameters, use those. Otherwise, initialize the parameters to zero
336  if (params_supplied_)
337  optvars.insert(sstr.str(), real_part ? std::real(params[i]) : std::imag(params[i]));
338  else
339  optvars.insert(sstr.str(), 0.0);
340  };
341 
342  myVars.clear();
343  for (int i = 0; i < nparams_active; i++)
344  {
345  const int p = m_act_rot_inds_[i].first;
346  const int q = m_act_rot_inds_[i].second;
347  registerParameter(i, p, q, myVars, params_, true);
348  if constexpr (IsComplex_t<ValueType>::value)
349  registerParameter(i, p, q, myVars, params_, false);
350  }
351 
352  if (use_global_rot_)
353  {
354  const size_t nfull_rot = m_full_rot_inds_.size();
355  myVarsFull_.resize(nfull_rot);
356  for (int i = 0; i < nfull_rot; i++)
357  myVarsFull_[i] = (params_supplied_ && i < m_act_rot_inds_.size()) ? params_[i] : 0.0;
358  }
359 
360  //Printing the parameters
361  if (true)
362  {
363  app_log() << std::string(16, ' ') << "Parameter name" << std::string(15, ' ') << "Value\n";
364  myVars.print(app_log());
365  }
366 
367  if (params_supplied_)
368  {
369  const size_t N = m_act_rot_inds_.size();
370  std::vector<ValueType> param(N);
371  //cast as RealType to copy from myVars into real or complex param vector
372  auto* param_data_alias = (RealType*)param.data();
373  //couldn't easily use std::copy since myVars is vector of pairs
374  for (size_t i = 0; i < myVars.size(); i++)
375  param_data_alias[i] = myVars[i];
376  apply_rotation(param, false);
377  }
378 }
379 
380 void RotatedSPOs::apply_rotation(const std::vector<ValueType>& param, bool use_stored_copy)
381 {
382  assert(param.size() == m_act_rot_inds_.size());
383 
384  const size_t nmo = Phi_->getOrbitalSetSize();
385  ValueMatrix rot_mat(nmo, nmo);
386 
388 
389  /*
390  rot_mat is now an anti-hermitian matrix. Now we convert
391  it into a unitary matrix via rot_mat = exp(-rot_mat).
392  Finally, apply unitary matrix to orbs.
393  */
395  {
397  Phi_->applyRotation(rot_mat, use_stored_copy);
398  }
399 }
400 
401 void RotatedSPOs::applyDeltaRotation(const std::vector<ValueType>& delta_param,
402  const std::vector<ValueType>& old_param,
403  std::vector<ValueType>& new_param)
404 {
405  const size_t nmo = Phi_->getOrbitalSetSize();
406  ValueMatrix new_rot_mat(nmo, nmo);
407  constructDeltaRotation(delta_param, old_param, m_act_rot_inds_, m_full_rot_inds_, new_param, new_rot_mat);
408 
409  {
411  Phi_->applyRotation(new_rot_mat, true);
412  }
413 }
414 
415 void RotatedSPOs::constructDeltaRotation(const std::vector<ValueType>& delta_param,
416  const std::vector<ValueType>& old_param,
417  const RotationIndices& act_rot_inds,
418  const RotationIndices& full_rot_inds,
419  std::vector<ValueType>& new_param,
420  ValueMatrix& new_rot_mat)
421 {
422  assert(delta_param.size() == act_rot_inds.size());
423  assert(old_param.size() == full_rot_inds.size());
424  assert(new_param.size() == full_rot_inds.size());
425 
426  const size_t nmo = new_rot_mat.rows();
427  assert(new_rot_mat.rows() == new_rot_mat.cols());
428 
429  ValueMatrix old_rot_mat(nmo, nmo);
430 
431  constructAntiSymmetricMatrix(full_rot_inds, old_param, old_rot_mat);
432  exponentiate_antisym_matrix(old_rot_mat);
433 
434  ValueMatrix delta_rot_mat(nmo, nmo);
435 
436  constructAntiSymmetricMatrix(act_rot_inds, delta_param, delta_rot_mat);
437  exponentiate_antisym_matrix(delta_rot_mat);
438 
439  // Apply delta rotation to old rotation.
440  BLAS::gemm('N', 'N', nmo, nmo, nmo, 1.0, delta_rot_mat.data(), nmo, old_rot_mat.data(), nmo, 0.0, new_rot_mat.data(),
441  nmo);
442 
443  ValueMatrix log_rot_mat(nmo, nmo);
444  log_antisym_matrix(new_rot_mat, log_rot_mat);
445  extractParamsFromAntiSymmetricMatrix(full_rot_inds, log_rot_mat, new_param);
446 }
447 
448 void RotatedSPOs::applyFullRotation(const std::vector<ValueType>& full_param, bool use_stored_copy)
449 {
450  assert(full_param.size() == m_full_rot_inds_.size());
451 
452  const size_t nmo = Phi_->getOrbitalSetSize();
453  ValueMatrix rot_mat(nmo, nmo);
454  rot_mat = ValueType(0);
455 
456  constructAntiSymmetricMatrix(m_full_rot_inds_, full_param, rot_mat);
457 
458  /*
459  rot_mat is now an anti-hermitian matrix. Now we convert
460  it into a unitary matrix via rot_mat = exp(-rot_mat).
461  Finally, apply unitary matrix to orbs.
462  */
464  Phi_->applyRotation(rot_mat, use_stored_copy);
465 }
466 
468 {
469  for (auto delta_param : history_params_)
470  {
471  apply_rotation(delta_param, false);
472  }
473 }
474 
475 // compute exponential of a real, antisymmetric matrix by diagonalizing and exponentiating eigenvalues
477 {
478  const int n = mat.rows();
479  std::vector<std::complex<RealType>> mat_h(n * n, 0);
480  std::vector<RealType> eval(n, 0);
481  std::vector<std::complex<RealType>> work(2 * n, 0);
482  std::vector<RealType> rwork(3 * n, 0);
483  std::vector<std::complex<RealType>> mat_d(n * n, 0);
484  std::vector<std::complex<RealType>> mat_t(n * n, 0);
485  // exponentiating e^X = e^iY (Y hermitian)
486  // i(-iX) = X, so -iX is hermitian
487  // diagonalize -iX = UDU^T, exponentiate e^iD, and return U e^iD U^T
488  // construct hermitian analogue of mat by multiplying by -i
489  for (int i = 0; i < n; ++i)
490  {
491  for (int j = i; j < n; ++j)
492  {
493  //This two liner does several things. The first is it unpacks row-major mat into column major format.
494  //Second, it builds the hermitian matrix -i*mat. Third, it relies on the hermiticity of -i*mat to
495  //fill the entire -i*mat matrix (in column major form) by iterating over the upper diagonal only.
496  mat_h[i + n * j] = std::complex<RealType>(std::imag(mat[i][j]), -1.0 * std::real(mat[i][j]));
497  mat_h[j + n * i] = std::complex<RealType>(-std::imag(mat[i][j]), 1.0 * std::real(mat[i][j]));
498  }
499  }
500  // diagonalize the matrix
501  char JOBZ('V'); //compute eigenvalues and eigenvectors.
502  char UPLO('U'); //store upper triangle of A.
503  int N(n);
504  int LDA(n);
505  int LWORK(2 * n);
506  int info = 0;
507  //Ax=lamda x. For given A=mat_h, returns the list of *real* eigenvalues lamda=eval, and
508  //the matrix of eigenvectors V=mat_h (overwritten). Eigenvectors are columns of this matrix.
509  //The eigendecomposition of this matrix is thus V*LAMBDA*V^dagger.
510  LAPACK::heev(JOBZ, UPLO, N, &mat_h.at(0), LDA, &eval.at(0), &work.at(0), LWORK, &rwork.at(0), info);
511  if (info != 0)
512  {
513  std::ostringstream msg;
514  msg << "heev failed with info = " << info << " in RotatedSPOs::exponentiate_antisym_matrix";
515  throw std::runtime_error(msg.str());
516  }
517  // iterate through diagonal matrix, exponentiate terms
518  for (int i = 0; i < n; ++i)
519  {
520  for (int j = 0; j < n; ++j)
521  {
522  mat_d[i + j * n] = (i == j) ? std::exp(std::complex<RealType>(0.0, eval[i])) : std::complex<RealType>(0.0, 0.0);
523  }
524  }
525  // perform matrix multiplication
526  // Everything here is column major, so normal BLAS ordering and conventions apply.
527 
528  // e^{LAMBDA} * V^dagger
529  BLAS::gemm('N', 'C', n, n, n, std::complex<RealType>(1.0, 0), &mat_d.at(0), n, &mat_h.at(0), n,
530  std::complex<RealType>(0.0, 0.0), &mat_t.at(0), n);
531  // V * [ e^{LAMBDA} * V^dagger ] = exp(K)
532  BLAS::gemm('N', 'N', n, n, n, std::complex<RealType>(1.0, 0), &mat_h.at(0), n, &mat_t.at(0), n,
533  std::complex<RealType>(0.0, 0.0), &mat_d.at(0), n);
534  for (int i = 0; i < n; ++i)
535  for (int j = 0; j < n; ++j)
536  //Copy [exp(K)]_ij in column major form to mat in row major form.
537  //For real build, the imaginary part is discarded. For complex build,
538  //the entire complex entry is copied.
539  copy_with_complex_cast(mat_d[i + n * j], mat[i][j]);
540 }
541 
543 {
544  const int n = mat.rows();
545  std::vector<ValueType> mat_h(n * n, 0);
546  std::vector<RealType> mat_l(n * n, 0);
547  std::vector<std::complex<RealType>> mat_cd(n * n, 0);
548  std::vector<std::complex<RealType>> mat_cl(n * n, 0);
549  std::vector<std::complex<RealType>> mat_ch(n * n, 0);
550 
551  for (int i = 0; i < n; ++i)
552  for (int j = 0; j < n; ++j)
553  //we copy input mat in row major form to column major array for LAPACK consumption.
554  mat_h[i + n * j] = mat[i][j];
555 
556  // diagonalize the matrix
557  char JOBL('V'); //Compute left eigenvectors.
558  char JOBR('N'); //Don't compute right eigenvectors.
559  int N(n);
560  int LDA(n);
561  int LWORK(4 * n);
562  int info = 0;
563 
564 #ifndef QMC_COMPLEX
565  std::vector<RealType> eval_r(n, 0);
566  std::vector<RealType> eval_i(n, 0);
567  std::vector<RealType> work(4 * n, 0);
568  LAPACK::geev(&JOBL, &JOBR, &N, &mat_h.at(0), &LDA, &eval_r.at(0), &eval_i.at(0), &mat_l.at(0), &LDA, nullptr, &LDA,
569  &work.at(0), &LWORK, &info);
570 #else
571  std::vector<ValueType> eval(n, 0);
572  std::vector<ValueType> work(2 * n, 0);
573  std::vector<RealType> rwork(2 * n, 0);
574  LAPACK::geev(&JOBL, &JOBR, &N, &mat_h.at(0), &LDA, &eval.at(0), &mat_cl.at(0), &LDA, nullptr, &LDA, &work.at(0),
575  &LWORK, &rwork.at(0), &info);
576 #endif
577  if (info != 0)
578  {
579  std::ostringstream msg;
580  msg << "heev failed with info = " << info << " in RotatedSPOs::log_antisym_matrix";
581  throw std::runtime_error(msg.str());
582  }
583 
584  // iterate through diagonal matrix, take log
585  for (int i = 0; i < n; ++i)
586  {
587  for (int j = 0; j < n; ++j)
588  {
589 #ifndef QMC_COMPLEX
590  auto tmp = (i == j) ? std::log(std::complex<RealType>(eval_r[i], eval_i[i])) : std::complex<RealType>(0.0, 0.0);
591  if (eval_i[j] > 0.0)
592  {
593  mat_cl[i + j * n] = std::complex<RealType>(mat_l[i + j * n], mat_l[i + (j + 1) * n]);
594  mat_cl[i + (j + 1) * n] = std::complex<RealType>(mat_l[i + j * n], -mat_l[i + (j + 1) * n]);
595  }
596  else if (!(eval_i[j] < 0.0))
597  {
598  mat_cl[i + j * n] = std::complex<RealType>(mat_l[i + j * n], 0.0);
599  }
600 #else
601  auto tmp = (i == j) ? std::log(eval[i]) : ValueType(0.0);
602 #endif
603  mat_cd[i + j * n] = tmp;
604  }
605  }
606 
607  RealType one(1.0);
608  RealType zero(0.0);
609  BLAS::gemm('N', 'N', n, n, n, one, &mat_cl.at(0), n, &mat_cd.at(0), n, zero, &mat_ch.at(0), n);
610  BLAS::gemm('N', 'C', n, n, n, one, &mat_ch.at(0), n, &mat_cl.at(0), n, zero, &mat_cd.at(0), n);
611 
612 
613  for (int i = 0; i < n; ++i)
614  for (int j = 0; j < n; ++j)
615  {
616 #ifndef QMC_COMPLEX
617  if (mat_cd[i + n * j].imag() > 1e-12)
618  {
619  app_log() << "warning: large imaginary value in antisymmetric matrix: (i,j) = (" << i << "," << j
620  << "), im = " << mat_cd[i + n * j].imag() << std::endl;
621  }
622  output[i][j] = mat_cd[i + n * j].real();
623 #else
624  output[i][j] = mat_cd[i + n * j];
625 #endif
626  }
627 }
628 
630  const opt_variables_type& optvars,
631  ValueVector& psi,
632  const ValueVector& psiinv,
633  std::vector<ValueType>& ratios,
634  Matrix<ValueType>& dratios,
635  int FirstIndex,
636  int LastIndex)
637 {
638  Phi_->evaluateDetRatios(VP, psi, psiinv, ratios);
639 
640  const size_t nel = LastIndex - FirstIndex;
641  const size_t nmo = Phi_->getOrbitalSetSize();
642 
643  psiM_inv.resize(nel, nel);
644  psiM_all.resize(nel, nmo);
645  dpsiM_all.resize(nel, nmo);
646  d2psiM_all.resize(nel, nmo);
647 
648  psiM_inv = 0;
649  psiM_all = 0;
650  dpsiM_all = 0;
651  d2psiM_all = 0;
652 
653  const ParticleSet& P = VP.getRefPS();
654  int iel = VP.refPtcl;
655 
656  Phi_->evaluate_notranspose(P, FirstIndex, LastIndex, psiM_all, dpsiM_all, d2psiM_all);
657 
658  for (int i = 0; i < nel; i++)
659  for (int j = 0; j < nel; j++)
660  psiM_inv(i, j) = psiM_all(i, j);
661 
662  Invert(psiM_inv.data(), nel, nel);
663 
664  const ValueType* const A(psiM_all.data());
665  const ValueType* const Ainv(psiM_inv.data());
666  SPOSet::ValueMatrix T_orig;
667  T_orig.resize(nel, nmo);
668 
669  BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), A, nmo, Ainv, nel, ValueType(0.0), T_orig.data(), nmo);
670 
672  T.resize(nel, nmo);
673 
674  ValueVector tmp_psi;
675  tmp_psi.resize(nmo);
676 
677  for (int iat = 0; iat < VP.getTotalNum(); iat++)
678  {
679  Phi_->evaluateValue(VP, iat, tmp_psi);
680 
681  for (int j = 0; j < nmo; j++)
682  psiM_all(iel - FirstIndex, j) = tmp_psi[j];
683 
684  for (int i = 0; i < nel; i++)
685  for (int j = 0; j < nel; j++)
686  psiM_inv(i, j) = psiM_all(i, j);
687 
688  Invert(psiM_inv.data(), nel, nel);
689 
690  const ValueType* const A(psiM_all.data());
691  const ValueType* const Ainv(psiM_inv.data());
692 
693  // The matrix A is rectangular. Ainv is the inverse of the square part of the matrix.
694  // The multiply of Ainv and the square part of A is just the identity.
695  // This multiply could be reduced to Ainv and the non-square part of A.
696  BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), A, nmo, Ainv, nel, ValueType(0.0), T.data(), nmo);
697 
698  for (int i = 0; i < myVars.size(); i++)
699  {
700  int kk = myVars.where(i);
701  if (kk >= 0)
702  {
703  int j = IsComplex_t<ValueType>::value ? i / 2 : i;
704  const int p = m_act_rot_inds_.at(j).first;
705  const int q = m_act_rot_inds_.at(j).second;
706  dratios(iat, kk) = T(p, q) - T_orig(p, q); // dratio size is (nknot, num_vars)
707 #ifdef QMC_COMPLEX
708  if (i % 2 == 1)
709  dratios(iat, kk) *= ComplexType(0, 1);
710 #endif
711  }
712  }
713  }
714 }
715 
717  const opt_variables_type& optvars,
718  Vector<ValueType>& dlogpsi,
719  int FirstIndex,
720  int LastIndex)
721 {
722  const size_t nel = LastIndex - FirstIndex;
723  const size_t nmo = Phi_->getOrbitalSetSize();
724 
725  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~PART1
726 
727  psiM_inv.resize(nel, nel);
728  psiM_all.resize(nel, nmo);
729  dpsiM_all.resize(nel, nmo);
730  d2psiM_all.resize(nel, nmo);
731 
732  psiM_inv = 0;
733  psiM_all = 0;
734  dpsiM_all = 0;
735  d2psiM_all = 0;
736 
737  Phi_->evaluate_notranspose(P, FirstIndex, LastIndex, psiM_all, dpsiM_all, d2psiM_all);
738 
739  for (int i = 0; i < nel; i++)
740  for (int j = 0; j < nel; j++)
741  psiM_inv(i, j) = psiM_all(i, j);
742 
743  Invert(psiM_inv.data(), nel, nel);
744 
745  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~PART2
746  const ValueType* const A(psiM_all.data());
747  const ValueType* const Ainv(psiM_inv.data());
749  T.resize(nel, nmo);
750 
751  BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), A, nmo, Ainv, nel, ValueType(0.0), T.data(), nmo);
752 
753  for (int i = 0; i < myVars.size(); i++)
754  {
755  int kk = myVars.where(i);
756  if (kk >= 0)
757  {
758  int j = IsComplex_t<ValueType>::value ? i / 2 : i;
759  const int p = m_act_rot_inds_.at(j).first;
760  const int q = m_act_rot_inds_.at(j).second;
761  dlogpsi[kk] = T(p, q);
762 #ifdef QMC_COMPLEX
763  if (i % 2 == 1)
764  dlogpsi[kk] *= ComplexType(0, 1);
765 #endif
766  }
767  }
768 }
769 
771  const opt_variables_type& optvars,
772  Vector<ValueType>& dlogpsi,
773  Vector<ValueType>& dhpsioverpsi,
774  const int& FirstIndex,
775  const int& LastIndex)
776 {
777  const size_t nel = LastIndex - FirstIndex;
778  const size_t nmo = Phi_->getOrbitalSetSize();
779 
780  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~PART1
781  myG_temp.resize(nel);
782  myG_J.resize(nel);
783  myL_temp.resize(nel);
784  myL_J.resize(nel);
785 
786  myG_temp = 0;
787  myG_J = 0;
788  myL_temp = 0;
789  myL_J = 0;
790 
791  Bbar.resize(nel, nmo);
792  psiM_inv.resize(nel, nel);
793  psiM_all.resize(nel, nmo);
794  dpsiM_all.resize(nel, nmo);
795  d2psiM_all.resize(nel, nmo);
796 
797  Bbar = 0;
798  psiM_inv = 0;
799  psiM_all = 0;
800  dpsiM_all = 0;
801  d2psiM_all = 0;
802 
803 
804  Phi_->evaluate_notranspose(P, FirstIndex, LastIndex, psiM_all, dpsiM_all, d2psiM_all);
805 
806  for (int i = 0; i < nel; i++)
807  for (int j = 0; j < nel; j++)
808  psiM_inv(i, j) = psiM_all(i, j);
809 
810  Invert(psiM_inv.data(), nel, nel);
811 
812  //current value of Gradient and Laplacian
813  // gradient components
814  for (int a = 0; a < nel; a++)
815  for (int i = 0; i < nel; i++)
816  for (int k = 0; k < 3; k++)
817  myG_temp[a][k] += psiM_inv(i, a) * dpsiM_all(a, i)[k];
818  // laplacian components
819  for (int a = 0; a < nel; a++)
820  {
821  for (int i = 0; i < nel; i++)
822  myL_temp[a] += psiM_inv(i, a) * d2psiM_all(a, i);
823  }
824 
825  // calculation of myG_J which will be used to represent \frac{\nabla\psi_{J}}{\psi_{J}}
826  // calculation of myL_J will be used to represent \frac{\nabla^2\psi_{J}}{\psi_{J}}
827  // IMPORTANT NOTE: The value of P.L holds \nabla^2 ln[\psi] but we need \frac{\nabla^2 \psi}{\psi} and this is what myL_J will hold
828  for (int a = 0, iat = FirstIndex; a < nel; a++, iat++)
829  {
830  myG_J[a] = (P.G[iat] - myG_temp[a]);
831  myL_J[a] = (P.L[iat] + dot(P.G[iat], P.G[iat]) - myL_temp[a]);
832  }
833  //possibly replace wit BLAS calls
834  for (int i = 0; i < nel; i++)
835  for (int j = 0; j < nmo; j++)
836  Bbar(i, j) = d2psiM_all(i, j) + ValueType(2.0) * ValueType(dot(myG_J[i], dpsiM_all(i, j))) +
837  ValueType(myL_J[i]) * psiM_all(i, j);
838 
839 
840  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~PART2
841  const ValueType* const A(psiM_all.data());
842  const ValueType* const Ainv(psiM_inv.data());
843  const ValueType* const B(Bbar.data());
849  T.resize(nel, nmo);
850  Y1.resize(nel, nel);
851  Y2.resize(nel, nmo);
852  Y3.resize(nel, nmo);
853  Y4.resize(nel, nmo);
854 
855 
856  BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), A, nmo, Ainv, nel, ValueType(0.0), T.data(), nmo);
857  BLAS::gemm('N', 'N', nel, nel, nel, ValueType(1.0), B, nmo, Ainv, nel, ValueType(0.0), Y1.data(), nel);
858  BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), T.data(), nmo, Y1.data(), nel, ValueType(0.0), Y2.data(), nmo);
859  BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), B, nmo, Ainv, nel, ValueType(0.0), Y3.data(), nmo);
860 
861  //possibly replace with BLAS call
862  Y4 = Y3 - Y2;
863 
864  for (int i = 0; i < myVars.size(); i++)
865  {
866  int kk = myVars.where(i);
867  if (kk >= 0)
868  {
869  int j = IsComplex_t<ValueType>::value ? i / 2 : i;
870  const int p = m_act_rot_inds_.at(j).first;
871  const int q = m_act_rot_inds_.at(j).second;
872 
873  ValueType pref1 = ValueType(1.0);
874  ValueType pref2 = ValueType(-0.5);
875 #ifdef QMC_COMPLEX
876  if (i % 2 == 1)
877  {
878  pref1 *= ComplexType(0, 1);
879  pref2 *= ComplexType(0, 1);
880  }
881 #endif
882  dlogpsi[kk] += pref1 * T(p, q);
883  dhpsioverpsi[kk] += pref2 * Y4(p, q);
884  }
885  }
886 }
887 
889  const opt_variables_type& optvars,
890  Vector<ValueType>& dlogpsi,
891  Vector<ValueType>& dhpsioverpsi,
892  const ValueType& psiCurrent,
893  const std::vector<ValueType>& Coeff,
894  const std::vector<size_t>& C2node_up,
895  const std::vector<size_t>& C2node_dn,
896  const ValueVector& detValues_up,
897  const ValueVector& detValues_dn,
898  const GradMatrix& grads_up,
899  const GradMatrix& grads_dn,
900  const ValueMatrix& lapls_up,
901  const ValueMatrix& lapls_dn,
902  const ValueMatrix& M_up,
903  const ValueMatrix& M_dn,
904  const ValueMatrix& Minv_up,
905  const ValueMatrix& Minv_dn,
906  const GradMatrix& B_grad,
907  const ValueMatrix& B_lapl,
908  const std::vector<int>& detData_up,
909  const size_t N1,
910  const size_t N2,
911  const size_t NP1,
912  const size_t NP2,
913  const std::vector<std::vector<int>>& lookup_tbl)
914 {
915 #ifndef QMC_COMPLEX
916  bool recalculate(false);
917  for (int k = 0; k < myVars.size(); ++k)
918  {
919  int kk = myVars.where(k);
920  if (kk < 0)
921  continue;
922  if (optvars.recompute(kk))
923  recalculate = true;
924  }
925  if (recalculate)
926  {
929  const int NP = P.getTotalNum();
930  myG_temp.resize(NP);
931  myG_temp = 0.0;
932  myL_temp.resize(NP);
933  myL_temp = 0.0;
934  myG_J.resize(NP);
935  myG_J = 0.0;
936  myL_J.resize(NP);
937  myL_J = 0.0;
938  const size_t nmo = Phi_->getOrbitalSetSize();
939  const size_t nel = P.last(0) - P.first(0);
940 
941  const RealType* restrict C_p = Coeff.data();
942  for (int i = 0; i < Coeff.size(); i++)
943  {
944  const size_t upC = C2node_up[i];
945  const size_t dnC = C2node_dn[i];
946  const ValueType tmp1 = C_p[i] * detValues_dn[dnC];
947  const ValueType tmp2 = C_p[i] * detValues_up[upC];
948  for (size_t k = 0, j = N1; k < NP1; k++, j++)
949  {
950  myG_temp[j] += tmp1 * grads_up(upC, k);
951  myL_temp[j] += tmp1 * lapls_up(upC, k);
952  }
953  for (size_t k = 0, j = N2; k < NP2; k++, j++)
954  {
955  myG_temp[j] += tmp2 * grads_dn(dnC, k);
956  myL_temp[j] += tmp2 * lapls_dn(dnC, k);
957  }
958  }
959 
960  myG_temp *= (1 / psiCurrent);
961  myL_temp *= (1 / psiCurrent);
962 
963  // calculation of myG_J which will be used to represent \frac{\nabla\psi_{J}}{\psi_{J}}
964  // calculation of myL_J will be used to represent \frac{\nabla^2\psi_{J}}{\psi_{J}}
965  // IMPORTANT NOTE: The value of P.L holds \nabla^2 ln[\psi] but we need \frac{\nabla^2 \psi}{\psi} and this is what myL_J will hold
966  for (int iat = 0; iat < (myL_temp.size()); iat++)
967  {
968  myG_J[iat] = (P.G[iat] - myG_temp[iat]);
969  myL_J[iat] = (P.L[iat] + dot(P.G[iat], P.G[iat]) - myL_temp[iat]);
970  }
971 
972 
973  table_method_eval(dlogpsi, dhpsioverpsi, myL_J, myG_J, nel, nmo, psiCurrent, Coeff, C2node_up, C2node_dn,
974  detValues_up, detValues_dn, grads_up, grads_dn, lapls_up, lapls_dn, M_up, M_dn, Minv_up, Minv_dn,
975  B_grad, B_lapl, detData_up, N1, N2, NP1, NP2, lookup_tbl);
976  }
977 #endif
978 }
979 
980 
982  const opt_variables_type& optvars,
983  Vector<ValueType>& dlogpsi,
984  const QTFull::ValueType& psiCurrent,
985  const std::vector<ValueType>& Coeff,
986  const std::vector<size_t>& C2node_up,
987  const std::vector<size_t>& C2node_dn,
988  const ValueVector& detValues_up,
989  const ValueVector& detValues_dn,
990  const ValueMatrix& M_up,
991  const ValueMatrix& M_dn,
992  const ValueMatrix& Minv_up,
993  const ValueMatrix& Minv_dn,
994  const std::vector<int>& detData_up,
995  const std::vector<std::vector<int>>& lookup_tbl)
996 {
997 #ifndef QMC_COMPLEX
998  bool recalculate(false);
999  for (int k = 0; k < myVars.size(); ++k)
1000  {
1001  int kk = myVars.where(k);
1002  if (kk < 0)
1003  continue;
1004  if (optvars.recompute(kk))
1005  recalculate = true;
1006  }
1007  if (recalculate)
1008  {
1009  const size_t nmo = Phi_->getOrbitalSetSize();
1010  const size_t nel = P.last(0) - P.first(0);
1011 
1012  table_method_evalWF(dlogpsi, nel, nmo, psiCurrent, Coeff, C2node_up, C2node_dn, detValues_up, detValues_dn, M_up,
1013  M_dn, Minv_up, Minv_dn, detData_up, lookup_tbl);
1014  }
1015 #endif
1016 }
1017 
1019  Vector<ValueType>& dhpsioverpsi,
1020  const ParticleSet::ParticleLaplacian& myL_J,
1021  const ParticleSet::ParticleGradient& myG_J,
1022  const size_t nel,
1023  const size_t nmo,
1024  const ValueType& psiCurrent,
1025  const std::vector<RealType>& Coeff,
1026  const std::vector<size_t>& C2node_up,
1027  const std::vector<size_t>& C2node_dn,
1028  const ValueVector& detValues_up,
1029  const ValueVector& detValues_dn,
1030  const GradMatrix& grads_up,
1031  const GradMatrix& grads_dn,
1032  const ValueMatrix& lapls_up,
1033  const ValueMatrix& lapls_dn,
1034  const ValueMatrix& M_up,
1035  const ValueMatrix& M_dn,
1036  const ValueMatrix& Minv_up,
1037  const ValueMatrix& Minv_dn,
1038  const GradMatrix& B_grad,
1039  const ValueMatrix& B_lapl,
1040  const std::vector<int>& detData_up,
1041  const size_t N1,
1042  const size_t N2,
1043  const size_t NP1,
1044  const size_t NP2,
1045  const std::vector<std::vector<int>>& lookup_tbl)
1046 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1047 GUIDE TO THE MATICES BEING BUILT
1048 ----------------------------------------------
1049 The idea here is that there is a loop over all unique determinants. For each determiant the table method is employed to calculate the contributions to the parameter derivatives (dhpsioverpsi/dlogpsi)
1050 
1051  loop through unquie determinants
1052  loop through parameters
1053  evaluate contributaion to dlogpsi and dhpsioverpsi
1054 \noindent
1055 
1056  BLAS GUIDE for matrix multiplication of [ alpha * A.B + beta * C = C ]
1057  Matrix A is of dimensions a1,a2 and Matrix B is b1,b2 in which a2=b1
1058  The BLAS command is as follows...
1059 
1060  BLAS::gemm('N','N', b2, a1, a2 ,alpha, B, b2, A, a2, beta, C, b2);
1061 
1062 Below is a human readable format for the matrix multiplications performed below...
1063 
1064 This notation is inspired by http://dx.doi.org/10.1063/1.4948778
1065 \newline
1066 \hfill\break
1067 $
1068  A_{i,j}=\phi_j(r_{i}) \\
1069  T = A^{-1} \widetilde{A} \\
1070  B_{i,j} =\nabla^2 \phi_{j}(r_i) + \frac{\nabla_{i}J}{J} \cdot \nabla \phi_{j}(r_{i}) + \frac{\nabla^2_i J}{J} \phi_{j}(r_{i}) \\
1071  \hat{O_{I}} = \hat{O}D_{I} \\
1072  D_{I}=det(A_{I}) \newline
1073  \psi_{MS} = \sum_{I=0} C_{I} D_{I\uparrow}D_{I\downarrow} \\
1074  \Psi_{total} = \psi_{J}\psi_{MS} \\
1075  \alpha_{I} = P^{T}_{I}TQ_{I} \\
1076  M_{I} = P^{T}_{I} \widetilde{M} Q_{I} = P^{T}_{I} (A^{-1}\widetilde{B} - A^{-1} B A^{-1}\widetilde{A} )Q_{I} \\
1077 $
1078 \newline
1079 There are three constants I use in the expressions for dhpsioverpsi and dlogpsi
1080 \newline
1081 \hfill\break
1082 $
1083  const0 = C_{0}*det(A_{0\downarrow})+\sum_{I=1} C_{I}*det(A_{I\downarrow})* det(\alpha_{I\uparrow}) \\
1084  const1 = C_{0}*\hat{O} det(A_{0\downarrow})+\sum_{I=1} C_{I}*\hat{O}det(A_{I\downarrow})* det(\alpha_{I\uparrow}) \\
1085  const2 = \sum_{I=1} C_{I}*det(A_{I\downarrow})* Tr[\alpha_{I}^{-1}M_{I}]*det(\alpha_{I}) \\
1086 $
1087 \newline
1088 Below is a translation of the shorthand I use to represent matrices independent of ``excitation matrix".
1089 \newline
1090 \hfill\break
1091 $
1092  Y_{1} = A^{-1}B \\
1093  Y_{2} = A^{-1}BA^{-1}\widetilde{A} \\
1094  Y_{3} = A^{-1}\widetilde{B} \\
1095  Y_{4} = \widetilde{M} = (A^{-1}\widetilde{B} - A^{-1} B A^{-1}\widetilde{A} )\\
1096 $
1097 \newline
1098 Below is a translation of the shorthand I use to represent matrices dependent on ``excitation" with respect to the reference Matrix and sums of matrices. Above this line I have represented these excitation matrices with a subscript ``I" but from this point on The subscript will be omitted and it is clear that whenever a matrix depends on $P^{T}_I$ and $Q_{I}$ that this is an excitation matrix. The reference matrix is always $A_{0}$ and is always the Hartree Fock Matrix.
1099 \newline
1100 \hfill\break
1101 $
1102  Y_{5} = TQ \\
1103  Y_{6} = (P^{T}TQ)^{-1} = \alpha_{I}^{-1}\\
1104  Y_{7} = \alpha_{I}^{-1} P^{T} \\
1105  Y_{11} = \widetilde{M}Q \\
1106  Y_{23} = P^{T}\widetilde{M}Q \\
1107  Y_{24} = \alpha_{I}^{-1}P^{T}\widetilde{M}Q \\
1108  Y_{25} = \alpha_{I}^{-1}P^{T}\widetilde{M}Q\alpha_{I}^{-1} \\
1109  Y_{26} = \alpha_{I}^{-1}P^{T}\widetilde{M}Q\alpha_{I}^{-1}P^{T}\\
1110 $
1111 \newline
1112 So far you will notice that I have not included up or down arrows to specify what spin the matrices are of. This is because we are calculating the derivative of all up or all down spin orbital rotation parameters at a time. If we are finding the up spin derivatives then any term that is down spin will be constant. The following assumes that we are taking up-spin MO rotation parameter derivatives. Of course the down spin expression can be retrieved by swapping the up and down arrows. I have dubbed any expression with lowercase p prefix as a "precursor" to an expression actually used...
1113 \newline
1114 \hfill\break
1115 $
1116  \dot{C_{I}} = C_{I}*det(A_{I\downarrow})\\
1117  \ddot{C_{I}} = C_{I}*\hat{O}det(A_{I\downarrow}) \\
1118  pK1 = \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) Tr[\alpha_{I}^{-1}M_{I}] (Q\alpha_{I}^{-1}P^{T}) \\
1119  pK2 = \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) (Q\alpha_{I}^{-1}P^{T}) \\
1120  pK3 = \sum_{I=1} \ddot{C_{I}} det(\alpha_{I}) (Q\alpha_{I}^{-1}P^{T}) \\
1121  pK4 = \sum_{I=1} \dot{C_{I}} det(A_{I}) (Q\alpha_{I}^{-1}P^{T}) \\
1122  pK5 = \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) (Q\alpha_{I}^{-1} M_{I} \alpha_{I}^{-1}P^{T}) \\
1123 $
1124 \newline
1125 Now these p matrices will be used to make various expressions via BLAS commands.
1126 \newline
1127 \hfill\break
1128 $
1129  K1T = const0^{-1}*pK1.T =const0^{-1} \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) Tr[\alpha_{I}^{-1}M_{I}] (Q\alpha_{I}^{-1}P^{T}T) \\
1130  TK1T = T.K1T = const0^{-1} \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) Tr[\alpha_{I}^{-1}M_{I}] (TQ\alpha_{I}^{-1}P^{T}T)\\ \\
1131  K2AiB = const0^{-1} \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) (Q\alpha_{I}^{-1}P^{T}A^{-1}\widetilde{B})\\
1132  TK2AiB = T.K2AiB = const0^{-1} \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) (TQ\alpha_{I}^{-1}P^{T}A^{-1}\widetilde{B})\\
1133  K2XA = const0^{-1} \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) (Q\alpha_{I}^{-1}P^{T}X\widetilde{A})\\
1134  TK2XA = T.K2XA = const0^{-1} \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) (TQ\alpha_{I}^{-1}P^{T}X\widetilde{A})\\ \\
1135  K2T = \frac{const1}{const0^{2}} \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) (Q\alpha_{I}^{-1}P^{T}T) \\
1136  TK2T = T.K2T =\frac{const1}{const0^{2}} \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) (TQ\alpha_{I}^{-1}P^{T}T) \\
1137  MK2T = \frac{const0}{const1} Y_{4}.K2T= const0^{-1} \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) (\widetilde{M}Q\alpha_{I}^{-1}P^{T}T)\\ \\
1138  K3T = const0^{-1} \sum_{I=1} \ddot{C_{I}} det(\alpha_{I}) (Q\alpha_{I}^{-1}P^{T}T) \\
1139  TK3T = T.K3T = const0^{-1} \sum_{I=1} \ddot{C_{I}} det(\alpha_{I}) (TQ\alpha_{I}^{-1}P^{T}T)\\ \\
1140  K4T = \sum_{I=1} \dot{C_{I}} det(A_{I}) (Q\alpha_{I}^{-1}P^{T}T) \\
1141  TK4T = T.K4T = \sum_{I=1} \dot{C_{I}} det(A_{I}) (TQ\alpha_{I}^{-1}P^{T}T) \\ \\
1142  K5T = const0^{-1} \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) (Q\alpha_{I}^{-1} M_{I} \alpha_{I}^{-1}P^{T} T) \\
1143  TK5T = T.K5T = \sum_{I=1} \dot{C_{I}} det(\alpha_{I}) (T Q\alpha_{I}^{-1} M_{I} \alpha_{I}^{-1}P^{T} T) \\
1144 $
1145 \newline
1146 Now with all these matrices and constants the expressions of dhpsioverpsi and dlogpsi can be created.
1147 
1148 
1149 
1150 
1151 In addition I will be using a special generalization of the kinetic operator which I will denote as O. Our Slater matrix with the special O operator applied to each element will be called B_bar
1152 
1153 $
1154 ``Bbar"_{i,j} =\nabla^2 \phi_{j}(r_i) + \frac{\nabla_{i}J}{J} \cdot \nabla \phi_{j}(r_{i}) + \frac{\nabla^2_i J}{J} \phi_{j}(r_{i})
1155 $
1156 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1157 {
1158 #ifndef QMC_COMPLEX
1159  ValueMatrix Table;
1160  ValueMatrix Bbar;
1161  ValueMatrix Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y11, Y23, Y24, Y25, Y26;
1162  ValueMatrix pK1, K1T, TK1T, pK2, K2AiB, TK2AiB, K2XA, TK2XA, K2T, TK2T, MK2T, pK3, K3T, TK3T, pK5, K5T, TK5T;
1163 
1164  Table.resize(nel, nmo);
1165 
1166  Bbar.resize(nel, nmo);
1167 
1168  Y1.resize(nel, nel);
1169  Y2.resize(nel, nmo);
1170  Y3.resize(nel, nmo);
1171  Y4.resize(nel, nmo);
1172 
1173  pK1.resize(nmo, nel);
1174  K1T.resize(nmo, nmo);
1175  TK1T.resize(nel, nmo);
1176 
1177  pK2.resize(nmo, nel);
1178  K2AiB.resize(nmo, nmo);
1179  TK2AiB.resize(nel, nmo);
1180  K2XA.resize(nmo, nmo);
1181  TK2XA.resize(nel, nmo);
1182  K2T.resize(nmo, nmo);
1183  TK2T.resize(nel, nmo);
1184  MK2T.resize(nel, nmo);
1185 
1186  pK3.resize(nmo, nel);
1187  K3T.resize(nmo, nmo);
1188  TK3T.resize(nel, nmo);
1189 
1190  pK5.resize(nmo, nel);
1191  K5T.resize(nmo, nmo);
1192  TK5T.resize(nel, nmo);
1193 
1194  const int parameters_size(m_act_rot_inds_.size());
1195  const int parameter_start_index(0);
1196 
1197  const size_t num_unique_up_dets(detValues_up.size());
1198  const size_t num_unique_dn_dets(detValues_dn.size());
1199 
1200  const RealType* restrict cptr = Coeff.data();
1201  const size_t nc = Coeff.size();
1202  const size_t* restrict upC(C2node_up.data());
1203  const size_t* restrict dnC(C2node_dn.data());
1204  //B_grad holds the gradient operator
1205  //B_lapl holds the laplacian operator
1206  //B_bar will hold our special O operator
1207 
1208  const int offset1(N1);
1209  const int offset2(N2);
1210  const int NPother(NP2);
1211 
1212  RealType* T(Table.data());
1213 
1214  //possibly replace wit BLAS calls
1215  for (int i = 0; i < nel; i++)
1216  for (int j = 0; j < nmo; j++)
1217  Bbar(i, j) = B_lapl(i, j) + 2 * dot(myG_J[i + offset1], B_grad(i, j)) + myL_J[i + offset1] * M_up(i, j);
1218 
1219  const RealType* restrict B(Bbar.data());
1220  const RealType* restrict A(M_up.data());
1221  const RealType* restrict Ainv(Minv_up.data());
1222  //IMPORTANT NOTE: THE Dets[0]->psiMinv OBJECT DOES NOT HOLD THE INVERSE IF THE MULTIDIRACDETERMINANTBASE ONLY CONTAINS ONE ELECTRON. NEED A FIX FOR THIS CASE
1223  // The T matrix should be calculated and stored for use
1224  // T = A^{-1} \widetilde A
1225  //REMINDER: that the ValueMatrix "matrix" stores data in a row major order and that BLAS commands assume column major
1226  BLAS::gemm('N', 'N', nmo, nel, nel, RealType(1.0), A, nmo, Ainv, nel, RealType(0.0), T, nmo);
1227 
1228  BLAS::gemm('N', 'N', nel, nel, nel, RealType(1.0), B, nmo, Ainv, nel, RealType(0.0), Y1.data(), nel);
1229  BLAS::gemm('N', 'N', nmo, nel, nel, RealType(1.0), T, nmo, Y1.data(), nel, RealType(0.0), Y2.data(), nmo);
1230  BLAS::gemm('N', 'N', nmo, nel, nel, RealType(1.0), B, nmo, Ainv, nel, RealType(0.0), Y3.data(), nmo);
1231 
1232  //possibly replace with BLAS call
1233  Y4 = Y3 - Y2;
1234 
1235  //Need to create the constants: (Oi, const0, const1, const2)to take advantage of minimal BLAS commands;
1236  //Oi is the special operator applied to the slater matrix "A subscript i" from the total CI expansion
1237  //\hat{O_{i}} = \hat{O}D_{i} with D_{i}=det(A_{i}) and Multi-Slater component defined as \sum_{i=0} C_{i} D_{i\uparrow}D_{i\downarrow}
1238  std::vector<RealType> Oi(num_unique_dn_dets);
1239 
1240  for (int index = 0; index < num_unique_dn_dets; index++)
1241  for (int iat = 0; iat < NPother; iat++)
1242  Oi[index] += lapls_dn(index, iat) + 2 * dot(grads_dn(index, iat), myG_J[offset2 + iat]) +
1243  myL_J[offset2 + iat] * detValues_dn[index];
1244 
1245  //const0 = C_{0}*det(A_{0\downarrow})+\sum_{i=1} C_{i}*det(A_{i\downarrow})* det(\alpha_{i\uparrow})
1246  //const1 = C_{0}*\hat{O} det(A_{0\downarrow})+\sum_{i=1} C_{i}*\hat{O}det(A_{i\downarrow})* det(\alpha_{i\uparrow})
1247  //const2 = \sum_{i=1} C_{i}*det(A_{i\downarrow})* Tr[\alpha_{i}^{-1}M_{i}]*det(\alpha_{i})
1248  RealType const0(0.0), const1(0.0), const2(0.0);
1249  for (size_t i = 0; i < nc; ++i)
1250  {
1251  const RealType c = cptr[i];
1252  const size_t up = upC[i];
1253  const size_t down = dnC[i];
1254 
1255  const0 += c * detValues_dn[down] * (detValues_up[up] / detValues_up[0]);
1256  const1 += c * Oi[down] * (detValues_up[up] / detValues_up[0]);
1257  }
1258 
1259  std::fill(pK1.begin(), pK1.end(), 0.0);
1260  std::fill(pK2.begin(), pK2.end(), 0.0);
1261  std::fill(pK3.begin(), pK3.end(), 0.0);
1262  std::fill(pK5.begin(), pK5.end(), 0.0);
1263 
1264  //Now we are going to loop through all unique determinants.
1265  //The few lines above are for the reference matrix contribution.
1266  //Although I start the loop below from index 0, the loop only performs actions when the index is >= 1
1267  //the detData object contains all the information about the P^T and Q matrices (projection matrices) needed in the table method
1268  const int* restrict data_it = detData_up.data();
1269  for (int index = 0, datum = 0; index < num_unique_up_dets; index++)
1270  {
1271  const int k = data_it[datum];
1272 
1273  if (k == 0)
1274  {
1275  datum += 3 * k + 1;
1276  }
1277 
1278  else
1279  {
1280  //Number of rows and cols of P^T
1281  const int prows = k;
1282  const int pcols = nel;
1283  //Number of rows and cols of Q
1284  const int qrows = nmo;
1285  const int qcols = k;
1286 
1287  Y5.resize(nel, k);
1288  Y6.resize(k, k);
1289 
1290  //Any matrix multiplication of P^T or Q is simply a projection
1291  //Explicit matrix multiplication can be avoided; instead column or row copying can be done
1292  //BlAS::copy(size of col/row being copied,
1293  // Matrix pointer + place to begin copying,
1294  // storage spacing (number of elements btw next row/col element),
1295  // Pointer to resultant matrix + place to begin pasting,
1296  // storage spacing of resultant matrix)
1297  //For example the next 4 lines is the matrix multiplication of T*Q = Y5
1298  std::fill(Y5.begin(), Y5.end(), 0.0);
1299  for (int i = 0; i < k; i++)
1300  {
1301  BLAS::copy(nel, T + data_it[datum + 1 + k + i], nmo, Y5.data() + i, k);
1302  }
1303 
1304  std::fill(Y6.begin(), Y6.end(), 0.0);
1305  for (int i = 0; i < k; i++)
1306  {
1307  BLAS::copy(k, Y5.data() + (data_it[datum + 1 + i]) * k, 1, (Y6.data() + i * k), 1);
1308  }
1309 
1310 
1311  Vector<ValueType> WS;
1312  Vector<IndexType> Piv;
1313  WS.resize(k);
1314  Piv.resize(k);
1315  std::complex<RealType> logdet = 0.0;
1316  InvertWithLog(Y6.data(), k, k, WS.data(), Piv.data(), logdet);
1317 
1318  Y11.resize(nel, k);
1319  Y23.resize(k, k);
1320  Y24.resize(k, k);
1321  Y25.resize(k, k);
1322  Y26.resize(k, nel);
1323 
1324  std::fill(Y11.begin(), Y11.end(), 0.0);
1325  for (int i = 0; i < k; i++)
1326  {
1327  BLAS::copy(nel, Y4.data() + (data_it[datum + 1 + k + i]), nmo, Y11.data() + i, k);
1328  }
1329 
1330  std::fill(Y23.begin(), Y23.end(), 0.0);
1331  for (int i = 0; i < k; i++)
1332  {
1333  BLAS::copy(k, Y11.data() + (data_it[datum + 1 + i]) * k, 1, (Y23.data() + i * k), 1);
1334  }
1335 
1336  BLAS::gemm('N', 'N', k, k, k, RealType(1.0), Y23.data(), k, Y6.data(), k, RealType(0.0), Y24.data(), k);
1337  BLAS::gemm('N', 'N', k, k, k, RealType(1.0), Y6.data(), k, Y24.data(), k, RealType(0.0), Y25.data(), k);
1338 
1339 
1340  Y26.resize(k, nel);
1341 
1342  std::fill(Y26.begin(), Y26.end(), 0.0);
1343  for (int i = 0; i < k; i++)
1344  {
1345  BLAS::copy(k, Y25.data() + i, k, Y26.data() + (data_it[datum + 1 + i]), nel);
1346  }
1347 
1348 
1349  Y7.resize(k, nel);
1350 
1351  std::fill(Y7.begin(), Y7.end(), 0.0);
1352  for (int i = 0; i < k; i++)
1353  {
1354  BLAS::copy(k, Y6.data() + i, k, Y7.data() + (data_it[datum + 1 + i]), nel);
1355  }
1356 
1357  // c_Tr_AlphaI_MI is a constant contributing to constant const2
1358  // c_Tr_AlphaI_MI = Tr[\alpha_{I}^{-1}(P^{T}\widetilde{M} Q)]
1359  RealType c_Tr_AlphaI_MI = 0.0;
1360  for (int i = 0; i < k; i++)
1361  {
1362  c_Tr_AlphaI_MI += Y24(i, i);
1363  }
1364 
1365  for (int p = 0; p < lookup_tbl[index].size(); p++)
1366  {
1367  //el_p is the element position that contains information about the CI coefficient, and det up/dn values associated with the current unique determinant
1368  const int el_p(lookup_tbl[index][p]);
1369  const RealType c = cptr[el_p];
1370  const size_t up = upC[el_p];
1371  const size_t down = dnC[el_p];
1372 
1373  const RealType alpha_1(c * detValues_dn[down] * detValues_up[up] / detValues_up[0] * c_Tr_AlphaI_MI);
1374  const RealType alpha_2(c * detValues_dn[down] * detValues_up[up] / detValues_up[0]);
1375  const RealType alpha_3(c * Oi[down] * detValues_up[up] / detValues_up[0]);
1376 
1377  const2 += alpha_1;
1378 
1379  for (int i = 0; i < k; i++)
1380  {
1381  BLAS::axpy(nel, alpha_1, Y7.data() + i * nel, 1, pK1.data() + (data_it[datum + 1 + k + i]) * nel, 1);
1382  BLAS::axpy(nel, alpha_2, Y7.data() + i * nel, 1, pK2.data() + (data_it[datum + 1 + k + i]) * nel, 1);
1383  BLAS::axpy(nel, alpha_3, Y7.data() + i * nel, 1, pK3.data() + (data_it[datum + 1 + k + i]) * nel, 1);
1384  BLAS::axpy(nel, alpha_2, Y26.data() + i * nel, 1, pK5.data() + (data_it[datum + 1 + k + i]) * nel, 1);
1385  }
1386  }
1387  datum += 3 * k + 1;
1388  }
1389  }
1390 
1391 
1392  BLAS::gemm('N', 'N', nmo, nmo, nel, 1.0 / const0, T, nmo, pK1.data(), nel, RealType(0.0), K1T.data(), nmo);
1393  BLAS::gemm('N', 'N', nmo, nel, nmo, RealType(1.0), K1T.data(), nmo, T, nmo, RealType(0.0), TK1T.data(), nmo);
1394 
1395  BLAS::gemm('N', 'N', nmo, nmo, nel, 1.0 / const0, Y3.data(), nmo, pK2.data(), nel, RealType(0.0), K2AiB.data(), nmo);
1396  BLAS::gemm('N', 'N', nmo, nel, nmo, RealType(1.0), K2AiB.data(), nmo, T, nmo, RealType(0.0), TK2AiB.data(), nmo);
1397  BLAS::gemm('N', 'N', nmo, nmo, nel, 1.0 / const0, Y2.data(), nmo, pK2.data(), nel, RealType(0.0), K2XA.data(), nmo);
1398  BLAS::gemm('N', 'N', nmo, nel, nmo, RealType(1.0), K2XA.data(), nmo, T, nmo, RealType(0.0), TK2XA.data(), nmo);
1399 
1400  BLAS::gemm('N', 'N', nmo, nmo, nel, const1 / (const0 * const0), T, nmo, pK2.data(), nel, RealType(0.0), K2T.data(),
1401  nmo);
1402  BLAS::gemm('N', 'N', nmo, nel, nmo, RealType(1.0), K2T.data(), nmo, T, nmo, RealType(0.0), TK2T.data(), nmo);
1403  BLAS::gemm('N', 'N', nmo, nel, nmo, const0 / const1, K2T.data(), nmo, Y4.data(), nmo, RealType(0.0), MK2T.data(),
1404  nmo);
1405 
1406  BLAS::gemm('N', 'N', nmo, nmo, nel, 1.0 / const0, T, nmo, pK3.data(), nel, RealType(0.0), K3T.data(), nmo);
1407  BLAS::gemm('N', 'N', nmo, nel, nmo, RealType(1.0), K3T.data(), nmo, T, nmo, RealType(0.0), TK3T.data(), nmo);
1408 
1409  BLAS::gemm('N', 'N', nmo, nmo, nel, 1.0 / const0, T, nmo, pK5.data(), nel, RealType(0.0), K5T.data(), nmo);
1410  BLAS::gemm('N', 'N', nmo, nel, nmo, RealType(1.0), K5T.data(), nmo, T, nmo, RealType(0.0), TK5T.data(), nmo);
1411 
1412 
1413  for (int mu = 0, k = parameter_start_index; k < (parameter_start_index + parameters_size); k++, mu++)
1414  {
1415  int kk = myVars.where(k);
1416  if (kk >= 0)
1417  {
1418  const int i(m_act_rot_inds_[mu].first), j(m_act_rot_inds_[mu].second);
1419  if (i <= nel - 1 && j > nel - 1)
1420  {
1421  dhpsioverpsi[kk] +=
1422  ValueType(-0.5 * Y4(i, j) -
1423  0.5 *
1424  (-K5T(i, j) + K5T(j, i) + TK5T(i, j) + K2AiB(i, j) - K2AiB(j, i) - TK2AiB(i, j) - K2XA(i, j) +
1425  K2XA(j, i) + TK2XA(i, j) - MK2T(i, j) + K1T(i, j) - K1T(j, i) - TK1T(i, j) -
1426  const2 / const1 * K2T(i, j) + const2 / const1 * K2T(j, i) + const2 / const1 * TK2T(i, j) +
1427  K3T(i, j) - K3T(j, i) - TK3T(i, j) - K2T(i, j) + K2T(j, i) + TK2T(i, j)));
1428  }
1429  else if (i <= nel - 1 && j <= nel - 1)
1430  {
1431  dhpsioverpsi[kk] += ValueType(
1432  -0.5 * (Y4(i, j) - Y4(j, i)) -
1433  0.5 *
1434  (-K5T(i, j) + K5T(j, i) + TK5T(i, j) - TK5T(j, i) + K2AiB(i, j) - K2AiB(j, i) - TK2AiB(i, j) +
1435  TK2AiB(j, i) - K2XA(i, j) + K2XA(j, i) + TK2XA(i, j) - TK2XA(j, i) - MK2T(i, j) + MK2T(j, i) +
1436  K1T(i, j) - K1T(j, i) - TK1T(i, j) + TK1T(j, i) - const2 / const1 * K2T(i, j) +
1437  const2 / const1 * K2T(j, i) + const2 / const1 * TK2T(i, j) - const2 / const1 * TK2T(j, i) + K3T(i, j) -
1438  K3T(j, i) - TK3T(i, j) + TK3T(j, i) - K2T(i, j) + K2T(j, i) + TK2T(i, j) - TK2T(j, i)));
1439  }
1440  else
1441  {
1442  dhpsioverpsi[kk] += ValueType(-0.5 *
1443  (-K5T(i, j) + K5T(j, i) + K2AiB(i, j) - K2AiB(j, i) - K2XA(i, j) + K2XA(j, i)
1444 
1445  + K1T(i, j) - K1T(j, i) - const2 / const1 * K2T(i, j) +
1446  const2 / const1 * K2T(j, i) + K3T(i, j) - K3T(j, i) - K2T(i, j) + K2T(j, i)));
1447  }
1448  }
1449  }
1450 #endif
1451 }
1452 
1454  const size_t nel,
1455  const size_t nmo,
1456  const ValueType& psiCurrent,
1457  const std::vector<RealType>& Coeff,
1458  const std::vector<size_t>& C2node_up,
1459  const std::vector<size_t>& C2node_dn,
1460  const ValueVector& detValues_up,
1461  const ValueVector& detValues_dn,
1462  const ValueMatrix& M_up,
1463  const ValueMatrix& M_dn,
1464  const ValueMatrix& Minv_up,
1465  const ValueMatrix& Minv_dn,
1466  const std::vector<int>& detData_up,
1467  const std::vector<std::vector<int>>& lookup_tbl)
1468 {
1469 #ifndef QMC_COMPLEX
1470  ValueMatrix Table;
1471  ValueMatrix Y5, Y6, Y7;
1472  ValueMatrix pK4, K4T, TK4T;
1473 
1474  Table.resize(nel, nmo);
1475 
1476  Bbar.resize(nel, nmo);
1477 
1478  pK4.resize(nmo, nel);
1479  K4T.resize(nmo, nmo);
1480  TK4T.resize(nel, nmo);
1481 
1482  const int parameters_size(m_act_rot_inds_.size());
1483  const int parameter_start_index(0);
1484 
1485  const size_t num_unique_up_dets(detValues_up.size());
1486  const size_t num_unique_dn_dets(detValues_dn.size());
1487 
1488  const RealType* restrict cptr = Coeff.data();
1489  const size_t nc = Coeff.size();
1490  const size_t* restrict upC(C2node_up.data());
1491  const size_t* restrict dnC(C2node_dn.data());
1492 
1493  RealType* T(Table.data());
1494 
1495  const RealType* restrict A(M_up.data());
1496  const RealType* restrict Ainv(Minv_up.data());
1497  //IMPORTANT NOTE: THE Dets[0]->psiMinv OBJECT DOES NOT HOLD THE INVERSE IF THE MULTIDIRACDETERMINANTBASE ONLY CONTAINS ONE ELECTRON. NEED A FIX FOR THIS CASE
1498  // The T matrix should be calculated and stored for use
1499  // T = A^{-1} \widetilde A
1500  //REMINDER: that the ValueMatrix "matrix" stores data in a row major order and that BLAS commands assume column major
1501  BLAS::gemm('N', 'N', nmo, nel, nel, RealType(1.0), A, nmo, Ainv, nel, RealType(0.0), T, nmo);
1502 
1503  //const0 = C_{0}*det(A_{0\downarrow})+\sum_{i=1} C_{i}*det(A_{i\downarrow})* det(\alpha_{i\uparrow})
1504  RealType const0(0.0), const1(0.0), const2(0.0);
1505  for (size_t i = 0; i < nc; ++i)
1506  {
1507  const RealType c = cptr[i];
1508  const size_t up = upC[i];
1509  const size_t down = dnC[i];
1510 
1511  const0 += c * detValues_dn[down] * (detValues_up[up] / detValues_up[0]);
1512  }
1513 
1514  std::fill(pK4.begin(), pK4.end(), 0.0);
1515 
1516  //Now we are going to loop through all unique determinants.
1517  //The few lines above are for the reference matrix contribution.
1518  //Although I start the loop below from index 0, the loop only performs actions when the index is >= 1
1519  //the detData object contains all the information about the P^T and Q matrices (projection matrices) needed in the table method
1520  const int* restrict data_it = detData_up.data();
1521  for (int index = 0, datum = 0; index < num_unique_up_dets; index++)
1522  {
1523  const int k = data_it[datum];
1524 
1525  if (k == 0)
1526  {
1527  datum += 3 * k + 1;
1528  }
1529 
1530  else
1531  {
1532  //Number of rows and cols of P^T
1533  const int prows = k;
1534  const int pcols = nel;
1535  //Number of rows and cols of Q
1536  const int qrows = nmo;
1537  const int qcols = k;
1538 
1539  Y5.resize(nel, k);
1540  Y6.resize(k, k);
1541 
1542  //Any matrix multiplication of P^T or Q is simply a projection
1543  //Explicit matrix multiplication can be avoided; instead column or row copying can be done
1544  //BlAS::copy(size of col/row being copied,
1545  // Matrix pointer + place to begin copying,
1546  // storage spacing (number of elements btw next row/col element),
1547  // Pointer to resultant matrix + place to begin pasting,
1548  // storage spacing of resultant matrix)
1549  //For example the next 4 lines is the matrix multiplication of T*Q = Y5
1550  std::fill(Y5.begin(), Y5.end(), 0.0);
1551  for (int i = 0; i < k; i++)
1552  {
1553  BLAS::copy(nel, T + data_it[datum + 1 + k + i], nmo, Y5.data() + i, k);
1554  }
1555 
1556  std::fill(Y6.begin(), Y6.end(), 0.0);
1557  for (int i = 0; i < k; i++)
1558  {
1559  BLAS::copy(k, Y5.data() + (data_it[datum + 1 + i]) * k, 1, (Y6.data() + i * k), 1);
1560  }
1561 
1562  Vector<ValueType> WS;
1563  Vector<IndexType> Piv;
1564  WS.resize(k);
1565  Piv.resize(k);
1566  std::complex<RealType> logdet = 0.0;
1567  InvertWithLog(Y6.data(), k, k, WS.data(), Piv.data(), logdet);
1568 
1569  Y7.resize(k, nel);
1570 
1571  std::fill(Y7.begin(), Y7.end(), 0.0);
1572  for (int i = 0; i < k; i++)
1573  {
1574  BLAS::copy(k, Y6.data() + i, k, Y7.data() + (data_it[datum + 1 + i]), nel);
1575  }
1576 
1577  for (int p = 0; p < lookup_tbl[index].size(); p++)
1578  {
1579  //el_p is the element position that contains information about the CI coefficient, and det up/dn values associated with the current unique determinant
1580  const int el_p(lookup_tbl[index][p]);
1581  const RealType c = cptr[el_p];
1582  const size_t up = upC[el_p];
1583  const size_t down = dnC[el_p];
1584 
1585  const RealType alpha_4(c * detValues_dn[down] * detValues_up[up] * (1 / psiCurrent));
1586 
1587  for (int i = 0; i < k; i++)
1588  {
1589  BLAS::axpy(nel, alpha_4, Y7.data() + i * nel, 1, pK4.data() + (data_it[datum + 1 + k + i]) * nel, 1);
1590  }
1591  }
1592  datum += 3 * k + 1;
1593  }
1594  }
1595 
1596  BLAS::gemm('N', 'N', nmo, nmo, nel, RealType(1.0), T, nmo, pK4.data(), nel, RealType(0.0), K4T.data(), nmo);
1597  BLAS::gemm('N', 'N', nmo, nel, nmo, RealType(1.0), K4T.data(), nmo, T, nmo, RealType(0.0), TK4T.data(), nmo);
1598 
1599  for (int mu = 0, k = parameter_start_index; k < (parameter_start_index + parameters_size); k++, mu++)
1600  {
1601  int kk = myVars.where(k);
1602  if (kk >= 0)
1603  {
1604  const int i(m_act_rot_inds_[mu].first), j(m_act_rot_inds_[mu].second);
1605  if (i <= nel - 1 && j > nel - 1)
1606  {
1607  dlogpsi[kk] += ValueType(detValues_up[0] * (Table(i, j)) * const0 * (1 / psiCurrent) +
1608  (K4T(i, j) - K4T(j, i) - TK4T(i, j)));
1609  }
1610  else if (i <= nel - 1 && j <= nel - 1)
1611  {
1612  dlogpsi[kk] += ValueType(detValues_up[0] * (Table(i, j) - Table(j, i)) * const0 * (1 / psiCurrent) +
1613  (K4T(i, j) - TK4T(i, j) - K4T(j, i) + TK4T(j, i)));
1614  }
1615  else
1616  {
1617  dlogpsi[kk] += ValueType((K4T(i, j) - K4T(j, i)));
1618  }
1619  }
1620  }
1621 #endif
1622 }
1623 
1624 
1625 std::unique_ptr<SPOSet> RotatedSPOs::makeClone() const
1626 {
1627  auto myclone = std::make_unique<RotatedSPOs>(my_name_, std::unique_ptr<SPOSet>(Phi_->makeClone()));
1628 
1629  myclone->params_ = this->params_;
1630  myclone->params_supplied_ = this->params_supplied_;
1631  myclone->m_act_rot_inds_ = this->m_act_rot_inds_;
1632  myclone->m_full_rot_inds_ = this->m_full_rot_inds_;
1633  myclone->myVars = this->myVars;
1634  myclone->myVarsFull_ = this->myVarsFull_;
1635  myclone->history_params_ = this->history_params_;
1636  myclone->use_global_rot_ = this->use_global_rot_;
1637  return myclone;
1638 }
1639 
1642  const RefVector<ValueVector>& psi_list,
1643  const std::vector<const ValueType*>& invRow_ptr_list,
1644  std::vector<std::vector<ValueType>>& ratios_list) const
1645 {
1646  auto phi_list = extractPhiRefList(spo_list);
1647  auto& leader = phi_list.getLeader();
1648  leader.mw_evaluateDetRatios(phi_list, vp_list, psi_list, invRow_ptr_list, ratios_list);
1649 }
1650 
1652  const RefVectorWithLeader<ParticleSet>& P_list,
1653  int iat,
1654  const RefVector<ValueVector>& psi_v_list) const
1655 {
1656  auto phi_list = extractPhiRefList(spo_list);
1657  auto& leader = phi_list.getLeader();
1658  leader.mw_evaluateValue(phi_list, P_list, iat, psi_v_list);
1659 }
1660 
1662  const RefVectorWithLeader<ParticleSet>& P_list,
1663  int iat,
1664  const RefVector<ValueVector>& psi_v_list,
1665  const RefVector<GradVector>& dpsi_v_list,
1666  const RefVector<ValueVector>& d2psi_v_list) const
1667 {
1668  auto phi_list = extractPhiRefList(spo_list);
1669  auto& leader = phi_list.getLeader();
1670  leader.mw_evaluateVGL(phi_list, P_list, iat, psi_v_list, dpsi_v_list, d2psi_v_list);
1671 }
1672 
1674  const RefVectorWithLeader<ParticleSet>& P_list,
1675  int iat,
1676  const RefVector<ValueVector>& psi_v_list,
1677  const RefVector<GradVector>& dpsi_v_list,
1678  const RefVector<ValueVector>& d2psi_v_list,
1679  OffloadMatrix<ComplexType>& mw_dspin) const
1680 {
1681  auto phi_list = extractPhiRefList(spo_list);
1682  auto& leader = phi_list.getLeader();
1683  leader.mw_evaluateVGLWithSpin(phi_list, P_list, iat, psi_v_list, dpsi_v_list, d2psi_v_list, mw_dspin);
1684 }
1685 
1687  const RefVectorWithLeader<ParticleSet>& P_list,
1688  int iat,
1689  const std::vector<const ValueType*>& invRow_ptr_list,
1690  OffloadMWVGLArray& phi_vgl_v,
1691  std::vector<ValueType>& ratios,
1692  std::vector<GradType>& grads) const
1693 {
1694  auto phi_list = extractPhiRefList(spo_list);
1695  auto& leader = phi_list.getLeader();
1696  leader.mw_evaluateVGLandDetRatioGrads(phi_list, P_list, iat, invRow_ptr_list, phi_vgl_v, ratios, grads);
1697 }
1698 
1700  const RefVectorWithLeader<ParticleSet>& P_list,
1701  int iat,
1702  const std::vector<const ValueType*>& invRow_ptr_list,
1703  OffloadMWVGLArray& phi_vgl_v,
1704  std::vector<ValueType>& ratios,
1705  std::vector<GradType>& grads,
1706  std::vector<ValueType>& spingrads) const
1707 {
1708  auto phi_list = extractPhiRefList(spo_list);
1709  auto& leader = phi_list.getLeader();
1710  leader.mw_evaluateVGLandDetRatioGradsWithSpin(phi_list, P_list, iat, invRow_ptr_list, phi_vgl_v, ratios, grads,
1711  spingrads);
1712 }
1713 
1715  const RefVectorWithLeader<ParticleSet>& P_list,
1716  int first,
1717  int last,
1718  const RefVector<ValueMatrix>& logdet_list,
1719  const RefVector<GradMatrix>& dlogdet_list,
1720  const RefVector<ValueMatrix>& d2logdet_list) const
1721 {
1722  auto phi_list = extractPhiRefList(spo_list);
1723  auto& leader = phi_list.getLeader();
1724  leader.mw_evaluate_notranspose(phi_list, P_list, first, last, logdet_list, dlogdet_list, d2logdet_list);
1725 }
1726 
1727 void RotatedSPOs::createResource(ResourceCollection& collection) const { Phi_->createResource(collection); }
1728 
1730 {
1731  auto phi_list = extractPhiRefList(spo_list);
1732  auto& leader = phi_list.getLeader();
1733  leader.acquireResource(collection, phi_list);
1734 }
1735 
1737 {
1738  auto phi_list = extractPhiRefList(spo_list);
1739  auto& leader = phi_list.getLeader();
1740  leader.releaseResource(collection, phi_list);
1741 }
1742 
1744 {
1745  auto& spo_leader = spo_list.getCastedLeader<RotatedSPOs>();
1746  const auto nw = spo_list.size();
1747  RefVectorWithLeader<SPOSet> phi_list(*spo_leader.Phi_);
1748  phi_list.reserve(nw);
1749  for (int iw = 0; iw < nw; iw++)
1750  {
1751  RotatedSPOs& rot = spo_list.getCastedElement<RotatedSPOs>(iw);
1752  phi_list.emplace_back(*rot.Phi_);
1753  }
1754  return phi_list;
1755 }
1756 
1757 } // namespace qmcplusplus
void resetParametersExclusive(const opt_variables_type &active) override
reset
base class for Single-particle orbital sets
Definition: SPOSet.h:46
void resize(size_type n, Type_t val=Type_t())
Resize the container.
Definition: OhmmsVector.h:166
void writeVariationalParameters(hdf_archive &hout) override
Write the variational parameters for this object to the VP HDF file.
static void log_antisym_matrix(const ValueMatrix &mat, ValueMatrix &output)
static void constructAntiSymmetricMatrix(const RotationIndices &rot_indices, const std::vector< ValueType > &param, ValueMatrix &rot_mat)
Definition: RotatedSPOs.cpp:76
RotationIndices m_act_rot_inds_
Definition: RotatedSPOs.h:54
std::vector< ValueType > myVarsFull_
Full set of rotation matrix parameters for use in global rotation method.
Definition: RotatedSPOs.h:469
bool recompute(int i) const
Definition: VariableSet.h:206
std::ostream & app_warning()
Definition: OutputManager.h:69
void write(T &data, const std::string &aname)
write the data to the group aname and check status runtime error is issued on I/O error ...
Definition: hdf_archive.h:259
QMCTraits::RealType real
const ParticleSet & getRefPS() const
ParticleSet this object refers to.
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
const std::string my_name_
name of the object, unique identifier
Definition: SPOSet.h:564
QTBase::RealType RealType
Definition: Configuration.h:58
void evaluateDerivatives(ParticleSet &P, const opt_variables_type &optvars, Vector< ValueType > &dlogpsi, Vector< ValueType > &dhpsioverpsi, const int &FirstIndex, const int &LastIndex) override
Parameter derivatives of the wavefunction and the Laplacian of the wavefunction.
void copy_with_complex_cast(const std::complex< double > &source, std::complex< double > &dest)
size_t getTotalNum() const
Definition: ParticleSet.h:493
size_t nel_major_
the number of electrons of the majority spin
Definition: RotatedSPOs.h:127
void evaluateDerivativesWF(ParticleSet &P, const opt_variables_type &optvars, Vector< ValueType > &dlogpsi, int FirstIndex, int LastIndex) override
Parameter derivatives of the wavefunction.
std::ostream & app_log()
Definition: OutputManager.h:65
RotatedSPOs(const std::string &my_name, std::unique_ptr< SPOSet > &&spos)
Definition: RotatedSPOs.cpp:22
std::vector< std::vector< ValueType > > history_params_
List of previously applied parameters.
Definition: RotatedSPOs.h:475
RealType ValueType
Definition: QMCTypes.h:42
ParticleSet::ParticleGradient myG_temp
Definition: RotatedSPOs.h:136
A ParticleSet that handles virtual moves of a selected particle of a given physical ParticleSet Virtu...
opt_variables_type myVars
Optimizable variables.
Definition: SPOSet.h:568
OrbitalSetTraits< ValueType >::ValueMatrix ValueMatrix
Definition: SPOSet.h:50
int refPtcl
Reference particle.
class to handle hdf file
Definition: hdf_archive.h:51
QTBase::ComplexType ComplexType
Definition: Configuration.h:59
int first(int igroup) const
return the first index of a group i
Definition: ParticleSet.h:514
static void createRotationIndices(int nel, int nmo, RotationIndices &rot_indices)
Definition: RotatedSPOs.cpp:48
Attaches a unit to a Vector for IO.
void mw_evaluateVGLWithSpin(const RefVectorWithLeader< SPOSet > &spo_list, const RefVectorWithLeader< ParticleSet > &P_list, int iat, const RefVector< ValueVector > &psi_v_list, const RefVector< GradVector > &dpsi_v_list, const RefVector< ValueVector > &d2psi_v_list, OffloadMatrix< ComplexType > &mw_dspin) const override
evaluate the values, gradients and laplacians and spin gradient of this single-particle orbital sets ...
ParticleLaplacian L
laplacians of the particles
Definition: ParticleSet.h:85
void mw_evaluateDetRatios(const RefVectorWithLeader< SPOSet > &spo_list, const RefVectorWithLeader< const VirtualParticleSet > &vp_list, const RefVector< ValueVector > &psi_list, const std::vector< const ValueType *> &invRow_ptr_list, std::vector< std::vector< ValueType >> &ratios_list) const override
evaluate determinant ratios for virtual moves, e.g., sphere move for nonlocalPP, of multiple walkers ...
void setRotationParameters(const std::vector< RealType > &param_list)
For now, this takes the real optimizable parameters (real rotation coefficients) and converts them to...
Definition: RotatedSPOs.cpp:36
constexpr char UPLO
Definition: BLAS.hpp:42
void copy(const Array< T1, 3 > &src, Array< T2, 3 > &dest)
Definition: Blitz.h:639
OrbitalSetTraits< ValueType >::GradMatrix GradMatrix
Definition: SPOSet.h:52
void buildOptVariables(size_t nel)
Specialized paritlce class for atomistic simulations.
Definition: ParticleSet.h:55
bool getShape(const std::string &aname, std::vector< int > &sizes_out)
read the shape of multidimensional filespace from the group aname this function can be used to query ...
Definition: hdf_archive.h:231
float imag(const float &c)
imaginary part of a scalar. Cannot be replaced by std::imag due to AFQMC specific needs...
std::unique_ptr< SPOSet > makeClone() const override
make a clone of itself every derived class must implement this to have threading working correctly...
size_type size() const
return the current size
Definition: OhmmsVector.h:162
ParticleSet::ParticleLaplacian myL_temp
Definition: RotatedSPOs.h:137
RotationIndices m_full_rot_inds_
Definition: RotatedSPOs.h:57
static void extractParamsFromAntiSymmetricMatrix(const RotationIndices &rot_indices, const ValueMatrix &rot_mat, std::vector< ValueType > &param)
Definition: RotatedSPOs.cpp:97
QTBase::ValueType ValueType
Definition: Configuration.h:60
ParticleSet::ParticleLaplacian myL_J
Definition: RotatedSPOs.h:137
void table_method_eval(Vector< ValueType > &dlogpsi, Vector< ValueType > &dhpsioverpsi, const ParticleSet::ParticleLaplacian &myL_J, const ParticleSet::ParticleGradient &myG_J, const size_t nel, const size_t nmo, const ValueType &psiCurrent, const std::vector< RealType > &Coeff, const std::vector< size_t > &C2node_up, const std::vector< size_t > &C2node_dn, const ValueVector &detValues_up, const ValueVector &detValues_dn, const GradMatrix &grads_up, const GradMatrix &grads_dn, const ValueMatrix &lapls_up, const ValueMatrix &lapls_dn, const ValueMatrix &M_up, const ValueMatrix &M_dn, const ValueMatrix &Minv_up, const ValueMatrix &Minv_dn, const GradMatrix &B_grad, const ValueMatrix &B_lapl, const std::vector< int > &detData_up, const size_t N1, const size_t N2, const size_t NP1, const size_t NP2, const std::vector< std::vector< int >> &lookup_tbl)
void mw_evaluateVGL(const RefVectorWithLeader< SPOSet > &spo_list, const RefVectorWithLeader< ParticleSet > &P_list, int iat, const RefVector< ValueVector > &psi_v_list, const RefVector< GradVector > &dpsi_v_list, const RefVector< ValueVector > &d2psi_v_list) const override
evaluate the values, gradients and laplacians of this single-particle orbital sets of multiple walker...
void mw_evaluate_notranspose(const RefVectorWithLeader< SPOSet > &spo_list, const RefVectorWithLeader< ParticleSet > &P_list, int first, int last, const RefVector< ValueMatrix > &logdet_list, const RefVector< GradMatrix > &dlogdet_list, const RefVector< ValueMatrix > &d2logdet_list) const override
void InvertWithLog(T *restrict x, int n, int m, T *restrict work, int *restrict pivot, std::complex< T1 > &logdet)
void applyDeltaRotation(const std::vector< ValueType > &delta_param, const std::vector< ValueType > &old_param, std::vector< ValueType > &new_param)
static void heev(char &jobz, char &uplo, int &n, std::complex< float > *a, int &lda, float *w, std::complex< float > *work, int &lwork, float *rwork, int &info)
Definition: BLAS.hpp:492
ParticleGradient G
gradients of the particles
Definition: ParticleSet.h:83
OrbitalSetTraits< ValueType >::ValueVector ValueVector
Definition: SPOSet.h:49
CASTTYPE & getCastedElement(size_t i) const
NewTimer & createGlobalTimer(const std::string &myname, timer_levels mylevel)
class to handle a set of variables that can be modified during optimizations
Definition: VariableSet.h:49
int where(int i) const
return the locator of the i-th Index
Definition: VariableSet.h:90
IndexType OrbitalSetSize
number of Single-particle orbitals
Definition: SPOSet.h:566
void mw_evaluateValue(const RefVectorWithLeader< SPOSet > &spo_list, const RefVectorWithLeader< ParticleSet > &P_list, int iat, const RefVector< ValueVector > &psi_v_list) const override
evaluate the values this single-particle orbital sets of multiple walkers
std::vector< std::pair< int, int > > RotationIndices
Definition: RotatedSPOs.h:42
int last(int igroup) const
return the last index of a group i
Definition: ParticleSet.h:517
MakeReturn< UnaryNode< FnExp, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t exp(const Vector< T1, C1 > &l)
void evaluateDerivRatios(const VirtualParticleSet &VP, const opt_variables_type &optvars, ValueVector &psi, const ValueVector &psiinv, std::vector< ValueType > &ratios, Matrix< ValueType > &dratios, int FirstIndex, int LastIndex) override
Determinant ratios and parameter derivatives of the wavefunction for virtual moves.
static void createRotationIndicesFull(int nel, int nmo, RotationIndices &rot_indices)
Definition: RotatedSPOs.cpp:55
void clear()
clear the variable set
Definition: VariableSet.cpp:28
size_type size() const
return the size
Definition: VariableSet.h:88
ParticleSet::ParticleGradient myG_J
Definition: RotatedSPOs.h:136
float conj(const float &c)
Workaround to allow conj on scalar to return real instead of complex.
static RefVectorWithLeader< SPOSet > extractPhiRefList(const RefVectorWithLeader< SPOSet > &spo_list)
void push(const std::string &gname, bool createit=true)
push a group to the group stack
MakeReturn< UnaryNode< FnLog, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t log(const Vector< T1, C1 > &l)
static void exponentiate_antisym_matrix(ValueMatrix &mat)
Define determinant operators.
void table_method_evalWF(Vector< ValueType > &dlogpsi, const size_t nel, const size_t nmo, const ValueType &psiCurrent, const std::vector< RealType > &Coeff, const std::vector< size_t > &C2node_up, const std::vector< size_t > &C2node_dn, const ValueVector &detValues_up, const ValueVector &detValues_dn, const ValueMatrix &M_up, const ValueMatrix &M_dn, const ValueMatrix &Minv_up, const ValueMatrix &Minv_dn, const std::vector< int > &detData_up, const std::vector< std::vector< int >> &lookup_tbl)
std::vector< std::reference_wrapper< T > > RefVector
static void constructDeltaRotation(const std::vector< ValueType > &delta_param, const std::vector< ValueType > &old_param, const RotationIndices &act_rot_inds, const RotationIndices &full_rot_inds, std::vector< ValueType > &new_param, ValueMatrix &new_rot_mat)
void apply_rotation(const std::vector< ValueType > &param, bool use_stored_copy)
sycl::event copy_n(sycl::queue &aq, const T1 *restrict VA, size_t array_size, T2 *restrict VC, const std::vector< sycl::event > &events)
Definition: syclBLAS.cpp:548
void mw_evaluateVGLandDetRatioGrads(const RefVectorWithLeader< SPOSet > &spo_list, const RefVectorWithLeader< ParticleSet > &P_list, int iat, const std::vector< const ValueType *> &invRow_ptr_list, OffloadMWVGLArray &phi_vgl_v, std::vector< ValueType > &ratios, std::vector< GradType > &grads) const override
evaluate the values, gradients and laplacians of this single-particle orbital sets and determinant ra...
bool is_group(const std::string &aname)
check if aname is a group
std::unique_ptr< SPOSet > Phi_
Definition: RotatedSPOs.h:119
static void copy(int n, const T *restrict a, T *restrict b)
Definition: BLAS.hpp:381
static void axpy(int n, double x, const double *a, double *b)
Definition: BLAS.hpp:55
bool use_global_rot_
Use global rotation or history list.
Definition: RotatedSPOs.h:480
Tensor< typename BinaryReturn< T1, T2, OpMultiply >::Type_t, D > dot(const AntiSymTensor< T1, D > &lhs, const AntiSymTensor< T2, D > &rhs)
LatticeGaussianProduct::ValueType ValueType
void read(T &data, const std::string &aname)
read the data from the group aname and check status runtime error is issued on I/O error ...
Definition: hdf_archive.h:306
void applyFullRotation(const std::vector< ValueType > &full_param, bool use_stored_copy)
std::vector< ValueType > params_
list of supplied orbital rotation parameters.
Definition: RotatedSPOs.h:466
const std::string & getName() const
return object name
Definition: SPOSet.h:557
T Invert(T *restrict x, int n, int m, T *restrict work, int *restrict pivot)
inverse a matrix
static void gemm(char Atrans, char Btrans, int M, int N, int K, double alpha, const double *A, int lda, const double *restrict B, int ldb, double beta, double *restrict C, int ldc)
Definition: BLAS.hpp:235
double B(double x, int k, int i, const std::vector< double > &t)
bool params_supplied_
true if SPO parameters (orbital rotation parameters) have been supplied by input
Definition: RotatedSPOs.h:464
A D-dimensional Array class based on PETE.
Definition: OhmmsArray.h:25
void readVariationalParameters(hdf_archive &hin) override
Read the variational parameters for this object from the VP HDF file.
NewTimer & apply_rotation_timer_
timer for apply_rotation
Definition: RotatedSPOs.h:472
static void geev(char *jobvl, char *jobvr, int *n, double *a, int *lda, double *alphar, double *alphai, double *vl, int *ldvl, double *vr, int *ldvr, double *work, int *lwork, int *info)
Definition: BLAS.hpp:594
void print(std::ostream &os, int leftPadSpaces=0, bool printHeader=false) const
void acquireResource(ResourceCollection &collection, const RefVectorWithLeader< SPOSet > &spo_list) const override
acquire a shared resource from collection
void releaseResource(ResourceCollection &collection, const RefVectorWithLeader< SPOSet > &spo_list) const override
return a shared resource to collection
void createResource(ResourceCollection &collection) const override
initialize a shared resource and hand it to collection
void mw_evaluateVGLandDetRatioGradsWithSpin(const RefVectorWithLeader< SPOSet > &spo_list, const RefVectorWithLeader< ParticleSet > &P_list, int iat, const std::vector< const ValueType *> &invRow_ptr_list, OffloadMWVGLArray &phi_vgl_v, std::vector< ValueType > &ratios, std::vector< GradType > &grads, std::vector< ValueType > &spingrads) const override
evaluate the values, gradients and laplacians of this single-particle orbital sets and determinant ra...