26 #include "DMRGSCFunitary.h" 38 for (
int irrep = 0; irrep <
num_irreps; irrep++ ){
39 jumper[ irrep ] =
new int[ 3 ];
40 const int NOCC = iHandler->
getNOCC( irrep );
41 const int NACT = iHandler->
getNDMRG( irrep );
42 const int NVIR = iHandler->
getNVIRT( irrep );
43 jumper[ irrep ][ 0 ] = x_linearlength;
44 x_linearlength += NOCC * NACT;
45 jumper[ irrep ][ 1 ] = x_linearlength;
46 x_linearlength += NACT * NVIR;
47 jumper[ irrep ][ 2 ] = x_linearlength;
48 x_linearlength += NOCC * NVIR;
55 for (
int irrep = 0; irrep <
num_irreps; irrep++ ){
delete [] jumper[ irrep ]; }
62 void CheMPS2::DMRGSCFunitary::buildSkewSymmX(
const int irrep,
double * result,
double * Xelem,
const bool compact )
const{
68 for (
int cnt = 0; cnt < linsize * linsize; cnt++ ){ result[ cnt ] = 0.0; }
72 for (
int occ = 0; occ < NOCC; occ++ ){
73 for (
int act = 0; act < NACT; act++ ){
74 const int xsolindex = jumper[ irrep ][ 0 ] + act + NACT * occ;
75 const int index1 = NOCC + act;
76 result[ index1 + linsize * occ ] = Xelem[ xsolindex ];
77 result[ occ + linsize * index1 ] = - Xelem[ xsolindex ];
80 for (
int act = 0; act < NACT; act++ ){
81 for (
int vir = 0; vir < NVIR; vir++ ){
82 const int xsolindex = jumper[ irrep ][ 1 ] + vir + NVIR * act;
83 const int index1 = NOCC + NACT + vir;
84 const int index2 = NOCC + act;
85 result[ index1 + linsize * index2 ] = Xelem[ xsolindex ];
86 result[ index2 + linsize * index1 ] = - Xelem[ xsolindex ];
89 for (
int occ = 0; occ < NOCC; occ++ ){
90 for (
int vir = 0; vir < NVIR; vir++ ){
91 const int xsolindex = jumper[ irrep ][ 2 ] + vir + NVIR * occ;
92 const int index1 = NOCC + NACT + vir;
93 result[ index1 + linsize * occ ] = Xelem[ xsolindex ];
94 result[ occ + linsize * index1 ] = - Xelem[ xsolindex ];
101 for (
int cnt = 0; cnt < irrep; cnt++ ){
103 jump += ( NORBx * ( NORBx - 1 ) ) / 2;
106 for (
int row = 0; row < linsize; row++ ){
107 for (
int col = row+1; col < linsize; col++ ){
108 result[ row + linsize * col ] = Xelem[ jump + row + ( col * ( col - 1 ) ) / 2 ];
109 result[ col + linsize * row ] = - Xelem[ jump + row + ( col * ( col - 1 ) ) / 2 ];
119 for (
int irrep = 0; irrep <
num_irreps; irrep++ ){
122 int size = linsize * linsize;
126 double * xblock = temp1;
127 double * Bmat = temp1 + size;
128 double * work1 = temp1 + 2 * size;
129 double * work2 = temp1 + 3 * size;
131 double * workLARGE = temp2;
132 int lworkLARGE = 4 * size;
135 buildSkewSymmX( irrep, xblock, vector, compact );
141 dgemm_( ¬rans, ¬rans, &linsize, &linsize, &linsize, &one, xblock, &linsize, xblock, &linsize, &
set, Bmat, &linsize );
147 dsyev_( &jobz, &uplo, &linsize, Bmat, &linsize, work1, workLARGE, &lworkLARGE, &info );
150 dgemm_( ¬rans, ¬rans, &linsize, &linsize, &linsize, &one, xblock, &linsize, Bmat, &linsize, &
set, work1, &linsize );
152 dgemm_( &trans, ¬rans, &linsize, &linsize, &linsize, &one, Bmat, &linsize, work1, &linsize, &
set, work2, &linsize );
154 if (CheMPS2::DMRGSCF_debugPrint){
155 cout <<
" DMRGSCFunitary::updateUnitary : Lambdas of irrep block " << irrep <<
" : " << endl;
156 for (
int cnt=0; cnt<linsize/2; cnt++){
157 cout <<
" block = [ " << work2[2*cnt + linsize*2*cnt] <<
" , " << work2[2*cnt + linsize*(2*cnt+1)] <<
" ] " << endl;
158 cout <<
" [ " << work2[2*cnt+1 + linsize*2*cnt] <<
" , " << work2[2*cnt+1 + linsize*(2*cnt+1)] <<
" ] " << endl;
163 for (
int cnt = 0; cnt < linsize/2; cnt++ ){
164 work1[cnt] = 0.5 * ( work2[ 2 * cnt + linsize * ( 2 * cnt + 1 ) ]
165 - work2[ 2 * cnt + 1 + linsize * ( 2 * cnt ) ] );
168 if ( CheMPS2::DMRGSCF_debugPrint ){
169 for (
int cnt = 0; cnt < linsize/2; cnt++ ){
170 work2[ 2 * cnt + linsize * ( 2 * cnt + 1 ) ] -= work1[ cnt ];
171 work2[ 2 * cnt + 1 + linsize * ( 2 * cnt ) ] += work1[ cnt ];
173 double rms_diff = 0.0;
174 for (
int cnt = 0; cnt < size; cnt++ ){ rms_diff += work2[ cnt ] * work2[ cnt ]; }
175 rms_diff = sqrt( rms_diff );
176 cout <<
" DMRGSCFunitary::updateUnitary : RMSdeviation of irrep block " << irrep <<
" (should be 0.0) = " << rms_diff << endl;
180 for (
int cnt = 0; cnt < size; cnt++ ){ work2[ cnt ] = 0.0; }
181 for (
int cnt = 0; cnt < linsize/2; cnt++ ){
182 double cosine = cos( work1[ cnt ] );
183 double sine = sin( work1[ cnt ] );
184 work2[ 2 * cnt + linsize * ( 2 * cnt ) ] = cosine;
185 work2[ 2 * cnt + 1 + linsize * ( 2 * cnt + 1) ] = cosine;
186 work2[ 2 * cnt + linsize * ( 2 * cnt + 1) ] = sine;
187 work2[ 2 * cnt + 1 + linsize * ( 2 * cnt ) ] = -sine;
189 for (
int cnt = 2*(linsize/2); cnt < linsize; cnt++ ){ work2[ cnt * (linsize + 1) ] = 1.0; }
192 dgemm_( ¬rans, ¬rans, &linsize, &linsize, &linsize, &one, Bmat, &linsize, work2, &linsize, &
set, work1, &linsize );
193 dgemm_( ¬rans, &trans, &linsize, &linsize, &linsize, &one, work1, &linsize, Bmat, &linsize, &
set, work2, &linsize );
197 dgemm_( ¬rans, ¬rans, &linsize, &linsize, &linsize, &one, work2, &linsize,
entries[ irrep ], &linsize, &
set, work1, &linsize );
198 dcopy_( &size, work1, &inc1,
entries[ irrep ], &inc1 );
200 dcopy_( &size, work2, &inc1,
entries[ irrep ], &inc1 );
214 for (
int irrep = 0; irrep <
num_irreps; irrep++ ){
222 double * rotation = eigenvecs + passed * ( tot_dmrg + 1 );
228 dgemm_( &trans, ¬rans, &NDMRG, &NORB, &NDMRG, &one, rotation, &tot_dmrg,
entries[ irrep ] + NOCC, &NORB, &
set, work, &NDMRG );
230 for (
int row = 0; row < NDMRG; row++ ){
231 for (
int col = 0; col < NORB; col++ ){
232 entries[ irrep ][ NOCC + row + NORB * col ] = work[ row + NDMRG * col ];
251 for (
int irrep = 0; irrep <
num_irreps; irrep++ ){
255 dgemm_( &trans, ¬rans, &linsize, &linsize, &linsize, &one,
entries[ irrep ], &linsize,
entries[ irrep ], &linsize, &
set, work, &linsize );
256 for (
int diag = 0; diag < linsize; diag++ ){
257 work[ diag * ( 1 + linsize ) ] -= 1.0;
259 double rms_diff = 0.0;
260 for (
int cnt = 0; cnt < linsize * linsize; cnt++ ){
261 rms_diff += work[ cnt ] * work[ cnt ];
263 rms_diff = sqrt( rms_diff );
264 cout <<
" DMRGSCFunitary::CheckDeviationFromUnitary : 2-norm of U[" << irrep <<
"]^T * U[" << irrep <<
"] - I = " << rms_diff << endl;
270 double CheMPS2::DMRGSCFunitary::get_determinant(
const int irrep,
double * work1,
double * work2,
double * work_eig,
int lwork_eig )
const{
275 for (
int row = 0; row < NORB; row++ ){
276 for (
int col = 0; col < NORB; col++ ){
277 work1[ row + NORB * col ] = (
entries[ irrep ][ row + NORB * col ]
278 +
entries[ irrep ][ col + NORB * row ] );
286 dsyev_( &jobz, &uplo, &NORB, work1, &NORB, work2, work_eig, &lwork_eig, &info );
293 dgemm_( &trans, ¬rans, &NORB, &NORB, &NORB, &one, work1, &NORB,
entries[ irrep ], &NORB, &
set, work_eig, &NORB );
294 dgemm_( ¬rans, ¬rans, &NORB, &NORB, &NORB, &one, work_eig, &NORB, work1, &NORB, &
set, work2, &NORB );
303 double f_high = work2[ 0 ];
304 for (
int diag = 1; diag < NORB; diag++ ){
305 double temp = work2[ diag * ( 1 + NORB ) ] * f_high - work2[ diag + NORB * ( diag - 1 ) ] * work2[ diag - 1 + NORB * diag ] * f_low;
309 const double determinant = f_high;
311 if ( CheMPS2::DMRGSCF_debugPrint ){
312 cout <<
" DMRGSCFunitary::get_determinant : det( U[" << irrep <<
"] ) = " << determinant << endl;
323 for (
int irrep = 0; irrep <
num_irreps; irrep++ ){
326 int size = linsize * linsize;
332 double * work1 = temp1;
333 double * work2 = temp1 + size;
334 double * work3 = temp1 + 2 * size;
335 double * work4 = temp1 + 3 * size;
337 double * workLARGE = temp2;
338 int lworkLARGE = 4 * size;
342 const double determinant = get_determinant( irrep, work1, work3, workLARGE, lworkLARGE );
343 assert( determinant > 0.0 );
346 for (
int cnt = 0; cnt < size; cnt++ ){ work2[ cnt ] = 0.0; }
347 for (
int cnt = 0; cnt < linsize/2; cnt++ ){
348 const double cosinus = 0.5 * ( work3[ 2 * cnt + linsize * ( 2 * cnt ) ] + work3[ 2 * cnt + 1 + linsize * ( 2 * cnt + 1 ) ] );
349 const double sinus = 0.5 * ( work3[ 2 * cnt + linsize * ( 2 * cnt + 1 ) ] - work3[ 2 * cnt + 1 + linsize * ( 2 * cnt ) ] );
350 const double theta = atan2( sinus, cosinus );
351 if (CheMPS2::DMRGSCF_debugPrint){
352 cout <<
" DMRGSCFunitary::getLog : block = [ " << work3[ 2 * cnt + linsize * ( 2 * cnt ) ] <<
" , " 353 << work3[ 2 * cnt + linsize * ( 2 * cnt + 1 ) ] <<
" ]" << endl;
354 cout <<
" [ " << work3[ 2 * cnt + 1 + linsize * ( 2 * cnt ) ] <<
" , " 355 << work3[ 2 * cnt + 1 + linsize * ( 2 * cnt + 1 ) ] <<
" ] and corresponds to theta = " << theta << endl;
357 work3[ 2 * cnt + linsize * ( 2 * cnt ) ] -= cosinus;
358 work3[ 2 * cnt + 1 + linsize * ( 2 * cnt + 1 ) ] -= cosinus;
359 work3[ 2 * cnt + linsize * ( 2 * cnt + 1 ) ] -= sinus;
360 work3[ 2 * cnt + 1 + linsize * ( 2 * cnt ) ] += sinus;
361 work2[ 2 * cnt + linsize * ( 2 * cnt + 1 ) ] = theta;
362 work2[ 2 * cnt + 1 + linsize * ( 2 * cnt ) ] = -theta;
364 for (
int cnt = 2*(linsize/2); cnt < linsize; cnt++ ){ work3[ cnt * ( linsize + 1 ) ] -= 1; }
367 if (CheMPS2::DMRGSCF_debugPrint){
368 double RMSdeviation = 0.0;
369 for (
int cnt = 0; cnt < size; cnt++ ){ RMSdeviation += work3[ cnt ] * work3[ cnt ]; }
370 RMSdeviation = sqrt( RMSdeviation );
371 cout <<
" DMRGSCFunitary::getLog : 2-norm of [ V^T*U*V - assumed blocks ] for irrep " << irrep <<
" (should be 0.0) = " << RMSdeviation << endl;
379 dgemm_(¬rans, ¬rans, &linsize, &linsize, &linsize, &one, work1, &linsize, work2, &linsize, &
set, workLARGE, &linsize );
380 dgemm_(¬rans, &trans, &linsize, &linsize, &linsize, &one, workLARGE, &linsize, work1, &linsize, &
set, work4, &linsize );
383 for (
int row = 0; row < linsize; row++ ){
384 for (
int col = row + 1; col < linsize; col++ ){
385 vector[ jump + row + ( col * ( col - 1 ) ) / 2 ] = 0.5 * ( work4[ row + linsize * col ] - work4[ col + linsize * row ] );
389 jump += ( linsize * ( linsize - 1 ) ) / 2;
398 cout <<
" DMRGSCFunitary::getLog : 2-norm of [ U - exp(ln(U)) ] (should be 0.0) = " << rms_diff << endl;
405 for (
int irrep = 0; irrep <
num_irreps; irrep++ ){
408 int size = linsize * linsize;
414 double * work1 = temp1;
415 double * work2 = temp1 + size;
417 double * workLARGE = temp2;
418 int lworkLARGE = 4 * size;
420 const double determinant = get_determinant( irrep, work1, work2, workLARGE, lworkLARGE );
421 if ( determinant < 0.0 ){
423 for (
int cnt = 0; cnt < linsize; cnt++ ){
entries[ irrep ][ 0 + linsize * cnt ] *= -1; }
int getNORB(const int irrep) const
Get the number of orbitals for an irrep.
void rotateActiveSpaceVectors(double *eigenvecs, double *work)
Rotate the unitary matrix.
const DMRGSCFindices * iHandler
The information on the occupied, active, and virtual spaces.
DMRGSCFunitary(const DMRGSCFindices *iHandler)
Constructor.
void loadU(const string filename=DMRGSCF_unitary_storage_name)
Load the unitary from disk.
static void read(const string filename, const int n_irreps, double **storage)
Read the DMRGSCFmatrix from disk.
int getDMRGcumulative(const int irrep) const
Get the cumulative number of active orbitals for an irrep.
void getLog(double *vector, double *temp1, double *temp2) const
Obtain the logarithm of the unitary matrix.
void saveU(const string filename=DMRGSCF_unitary_storage_name) const
Save the unitary to disk.
virtual ~DMRGSCFunitary()
Destructor.
double ** entries
The matrix entries.
static void write(const string filename, const DMRGSCFindices *idx, double **storage)
Write a DMRGSCFmatrix to disk.
double rms_deviation(const DMRGSCFmatrix *other) const
Get the RMS deviation with another DMRGSCFmatrix.
void CheckDeviationFromUnitary(double *work) const
Calculate the two-norm of U^T*U - I.
void makeSureAllBlocksDetOne(double *temp1, double *temp2)
Orbitals are defined up to a phase factor. Make sure that the logarithm of each block of the unitary ...
int getNumVariablesX() const
Get the number of variables in the x-parametrization of the unitary update.
int num_irreps
The number of irreps.
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 getNDMRG(const int irrep) const
Get the number of active orbitals for an irrep.
int getNOCC(const int irrep) const
Get the number of occupied orbitals for an irrep.
int getNVIRT(const int irrep) const
Get the number of virtual orbitals for an irrep.