-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathESolver.cpp
145 lines (139 loc) · 7.03 KB
/
ESolver.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <map>
#include <set>
#include "GlobalPrecisionParameters.h"
#include "main.h"
#include "FreeFunctions.h"
using namespace Eigen;
std::vector<int> findTargetQNumPositions(const std::vector<int>& qNumList,
int targetQNum)
{
std::vector<int> positions; // which rows and columns of matrix are in sector
for(auto firstElement = qNumList.begin(),
qNumListElement = firstElement, end = qNumList.end();
qNumListElement != end; qNumListElement++)
if(*qNumListElement == targetQNum)
positions.push_back(qNumListElement - firstElement);
return positions;
};
MatrixX_t createCrossSectorBlock(const MatrixX_t& mat,
const std::vector<int>& rowPositions,
const std::vector<int>& colPositions)
// pick out one block from full matrix
{
MatrixX_t crossSectorBlock(rowPositions.size(), colPositions.size());
int elmt = 0;
for(int j : colPositions)
for(int i : rowPositions)
crossSectorBlock(elmt++) = mat(i, j);
return crossSectorBlock;
};
VectorX_t filledOutEvec(const VectorX_t& sectorEvec, int fullMatrixSize,
const std::vector<int>& positions)
{
VectorX_t longEvec = VectorX_t::Zero(fullMatrixSize);
for(int i = 0, end = sectorEvec.size(); i < end; i++)
longEvec(positions[i]) = sectorEvec(i);
return longEvec;
};
HamSolver::HamSolver(const MatrixX_t& mat,
const std::vector<int>& hSprimeQNumList,
const std::vector<int>& hEprimeQNumList,
int targetQNum, rmMatrixX_t& bigSeed, double lancTolerance)
: hSprimeQNumList(hSprimeQNumList), hEprimeQNumList(hEprimeQNumList),
targetQNum(targetQNum)
{
std::vector<int> positions
= findTargetQNumPositions(vectorProductSum(hSprimeQNumList,
hEprimeQNumList),
targetQNum);
MatrixX_t sectorMat = createCrossSectorBlock(mat, positions, positions);
int multiplicity = positions.size();
rmMatrixX_t littleSeed(multiplicity, 1);
for(int i = 0; i < multiplicity; i++)
littleSeed(i) = bigSeed(positions[i]);
littleSeed.normalize();
lowestEval = lanczos(sectorMat, littleSeed, lancTolerance);
lowestEvec = filledOutEvec(littleSeed, mat.rows(), positions);
};
DMSolver::DMSolver(const HamSolver hSuperSolver, int maxEvecsToKeep)
: truncationError(0.)
{
std::set<int> qNumSet(hSuperSolver.hSprimeQNumList.begin(),
hSuperSolver.hSprimeQNumList.end());
std::map<int, std::vector<int>> qNumPositions;
// lists positions of each quantum number within hSuperSolver.hSprimeQNumList
std::multimap<double, std::pair<int, VectorX_t>> indexedEvecs;
// DM eigenvalue, then sector, then eigenvector
for(int qNum : qNumSet) // make list of indexed eigenvalues
if(std::count(hSuperSolver.hEprimeQNumList.begin(),
hSuperSolver.hEprimeQNumList.end(),
hSuperSolver.targetQNum - qNum))
{
std::vector<int> rowPositions
= findTargetQNumPositions(hSuperSolver.hSprimeQNumList, qNum);
qNumPositions
.insert(qNumPositions.end(),
std::pair<int, std::vector<int>>(qNum, rowPositions));
MatrixX_t crossSectorBlock
= createCrossSectorBlock(hSuperSolver.lowestEvec,
rowPositions,
findTargetQNumPositions(hSuperSolver
.hEprimeQNumList,
hSuperSolver
.targetQNum
- qNum));
SelfAdjointEigenSolver<MatrixX_t>
DMSectorSolver(crossSectorBlock * crossSectorBlock.adjoint());
// find DM sector eigenvectors
for(int i = 0, end = crossSectorBlock.rows(); i < end; i++)
indexedEvecs
.insert(std::pair<double, std::pair<int, VectorX_t>>
(DMSectorSolver.eigenvalues()(i),
std::pair<int, VectorX_t>(qNum,
DMSectorSolver
.eigenvectors().col(i))));
// add indexed eigenvalues to list
};
int matSize = hSuperSolver.lowestEvec.rows(),
nIndexedEvecs = indexedEvecs.size(), // most states allowed by symmetry
evecsToKeep = std::min({matSize, maxEvecsToKeep, nIndexedEvecs});
auto weight = indexedEvecs.crbegin();
std::advance(weight, evecsToKeep - 1);
for(; evecsToKeep >= 1 && weight -> first == 0; evecsToKeep--, weight--);
// eliminate null vectors of the density matrix
if(evecsToKeep < nIndexedEvecs)
// have you truncated below the highest number
// of DM eigenvectors allowed by symmetry?
{
for(; evecsToKeep >= 1
&& (weight -> first - std::next(weight, 1) -> first)
/ std::abs(weight -> first) < degenerateDMCutoff;
evecsToKeep--, weight--);
// find the highest-weighted eigenvector that does not terminate
// inside a degenerate eigenspace of the density matrix
weight++; // now points to first truncated DM eigenvalue
for(auto end = indexedEvecs.crend(); weight != end; weight++)
truncationError += weight -> first;
};
if(evecsToKeep == 0)
{
std::cerr << "More than mMax highest-weighted density-matrix "
<< "eigenvectors are degenerate." << std::endl;
exit(EXIT_FAILURE);
}
else if(evecsToKeep != maxEvecsToKeep)
std::cout << "Warning: mMax truncation ends in a degenerate DM "
<< "eigenspace, lowering cutoff to " << evecsToKeep
<< " states." << std::endl;
highestEvecQNums.reserve(evecsToKeep);
highestEvecs = MatrixX_t::Zero(matSize, evecsToKeep);
auto currentIndexedEvec = indexedEvecs.crbegin();
for(int j = 0; j < evecsToKeep; j++, currentIndexedEvec++)
{
highestEvecQNums.push_back(currentIndexedEvec -> second.first);
highestEvecs.col(j) = filledOutEvec(currentIndexedEvec -> second.second,
matSize,
qNumPositions[currentIndexedEvec
-> second.first]);
};
};