Skip to content

Commit

Permalink
Reduce unnecessary interfaces in DelayedUpdate.
Browse files Browse the repository at this point in the history
Move the state machine out to DiracDeterminant.
  • Loading branch information
ye-luo committed Feb 26, 2019
1 parent 3908768 commit 16845f9
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 77 deletions.
74 changes: 6 additions & 68 deletions src/QMCWaveFunctions/Fermion/DelayedUpdate.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,9 @@ namespace qmcplusplus {
/// current number of delays, increase one for each acceptance, reset to 0 after updating Ainv
int delay_count;

/// pointer to the row of up-to-date Ainv
const T* Ainv_row_ptr;
/** row id correspond to the up-to-date Ainv_row_ptr. [0 norb), Ainv_row_ptr is valid; -1, Ainv_row_ptr is not valid.
* This id is set by getInvRow indicating Ainv_row_ptr has been prepared for the Ainv_row_id row
* ratioGrad checks if Ainv_row_id is consistent. If not, Ainv_row_ptr needs to be recomputed.
* acceptRow and updateInvMat mark Ainv_row_ptr invalid by setting Ainv_row_id to -1
*/
int Ainv_row_id;
/// current determinant ratio
T curRatio;

public:
/// default constructor
DelayedUpdate(): delay_count(0), Ainv_row_ptr(nullptr), Ainv_row_id(-1) {}
DelayedUpdate(): delay_count(0) {}

///resize the internal storage
/** resize the internal storage
Expand All @@ -76,13 +65,13 @@ namespace qmcplusplus {
* @param Ainv inverse matrix
* @param rowchanged the row id corresponding to the proposed electron
*/
inline void getInvRow(const Matrix<T>& Ainv, int rowchanged)
template<typename VVT>
inline void getInvRow(const Matrix<T>& Ainv, int rowchanged, VVT& invRow)
{
Ainv_row_id = rowchanged;
if ( delay_count == 0 )
{
// Ainv is fresh, directly access Ainv
Ainv_row_ptr = Ainv[rowchanged];
std::copy_n(Ainv[rowchanged], invRow.size(), invRow.data());
return;
}
const T cone(1);
Expand All @@ -91,57 +80,11 @@ namespace qmcplusplus {
const int norb = Ainv.rows();
const int lda_Binv = Binv.cols();
// save AinvRow to new_AinvRow
std::copy_n(AinvRow, norb, V[delay_count]);
std::copy_n(AinvRow, norb, invRow.data());
// multiply V (NxK) Binv(KxK) U(KxN) AinvRow right to the left
BLAS::gemv('T', norb, delay_count, cone, U.data(), norb, AinvRow, 1, czero, p.data(), 1);
BLAS::gemv('N', delay_count, delay_count, cone, Binv.data(), lda_Binv, p.data(), 1, czero, Binv[delay_count], 1);
BLAS::gemv('N', norb, delay_count, -cone, V.data(), norb, Binv[delay_count], 1, cone, V[delay_count], 1);
Ainv_row_ptr = V[delay_count];
}

/** compute determinant ratio of new determinant
* @param Ainv inverse matrix
* @param rowchanged the row id corresponding to the proposed electron
* @param psiV new orbital values
*/
template<typename VVT>
inline T ratio(const Matrix<T>& Ainv, int rowchanged, const VVT& psiV)
{
// check Ainv_row_id against rowchanged to see if getInvRow() has been called
// This is intended to save redundant compuation in TM1 and TM3
if(Ainv_row_id != rowchanged)
getInvRow(Ainv, rowchanged);
return curRatio = simd::dot(Ainv_row_ptr,psiV.data(),Ainv.cols());
}

/** compute the old gradient
* @param Ainv inverse matrix
* @param rowchanged the row id corresponding to the proposed electron
* @param dpsiV old orbital derivatives
*/
template<typename GT>
inline GT evalGrad(const Matrix<T>& Ainv, int rowchanged, const GT* dpsiV)
{
getInvRow(Ainv, rowchanged);
return simd::dot(Ainv_row_ptr,dpsiV,Ainv.cols());
}

/** compute determinant ratio and gradients of new determinant
* @param Ainv inverse matrix
* @param rowchanged the row id corresponding to the proposed electron
* @param psiV new orbital values
* @param dpsiV new orbital derivatives
* @param g new gradients
*/
template<typename VVT, typename GGT, typename GT>
inline T ratioGrad(const Matrix<T>& Ainv, int rowchanged, const VVT& psiV, const GGT& dpsiV, GT& g)
{
// check Ainv_row_id against rowchanged to ensure getInvRow() called before ratioGrad()
// This is not a safety check. Some code paths do call ratioGrad without calling evalGrad first.
if(Ainv_row_id != rowchanged)
getInvRow(Ainv, rowchanged);
g = simd::dot(Ainv_row_ptr,dpsiV.data(),Ainv.cols());
return curRatio = simd::dot(Ainv_row_ptr,psiV.data(),Ainv.cols());
BLAS::gemv('N', norb, delay_count, -cone, V.data(), norb, Binv[delay_count], 1, cone, invRow.data(), 1);
}

/** accept a move with the update delayed
Expand All @@ -154,9 +97,6 @@ namespace qmcplusplus {
template<typename VVT>
inline void acceptRow(Matrix<T>& Ainv, int rowchanged, const VVT& psiV)
{
// Ainv_row_ptr is no more valid by marking Ainv_row_id -1
Ainv_row_id = -1;

const T cminusone(-1);
const T czero(0);
const int norb = Ainv.rows();
Expand Down Expand Up @@ -188,8 +128,6 @@ namespace qmcplusplus {
*/
inline void updateInvMat(Matrix<T>& Ainv)
{
// Ainv_row_ptr is no more valid by marking Ainv_row_id -1
Ainv_row_id = -1;
if(delay_count==0) return;
// update the inverse matrix
const T cone(1);
Expand Down
33 changes: 27 additions & 6 deletions src/QMCWaveFunctions/Fermion/DiracDeterminant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ namespace qmcplusplus
*@param first index of the first particle
*/
DiracDeterminant::DiracDeterminant(SPOSetPtr const spos, int first):
DiracDeterminantBase(spos,first), ndelay(1)
DiracDeterminantBase(spos,first), ndelay(1), invRow_id(-1)
{
ClassName = "DiracDeterminant";
}
Expand Down Expand Up @@ -87,6 +87,7 @@ void DiracDeterminant::resize(int nel, int morb)
dpsiM.resize(nel,norb);
d2psiM.resize(nel,norb);
psiV.resize(norb);
invRow.resize(norb);
psiM_temp.resize(nel,norb);
if( typeid(ValueType) != typeid(mValueType) )
psiM_hp.resize(nel,norb);
Expand Down Expand Up @@ -116,7 +117,9 @@ DiracDeterminant::evalGrad(ParticleSet& P, int iat)
{
const int WorkingIndex = iat-FirstIndex;
RatioTimer.start();
GradType g = updateEng.evalGrad(psiM, WorkingIndex, dpsiM[WorkingIndex]);
updateEng.getInvRow(psiM, WorkingIndex, invRow);
invRow_id = WorkingIndex;
GradType g = simd::dot(invRow.data(), dpsiM[WorkingIndex], invRow.size());
RatioTimer.stop();
return g;
}
Expand All @@ -131,9 +134,16 @@ DiracDeterminant::ratioGrad(ParticleSet& P, int iat, GradType& grad_iat)
const int WorkingIndex = iat-FirstIndex;
UpdateMode=ORB_PBYP_PARTIAL;
GradType rv;
curRatio = updateEng.ratioGrad(psiM, WorkingIndex, psiV, dpsiV, rv);
grad_iat += ((RealType)1.0/curRatio) * rv;
RatioTimer.stop();

// check invRow_id against WorkingIndex to ensure getInvRow() called before ratioGrad()
// This is not a safety check. Some code paths do call ratioGrad without calling evalGrad first.
if(invRow_id != WorkingIndex)
{
updateEng.getInvRow(psiM, WorkingIndex, invRow);
invRow_id = WorkingIndex;
}
curRatio = simd::dot(invRow.data(), psiV.data(), invRow.size());
grad_iat += ((RealType)1.0/curRatio) * simd::dot(invRow.data(), dpsiV.data(), invRow.size());
return curRatio;
}

Expand All @@ -146,6 +156,8 @@ void DiracDeterminant::acceptMove(ParticleSet& P, int iat)
LogValue +=std::log(std::abs(curRatio));
UpdateTimer.start();
updateEng.acceptRow(psiM,WorkingIndex,psiV);
// invRow becomes invalid after accepting a move
invRow_id = -1;
if(UpdateMode == ORB_PBYP_PARTIAL)
{
simd::copy(dpsiM[WorkingIndex], dpsiV.data(), NumOrbitals);
Expand All @@ -165,6 +177,8 @@ void DiracDeterminant::restore(int iat)
void DiracDeterminant::completeUpdates()
{
UpdateTimer.start();
// invRow becomes invalid after updating the inverse matrix
invRow_id = -1;
updateEng.updateInvMat(psiM);
UpdateTimer.stop();
}
Expand Down Expand Up @@ -265,7 +279,14 @@ DiracDeterminant::ValueType DiracDeterminant::ratio(ParticleSet& P, int iat)
Phi->evaluate(P, iat, psiV);
SPOVTimer.stop();
RatioTimer.start();
curRatio = updateEng.ratio(psiM, WorkingIndex, psiV);
// check invRow_id against WorkingIndex to see if getInvRow() has been called
// This is intended to save redundant compuation in TM1 and TM3
if(invRow_id != WorkingIndex)
{
updateEng.getInvRow(psiM, WorkingIndex, invRow);
invRow_id = WorkingIndex;
}
curRatio = simd::dot(invRow.data(), psiV.data(), invRow.size());
RatioTimer.stop();
return curRatio;
}
Expand Down
10 changes: 10 additions & 0 deletions src/QMCWaveFunctions/Fermion/DiracDeterminant.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,16 @@ class DiracDeterminant: public DiracDeterminantBase
DiracMatrix<mValueType> detEng;
DelayedUpdate<ValueType> updateEng;

/// the row of up-to-date inverse matrix
ValueVector_t invRow;

/** row id correspond to the up-to-date invRow. [0 norb), invRow is ready; -1, invRow is not valid.
* This id is set after calling getInvRow indicating invRow has been prepared for the invRow_id row
* ratioGrad checks if invRow_id is consistent. If not, invRow needs to be recomputed.
* acceptMove and completeUpdates mark invRow invalid by setting invRow_id to -1
*/
int invRow_id;

ValueType curRatio,cumRatio;
ParticleSet::SingleParticleValue_t *FirstAddressOfG;
ParticleSet::SingleParticleValue_t *LastAddressOfG;
Expand Down
6 changes: 3 additions & 3 deletions src/QMCWaveFunctions/tests/test_dirac_matrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,13 @@ TEST_CASE("DiracMatrix_update_row", "[wavefunction][fermion]")
dm.invert(a,false);

// new row
Vector<ValueType> v;
v.resize(3);
Vector<ValueType> v(3), invRow(3);
v[0] = 1.9;
v[1] = 2.0;
v[2] = 3.1;

ValueType det_ratio1 = updateEng.ratio(a,0,v);
updateEng.getInvRow(a,0,invRow);
ValueType det_ratio1 = simd::dot(v.data(), invRow.data(), invRow.size());

ValueType det_ratio = 0.178276269185;
REQUIRE(det_ratio1 == ValueApprox(det_ratio));
Expand Down

0 comments on commit 16845f9

Please sign in to comment.