26 #include "EdmistonRuedenberg.h" 27 #include "DMRGSCFrotations.h" 37 printLevel = printLevelIn;
51 VmatRotated =
new FourIndex( group, Isizes );
72 double gradNorm = 1.0;
74 double * gradient =
new double[numVariables];
75 for (
int cnt=0; cnt<numVariables; cnt++){ gradient[cnt] = 0.0; }
78 if (startFromRandomUnitary){
79 for (
int cnt=0; cnt<numVariables; cnt++){ gradient[cnt] = ((double) rand())/RAND_MAX - 0.5; }
81 for (
int cnt=0; cnt<numVariables; cnt++){ gradient[cnt] = 0.0; }
84 const int mem_size = iHandler->
getL() * iHandler->
getL() * iHandler->
getL() * iHandler->
getL();
85 DMRGSCFrotations::rotate( VMAT_ORIG, VmatRotated, NULL,
'F',
'F',
'F',
'F', iHandler, unitary, temp1, temp2, mem_size,
"edmistonruedenberg" );
88 double Icost = costFunction();
89 if (printLevel>0){ cout <<
" EdmistonRuedenberg::Optimize : Cost function at start = " << Icost << endl; }
90 double Icost_previous = 0.0;
94 while ((gradNorm > gradThreshold) && (nIterations < maxIter)){
102 Icost_previous = Icost;
103 DMRGSCFrotations::rotate( VMAT_ORIG, VmatRotated, NULL,
'F',
'F',
'F',
'F', iHandler, unitary, temp1, temp2, mem_size,
"edmistonruedenberg" );
104 Icost = costFunction();
109 if (Icost_previous > Icost){
110 if (printLevel>1){ cout <<
" WARNING : Icost = " << Icost <<
" < Icost_previous = " << Icost_previous << endl; }
111 for (
int cnt=0; cnt<numVariables; cnt++){ gradient[cnt] = -gradient[cnt]; }
112 int nIterationsBACK = 0;
113 while ((Icost_previous > Icost) && (nIterationsBACK < CheMPS2::EDMISTONRUED_maxIterBackTfo)){
115 for (
int cnt=0; cnt<numVariables; cnt++){ gradient[cnt] *= 0.5; }
117 DMRGSCFrotations::rotate( VMAT_ORIG, VmatRotated, NULL,
'F',
'F',
'F',
'F', iHandler, unitary, temp1, temp2, mem_size,
"edmistonruedenberg" );
118 Icost = costFunction();
120 if (printLevel>1){ cout <<
" WARNING : Rotated back a bit. Now Icost = " << Icost << endl; }
124 gradNorm = augmentedHessianNewtonRaphson(gradient, temp1, temp2);
127 cout <<
" After iteration " << nIterations <<
" : Icost = " << Icost <<
" has gradNorm = " << gradNorm << endl;
135 cout <<
" Cost function at stop = " << Icost << endl;
136 cout <<
" Gradient norm = " << gradNorm <<
" after " << nIterations <<
" iterations." << endl;
145 double CheMPS2::EdmistonRuedenberg::costFunction()
const{
149 for (
int orb=0; orb<iHandler->
getNORB(irrep); orb++){
150 Cost += VmatRotated->
get(irrep,irrep,irrep,irrep,orb,orb,orb,orb);
157 double CheMPS2::EdmistonRuedenberg::calcGradientValue(
const int irrep,
const int p,
const int q)
const{
159 return 4 * ( VmatRotated->
get(irrep, irrep, irrep, irrep, p, p, p, q) - VmatRotated->
get(irrep, irrep, irrep, irrep, q, q, q, p) );
163 double CheMPS2::EdmistonRuedenberg::calcHessianValue(
const int irrep,
const int p,
const int q,
const int r,
const int s)
const{
167 value += ( 8*VmatRotated->
get(irrep, irrep, irrep, irrep, p, p, q, s)
168 + 4*VmatRotated->
get(irrep, irrep, irrep, irrep, p, q, p, s)
169 - 2*VmatRotated->
get(irrep, irrep, irrep, irrep, q, q, q, s)
170 - 2*VmatRotated->
get(irrep, irrep, irrep, irrep, s, s, s, q) );
173 value += ( 8*VmatRotated->
get(irrep, irrep, irrep, irrep, q, q, p, r)
174 + 4*VmatRotated->
get(irrep, irrep, irrep, irrep, q, p, q, r)
175 - 2*VmatRotated->
get(irrep, irrep, irrep, irrep, p, p, p, r)
176 - 2*VmatRotated->
get(irrep, irrep, irrep, irrep, r, r, r, p) );
179 value -= ( 8*VmatRotated->
get(irrep, irrep, irrep, irrep, p, p, q, r)
180 + 4*VmatRotated->
get(irrep, irrep, irrep, irrep, p, q, p, r)
181 - 2*VmatRotated->
get(irrep, irrep, irrep, irrep, q, q, q, r)
182 - 2*VmatRotated->
get(irrep, irrep, irrep, irrep, r, r, r, q) );
185 value -= ( 8*VmatRotated->
get(irrep, irrep, irrep, irrep, q, q, p, s)
186 + 4*VmatRotated->
get(irrep, irrep, irrep, irrep, q, p, q, s)
187 - 2*VmatRotated->
get(irrep, irrep, irrep, irrep, p, p, p, s)
188 - 2*VmatRotated->
get(irrep, irrep, irrep, irrep, s, s, s, p) );
194 double CheMPS2::EdmistonRuedenberg::augmentedHessianNewtonRaphson(
double * gradient,
double * temp1,
double * temp2)
const{
197 double gradNorm = 0.0;
201 int linsize = iHandler->
getNORB(irrep);
205 int hessianlinearsize = linsize*(linsize-1)/2 + 1;
218 double * hessian = temp1;
219 double * eigen = temp2;
220 double * work = temp2 + hessianlinearsize;
221 int lwork = linsize*linsize*linsize*linsize - hessianlinearsize;
225 for (
int row=0; row<linsize; row++){
226 for (
int col=row+1; col<linsize; col++){
227 const double waarde = calcGradientValue(irrep, row, col);
228 gradient[jump + row + col*(col-1)/2] = waarde;
229 gradNorm += waarde * waarde;
230 for (
int row2=0; row2<linsize; row2++){
231 for (
int col2=row2+1; col2<linsize; col2++){
232 const double value = calcHessianValue(irrep, row, col, row2, col2);
233 hessian[row + col*(col-1)/2 + hessianlinearsize * (row2 + col2*(col2-1)/2)] = - value;
239 for (
int cnt=0; cnt<hessianlinearsize-1; cnt++){
240 hessian[hessianlinearsize-1 + hessianlinearsize * cnt] = - gradient[jump + cnt];
241 hessian[cnt + hessianlinearsize * (hessianlinearsize-1)] = - gradient[jump + cnt];
243 hessian[hessianlinearsize*hessianlinearsize-1] = 0.0;
249 dsyev_(&jobz,&uplo,&hessianlinearsize,hessian,&hessianlinearsize,eigen,work,&lwork,&info);
251 double scalar = 1.0/hessian[hessianlinearsize-1];
253 dscal_(&hessianlinearsize,&scalar,hessian,&inc);
255 for (
int cnt=0; cnt<hessianlinearsize-1; cnt++){ gradient[jump + cnt] = hessian[cnt]; }
257 jump += hessianlinearsize-1;
263 gradNorm = sqrt(gradNorm);
269 void CheMPS2::EdmistonRuedenberg::Fiedler(
const int irrep,
int * reorder,
double * laplacian,
double * temp2){
273 int linsize = iHandler->
getNORB(irrep);
274 assert( linsize>=2 );
277 double * work = temp2;
278 int lwork = 3*linsize*linsize;
279 double * eigs = temp2 + lwork;
285 dsyev_(&jobz, &uplo, &linsize, laplacian, &linsize, eigs, work, &lwork, &info);
287 cout <<
" EdmistonRuedenberg::Fiedler : Smallest eigs(Laplacian[" << irrep <<
"]) = [ " << eigs[0] <<
" , " << eigs[1] <<
" ]." << endl;
291 double * FiedlerVector = laplacian + linsize;
292 double * FiedlerVectorCopy = laplacian;
293 for (
int cnt=0; cnt<linsize; cnt++){ FiedlerVectorCopy[cnt] = FiedlerVector[cnt]; }
296 const double upperBound = 2.0;
297 for (
int value=0; value<linsize; value++){
299 for (
int cnt=1; cnt<linsize; cnt++){
300 if (FiedlerVectorCopy[cnt] < FiedlerVectorCopy[index]){ index = cnt; }
302 reorder[value] = index;
303 FiedlerVectorCopy[index] = upperBound;
308 for (
int cnt=0; cnt<linsize-1; cnt++){
309 if (FiedlerVector[reorder[cnt]] > FiedlerVector[reorder[cnt+1]]){ isOK =
false; }
312 cout <<
" Reorder[" << irrep <<
"] = [ ";
313 for (
int cnt=0; cnt<linsize-1; cnt++){ cout << reorder[cnt] <<
" , "; }
314 cout << reorder[linsize-1] <<
" ]." << endl;
318 double * blockU = unitary->
getBlock(irrep);
319 for (
int row=0; row<linsize; row++){
320 for (
int col=0; col<linsize; col++){
321 work[row + linsize * col] = blockU[reorder[row] + linsize * col];
325 int size = linsize*linsize;
327 dcopy_(&size, work, &inc, blockU, &inc);
334 dgemm_(&trans, ¬rans, &linsize, &linsize, &linsize, &alpha, blockU, &linsize, blockU, &linsize, &beta, work, &linsize);
336 for (
int row=0; row<linsize; row++){
337 sum += (work[row+linsize*row]-1.0)*(work[row+linsize*row]-1.0);
338 for (
int col=row+1; col<linsize; col++){
339 sum += work[row+linsize*col]*work[row+linsize*col] + work[col+linsize*row]*work[col+linsize*row];
343 cout <<
" 2-norm of Unitary[" << irrep <<
"]^T * Unitary[" << irrep <<
"] - I = " << sum << endl;
348 double CheMPS2::EdmistonRuedenberg::FiedlerExchangeCost()
const{
353 const int linsize = iHandler->
getNORB(irrep);
355 for (
int row=0; row<linsize; row++){
356 for (
int col=row+1; col<linsize; col++){
357 Cost += 2 * VmatRotated->
get(irrep,irrep,irrep,irrep,row,col,col,row) * (col-row) * (col-row);
371 const int mem_size = iHandler->
getL() * iHandler->
getL() * iHandler->
getL() * iHandler->
getL();
372 DMRGSCFrotations::rotate( VMAT_ORIG, VmatRotated, NULL,
'F',
'F',
'F',
'F', iHandler, unitary, temp1, temp2, mem_size,
"edmistonruedenberg" );
374 if (printLevel>0){ cout <<
" EdmistonRuedenberg::FiedlerExchange : Cost function at start = " << FiedlerExchangeCost() << endl; }
376 int * reorder =
new int[maxlinsize];
380 const int linsize = iHandler->
getNORB(irrep);
384 double * laplacian = temp1;
387 for (
int row=0; row<linsize; row++){
388 laplacian[row*(1+linsize)] = 0.0;
389 for (
int col=row+1; col<linsize; col++){
390 laplacian[row + linsize*col] = - VmatRotated->
get(irrep,irrep,irrep,irrep,row,col,col,row);
391 laplacian[col + linsize*row] = laplacian[row + linsize*col];
392 laplacian[row + linsize*row] -= laplacian[row + linsize*col];
394 for (
int col=0; col<row; col++){
395 laplacian[row + linsize*row] -= laplacian[row + linsize*col];
399 Fiedler(irrep, reorder, laplacian, temp2);
406 DMRGSCFrotations::rotate( VMAT_ORIG, VmatRotated, NULL,
'F',
'F',
'F',
'F', iHandler, unitary, temp1, temp2, mem_size,
"edmistonruedenberg" );
408 if (printLevel>0){ cout <<
" EdmistonRuedenberg::FiedlerExchange : Cost function at end = " << FiedlerExchangeCost() << endl; }
412 double CheMPS2::EdmistonRuedenberg::FiedlerGlobalCost(
const DMRGSCFindices * idx,
const FourIndex * VMAT_LOCAL,
int * dmrg2ham ){
416 for (
int dmrg_row = 0; dmrg_row < idx->
getL(); dmrg_row++ ){
417 for (
int dmrg_col = 0; dmrg_col < idx->
getL(); dmrg_col++ ){
418 const int ham_row = dmrg2ham[ dmrg_row ];
419 const int ham_col = dmrg2ham[ dmrg_col ];
424 cost += VMAT_LOCAL->
get( irrep_row, irrep_col, irrep_col, irrep_row, rel_row, rel_col, rel_col, rel_row ) * ( dmrg_row - dmrg_col ) * ( dmrg_row - dmrg_col );
436 for (
int orb = 0; orb < iHandler->
getL(); orb++ ){ dmrg2ham[ orb ] = orb; }
437 if ( printLevel > 0 ){ cout <<
" EdmistonRuedenberg::FiedlerGlobal : Cost function at start = " << FiedlerGlobalCost( iHandler, VMAT_ORIG, dmrg2ham ) << endl; }
440 double * laplacian =
new double[ iHandler->
getL() * iHandler->
getL() ];
441 for (
int ham_row = 0; ham_row < iHandler->
getL(); ham_row++ ){
442 double sum_over_column = 0.0;
443 for (
int ham_col = 0; ham_col < iHandler->
getL(); ham_col++ ){
444 if ( ham_row != ham_col ){
449 const double value = fabs( VMAT_ORIG->
get( irrep_row, irrep_col, irrep_col, irrep_row, rel_row, rel_col, rel_col, rel_row ) );
450 laplacian[ ham_row + iHandler->
getL() * ham_col ] = - value;
451 sum_over_column += value;
453 laplacian[ ham_row + iHandler->
getL() * ham_col ] = 0.0;
456 laplacian[ ham_row + iHandler->
getL() * ham_row ] = sum_over_column;
460 int lwork = 3 * iHandler->
getL() * iHandler->
getL();
461 double * work =
new double[ lwork ];
462 double * eigs =
new double[ iHandler->
getL() ];
465 int linsize = iHandler->
getL();
467 dsyev_( &jobz, &uplo, &linsize, laplacian, &linsize, eigs, work, &lwork, &info );
472 double * fiedler_vec = laplacian + linsize;
473 for (
int dummy = 0; dummy < linsize; dummy++ ){
475 for (
int orb = 1; orb < linsize; orb++ ){
476 if ( fiedler_vec[ orb ] < fiedler_vec[ index ] ){ index = orb; }
478 dmrg2ham[ dummy ] = index;
479 fiedler_vec[ index ] = 2.0;
484 if ( printLevel > 0 ){
485 cout <<
" EdmistonRuedenberg::FiedlerGlobal : Cost function at end = " << FiedlerGlobalCost( iHandler, VMAT_ORIG, dmrg2ham ) << endl;
486 cout <<
" EdmistonRuedenberg::FiedlerGlobal : Reordering = [ ";
487 for (
int orb = 0; orb < linsize - 1; orb++ ){ cout << dmrg2ham[ orb ] <<
", "; }
488 cout << dmrg2ham[ linsize - 1 ] <<
" ]." << endl;
int getNORB(const int irrep) const
Get the number of orbitals for an irrep.
double * getBlock(const int irrep)
Get a matrix block.
bool setGroup(const int nGroup)
Set the group.
static void rotate(const FourIndex *ORIG_VMAT, FourIndex *NEW_VMAT, DMRGSCFintegrals *ROT_TEI, const char space1, const char space2, const char space3, const char space4, DMRGSCFindices *idx, DMRGSCFunitary *umat, double *mem1, double *mem2, const int mem_size, const string filename)
Fill the rotated two-body matrix elements for the space. If the blocks become too large...
int getROTparamsize() const
Get the orbital rotation parameter space size.
int getNumberOfIrreps() const
Get the number of irreps for the currently activated group.
virtual ~EdmistonRuedenberg()
Destructor.
double get(const int irrep_i, const int irrep_j, const int irrep_k, const int irrep_l, const int i, const int j, const int k, const int l) const
Get an element.
EdmistonRuedenberg(const FourIndex *Vmat, const int group, const int printLevelIn=1)
Constructor.
void FiedlerGlobal(int *dmrg2ham) const
Permute the orbitals so that the bandwidth of the exchange matrix is (approximately) minimized...
int getL() const
Get the number of orbitals.
int get_irrep_size(const int irrep) const
Get a given irrep size.
DMRGSCFunitary * getUnitary()
Get the pointer to the unitary to use in DMRGSCF.
void FiedlerExchange(const int maxlinsize, double *temp1, double *temp2)
Permute the orbitals so that the bandwidth of the exchange matrix is (approximately) minimized (per i...
double Optimize(double *temp1, double *temp2, const bool startFromRandomUnitary, const double gradThreshold=EDMISTONRUED_gradThreshold, const int maxIter=EDMISTONRUED_maxIter)
Maximize the Edmiston-Ruedenberg cost function.
void identity()
Make this matrix the identity matrix.
void updateUnitary(double *workmem1, double *workmem2, double *vector, const bool multiply, const bool compact)
Update the unitary transformation.
int getOrbitalIrrep(const int index) const
Get the irrep corresponding to a global orbital index.
int getOrigNOCCstart(const int irrep) const
Get in the original Hamiltonian index the start orbital for the occupied orbitals with a certain irre...